iOS Project bootstrap
2016-04-02 20:32
796 查看
How do you setup your iOS projects?
Since we are approaching 2015 I’m working on refreshing my project bootstrap. I’ve decided to open source it so other can benefit or contribute.
I think it’s pretty neat but decide for yourself.
It’s still WIP so pull requests are most welcomed.
A project by default has 3 configurations:
Debug
Release
Adhoc
Each configuration can be put side by side on same device, and you can clearly distinguish each build. Easier to find issues across different versions and branches.
Looking at each of the icon you get following informations:
Build number: 29
Branch: Master
Commit hash
Version: 1.0
Configuration that the app was built with
You can also use KZBootstrap API to query those informations while running your application.
Warnings were added by compiler team for a reason, as such I start with Weverything and disable few warnings:
Wno-objc-missing-property-synthesis - don’t want to do @synthesize on properties
Wno-unused-macros - annoying when doing DSL
Wno-disabled-macro-expansion - needed for DSL/Metaprogramming
Wno-gnu-statement-expression - helpful
Wno-language-extension-token - language extensions are useful
Wno-overriding-method-mismatch - so I can change id to specific type and avoid unnecesary local variables
Also treat warnings as errors is a must.
turn all todo/fixme into warnings
warnings when files get too big
add KZBIgnoreLineCount anywhere in file to disable warning generation for that file.
Automatically generate macro for current developer, that way a team can have different code paths while they are working on features, or different logging levels. Without git changes.
One more thing, let’s add some macros: To prevent nil passed in as arguments:
KZB_REQUIRE_ALL_PARAMS
KZB_REQUIRE_PARAMS(1,2)
When your subclasses should call super:
KZB_REQUIRE_SUPER
When you want to avoid spelling errors:
KZB_KEYPATH
KZB_KEYPATH_T
Often when working with big clients, you need to have multiple environments for Staging / Production / QA etc. They usually differ in some kind of configuration, eg. different URL endpoints.
Too many times I’ve seen people creating separate targets for each of them, which leads to maintenance costs and unnecessary bloat/clutter.
As such I’ve created a different approach, with some nice automation:
Default environments can be changed either via xcodebuild user variable (on Jenkins) or via launch argument inside your schema.
on jenkins, xcodebuild … KZBEnv=@”Production” build
in custom Schema: Edit Scheme->Arguments->Launch Arguments-> “-KZBEnvOverride Production”
Environments can be changed without reinstalling application, even while it’s running.
All environments variables are created in a single plist
If any of the variables are missing an entry for one of the environments you get compile time error. You can even click on it to go to the configuration file.
Settings bundle will be automatically injected to give you environment switching.
You can register for callback when env changes, useful if you need to reset your database etc.
Production builds will remove all variables for other environments to prevent exposing non-production and unused configurations.
If you are using CocoaLumberjack you can include KZBootstrap/Logging subspec to get log formatting that works as clickable links in AppCode.
If you decide to include KZBootstrap/Debug subspec, you will get:
assertions when UIKit is layouted/displayed on background thread, so you can fix your code.
API interception capabilities for AFNetworking, which you can either display yourself (or send me PR with universal UI). Or just look at during debuging by calling
KZBootstrap is available through CocoaPods. To install it, simply add the following line to your Podfile:
KZBootstrap - for core functionality
KZBootstrap/Logging - additional logging functionality
KZBootstrap/Debug - additional debugging functionality
There are few things you need to do with your project, you can either use my crafter setup tool to make it automatic or do it manually:
KZBEnvironments.plist with KZBEnvironments key containing array of all environments. All extra keys are treated as env variables and should have a value for each of the allowed env’s.
BUNDLE_DISPLAY_NAME_SUFFIX _and BUNDLE_ID_SUFFIX should be added to User-Defined settings
In your target .plist file append both display name and bundle identifier keys with those variables eg.
Add KZBEnv user-defined setting with value of default env for each configuration then in preprocessor macros add KZBDefaultEnv=${KZBEnv}
Add empty file named KZBootstrapUserMacros.h anywhere in your project, and include it into your *prefix.pch file. Include that file in your .gitignore.
Set warnings as described above.
You should have Settings.bundle in the project so the code can inject it with environment switching functionality.
Add script execution at the end of your Build Phases
can selectively enable features by passing arguments to bootstrap.sh
Base crafter setup might look like this, replace CUSTOM with your preferred steps:
In you want to support dynamic env switching app delegate you can add something like this:
KZBootstrap is available under the MIT license. See the LICENSE file for more info.
Krzysztof Zablocki, krzysztof.zablocki@pixle.pl
My blog
Follow me on twitter.
All of this wouldn’t be possible if we didn’t have such a great community, based on my own previous work but also countless others. Tried to reference everything but if you think I missed something please
let me know.
References:
http://stackoverflow.com/questions/10497552/how-to-configure-independent-sets-of-runtime-settings-in-xcode
https://github.com/crushlovely/Amaro
https://github.com/crushlovely/Sidecar
http://swwritings.com/post/2013-05-20-concurrent-debug-beta-app-store-builds
https://gist.github.com/dulaccc/a52154ac4c007db2be55
https://gist.github.com/steipete/5664345
http://blog.manbolo.com/2013/05/17/passing-user-variable-to-xcodebuild
http://blog.jaredsinclair.com/post/97193356620/the-best-of-all-possible-xcode-automated-build
https://github.com/krzysztofzablocki/crafter
https://github.com/krzysztofzablocki/IconOverlaying
Big thanks goes to Lextech Global Services for supporting my community work, they are awesome. If you need a mobile app for your
enterprise, you should talk to them.
Since we are approaching 2015 I’m working on refreshing my project bootstrap. I’ve decided to open source it so other can benefit or contribute.
I think it’s pretty neat but decide for yourself.
It’s still WIP so pull requests are most welcomed.
Basic
setup and configuration
A project by default has 3 configurations:Debug
Release
Adhoc
Each configuration can be put side by side on same device, and you can clearly distinguish each build. Easier to find issues across different versions and branches.
Looking at each of the icon you get following informations:
Build number: 29
Branch: Master
Commit hash
Version: 1.0
Configuration that the app was built with
You can also use KZBootstrap API to query those informations while running your application.
Code
Quality and Warnings
Warnings were added by compiler team for a reason, as such I start with Weverything and disable few warnings:Wno-objc-missing-property-synthesis - don’t want to do @synthesize on properties
Wno-unused-macros - annoying when doing DSL
Wno-disabled-macro-expansion - needed for DSL/Metaprogramming
Wno-gnu-statement-expression - helpful
Wno-language-extension-token - language extensions are useful
Wno-overriding-method-mismatch - so I can change id to specific type and avoid unnecesary local variables
Also treat warnings as errors is a must.
That’s
not all, let’s add some scripts:
turn all todo/fixme into warningswarnings when files get too big
add KZBIgnoreLineCount anywhere in file to disable warning generation for that file.
Automatically generate macro for current developer, that way a team can have different code paths while they are working on features, or different logging levels. Without git changes.
#if merowing //! my code #endif
One more thing, let’s add some macros: To prevent nil passed in as arguments:
KZB_REQUIRE_ALL_PARAMS
KZB_REQUIRE_PARAMS(1,2)
When your subclasses should call super:
KZB_REQUIRE_SUPER
When you want to avoid spelling errors:
KZB_KEYPATH
KZB_KEYPATH_T
Environments
Often when working with big clients, you need to have multiple environments for Staging / Production / QA etc. They usually differ in some kind of configuration, eg. different URL endpoints.Too many times I’ve seen people creating separate targets for each of them, which leads to maintenance costs and unnecessary bloat/clutter.
As such I’ve created a different approach, with some nice automation:
Default environments can be changed either via xcodebuild user variable (on Jenkins) or via launch argument inside your schema.
on jenkins, xcodebuild … KZBEnv=@”Production” build
in custom Schema: Edit Scheme->Arguments->Launch Arguments-> “-KZBEnvOverride Production”
Environments can be changed without reinstalling application, even while it’s running.
All environments variables are created in a single plist
If any of the variables are missing an entry for one of the environments you get compile time error. You can even click on it to go to the configuration file.
Settings bundle will be automatically injected to give you environment switching.
You can register for callback when env changes, useful if you need to reset your database etc.
Production builds will remove all variables for other environments to prevent exposing non-production and unused configurations.
Logging
- Optional
If you are using CocoaLumberjack you can include KZBootstrap/Logging subspec to get log formatting that works as clickable links in AppCode.
Debugging
- Optional
If you decide to include KZBootstrap/Debug subspec, you will get:assertions when UIKit is layouted/displayed on background thread, so you can fix your code.
API interception capabilities for AFNetworking, which you can either display yourself (or send me PR with universal UI). Or just look at during debuging by calling
[KZBResponseTracker printAll]
Installing
KZBootstrap
KZBootstrap is available through CocoaPods. To install it, simply add the following line to your Podfile:KZBootstrap - for core functionality
KZBootstrap/Logging - additional logging functionality
KZBootstrap/Debug - additional debugging functionality
There are few things you need to do with your project, you can either use my crafter setup tool to make it automatic or do it manually:
KZBEnvironments.plist with KZBEnvironments key containing array of all environments. All extra keys are treated as env variables and should have a value for each of the allowed env’s.
BUNDLE_DISPLAY_NAME_SUFFIX _and BUNDLE_ID_SUFFIX should be added to User-Defined settings
In your target .plist file append both display name and bundle identifier keys with those variables eg.
app${BUNDLE_DISPLAY_NAME_SUFFIX}
Add KZBEnv user-defined setting with value of default env for each configuration then in preprocessor macros add KZBDefaultEnv=${KZBEnv}
Add empty file named KZBootstrapUserMacros.h anywhere in your project, and include it into your *prefix.pch file. Include that file in your .gitignore.
Set warnings as described above.
You should have Settings.bundle in the project so the code can inject it with environment switching functionality.
Add script execution at the end of your Build Phases
"${SRCROOT}/Pods/KZBootstrap/Pod/Assets/Scripts/bootstrap.sh"You
can selectively enable features by passing arguments to bootstrap.sh
-lwill enable line-count warnings
-twill enable TODO warnings
-uwill enable user macros
-nwill enable build-number automation
-iwill enable icon versioning. (This also enables build-number automation.)
Base crafter setup might look like this, replace CUSTOM with your preferred steps:
# All your configuration should happen inside configure block Crafter.configure do # This are projects wide instructions add_platform({:platform => :ios, :deployment => 7.0}) add_git_ignore duplicate_configurations({:adhoc => :release}) # set of options, warnings, static analyser and anything else normal xcode treats as build options set_options %w( RUN_CLANG_STATIC_ANALYZER GCC_TREAT_WARNINGS_AS_ERRORS ) set_build_settings({ :'WARNING_CFLAGS' => %w( -Weverything -Wno-objc-missing-property-synthesis -Wno-unused-macros -Wno-disabled-macro-expansion -Wno-gnu-statement-expression -Wno-language-extension-token -Wno-overriding-method-mismatch ).join(" ") }) set_build_settings({ :'BUNDLE_ID_SUFFIX' => '.dev', :'BUNDLE_DISPLAY_NAME_SUFFIX' => 'dev', :'KZBEnv' => 'QA' }, configuration: :debug) set_build_settings({ :'BUNDLE_ID_SUFFIX' => '.adhoc', :'BUNDLE_DISPLAY_NAME_SUFFIX' => 'adhoc', :'KZBEnv' => 'QA' }, configuration: :adhoc) set_build_settings({ :'BUNDLE_ID_SUFFIX' => '', :'BUNDLE_DISPLAY_NAME_SUFFIX' => '', :'KZBEnv' => 'PRODUCTION' }, configuration: :release) # CUSTOM: Modify plist file to include suffix and displayname # CUSTOM: Add empty KZBootstrapUserMacros.h file to your project and .gitignore # CUSTOM: Add KZBEnvironments.plist with list of your environments under KZBEnvironments key # target specific options, :default is just a name for you, feel free to call it whatever you like with :default do # each target have set of pods pods << %w(KZAsserts KZBootstrap KZBootstrap/Logging KZBootstrap/Debug) # add build script for bootstrap scripts << {:name => 'KZBootstrap setup', :script => '"${SRCROOT}/Pods/KZBootstrap/Pod/Assets/Scripts/bootstrap.sh"'} end end
In you want to support dynamic env switching app delegate you can add something like this:
NSLog(@"user variable = %@, launch argument %@", @"d", [[NSUserDefaults standardUserDefaults] objectForKey:@"KZBEnvOverride"]); KZBootstrap.defaultBuildEnvironment = KZBEnv; KZBootstrap.onCurrentEnvironmentChanged = ^(NSString *newEnv, NSString *oldEnv) { NSLog(@"Changing env from %@ to %@", oldEnv, newEnv); }; [KZBootstrap ready]; NSLog(@"KZBootstrap:\n\tshortVersion: %@\n\tbranch: %@\n\tbuildNumber: %@\n\tenvironment: %@", KZBootstrap.shortVersionString, KZBootstrap.gitBranch, @(KZBootstrap.buildNumber), KZBootstrap.currentEnvironment);
License
KZBootstrap is available under the MIT license. See the LICENSE file for more info.
Author
Krzysztof Zablocki, krzysztof.zablocki@pixle.plMy blog
Follow me on twitter.
Attributions
All of this wouldn’t be possible if we didn’t have such a great community, based on my own previous work but also countless others. Tried to reference everything but if you think I missed something pleaselet me know.
References:
http://stackoverflow.com/questions/10497552/how-to-configure-independent-sets-of-runtime-settings-in-xcode
https://github.com/crushlovely/Amaro
https://github.com/crushlovely/Sidecar
http://swwritings.com/post/2013-05-20-concurrent-debug-beta-app-store-builds
https://gist.github.com/dulaccc/a52154ac4c007db2be55
https://gist.github.com/steipete/5664345
http://blog.manbolo.com/2013/05/17/passing-user-variable-to-xcodebuild
http://blog.jaredsinclair.com/post/97193356620/the-best-of-all-possible-xcode-automated-build
https://github.com/krzysztofzablocki/crafter
https://github.com/krzysztofzablocki/IconOverlaying
Big thanks goes to Lextech Global Services for supporting my community work, they are awesome. If you need a mobile app for your
enterprise, you should talk to them.
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 介绍一款信息管理系统的开源框架---jeecg
- 源码被倒卖,大厂薅羊毛,开源真的只能被予取予求?
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 专家解读:开源软件项目是否会被限制出口?
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- 专家解读:开源软件项目是否会被限制出口?
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- fuse-dfs的设定手册
- Centos下***(pptpd)的部署
- 开源MySQL高效数据仓库解决方案:Infobright详细介绍
- 关于jquery中全局函数each使用介绍
- C#利用delegate实现Javascript的each方法
- jquery中map函数与each函数的区别实例介绍
- jQuery.each()用法分享
- jquery里的each使用方法详解