欢迎到个人博客: liumh.com查看本文。
与公司 QA 聊天,已不止1次被吐槽说移动端从开发环境转到生产环境时,还要靠修改代码来配置对应的环境参数。她认为,从 App 转测试以后,就不应当再修改代码,可以把所有的环境配置都整合到配置文件中,这样打不同环境下的安装包时,会自动选择对应的环境参数。这里说到的环境参数包括但不但限于: webservice 地址,友盟 AppKey,极光推送 AppKey 和是不是是生产环境标志等。
其实,我也讨厌修改环境参数啊~
为达成上述目的,主要是使用 Xcode 的 Configurations Setting File(即后缀为 xcconfig 文件) 来配置开发不同阶段下的环境。本文包括的内容以下:
包括了1些与 build settings 相干的知识。
target, 官方文档以下解释:
A target specifies a product to build and contains the instructions for building the product from a set of files in a project or workspace. A target defines a single product; it organizes the inputs into the build system—the source files and instructions for processing those source files—required to build that product. Projects can contain one or more targets, each of which produces one product.
target 定义了生成的唯1 product, 它将构建该 product 所需的文件和处理这些文件所需的指令集整合进 build system 中。Projects 会包括1个或多个 targets,每个 target 将会产出1个 product.
The instructions for building a product take the form of build settings and build phases, which you can examine and edit in the Xcode project editor. A target inherits the project build settings, but you can override any of the project settings by specifying different settings at the target level. There can be only one active target at a time; the Xcode scheme specifies the active target.
这些指令以 build setting 和 build phases 的情势存在,你可在 Xcode 的项目编辑器(TARGETS->Build Setting, TARGETS->Build Phases)中进行查看和编辑。target 中的 build setting 参数继承自 project 的 build settings, 但是你可以在 target 中修改任意 settings 来重写 project settings,这样,终究生效的 settings 参数以在 target 中设置的为准. Project 可包括多个 target, 但是在同1时刻,只会有1个 target 生效,可用 Xcode 的 scheme 来指定是哪个 target 生效.
A target and the product it creates can be related to another target. If a target requires the output of another target in order to build, the first target is said to depend upon the second. If both targets are in the same workspace, Xcode can discover the dependency, in which case it builds the products in the required order. Such a relationship is referred to as an implicit dependency. You can also specify explicit target dependencies in your build settings, and you can specify that two targets that Xcode might expect to have an implicit dependency are actually not dependent. For example, you might build both a library and an application that links against that library in the same workspace. Xcode can discover this relationship and automatically build the library first. However, if you actually want to link against a version of the library other than the one built in the workspace, you can create an explicit dependency in your build settings, which overrides this implicit dependency.
target 和其生成的 product 可与另外一个 target 有关,如果1个 target 的 build 依赖于另外一个 target 的输出,那末我们就说前1个 target 依赖于后1个 target .如果这些 target 在同1个 workspace 中,那末 Xcode 能够发现这类依赖关系,从而使其以我们期望的顺序生成 products.这类关系被称为隐式依赖关系。同时,你可以显示指定 targets 之间的依赖关系,并且这类依赖关系会覆盖 Xcode 推测出的隐式依赖关系。
指定 targets 之间的依赖关系的地方在 Project Editor->TRAGETS->Build Phases->Target Dependencies 处设置。以下图所示:
官方文档的解释以下:
An Xcode project is a repository for all the files, resources, and information required to build one or more software products. A project contains all the elements used to build your products and maintains the relationships between those elements. It contains one or more targets, which specify how to build products. A project defines default build settings for all the targets in the project (each target can also specify its own build settings, which override the project build settings).
Xcode project 是1个仓库,该仓库包括了所有的文件,资源和用于生成1个或多个 software products 的信息。它包括1个或多个 targets,其中的每个 target 指明了如何生成 products。project 为其具有的所有 targets 定义了默许的 build settings,固然,每个 target 能够制定其自己的 build settings,且 target 的 build settings 会重写 project 的 build settings。
Xcode project 文件包括以下信息:
project 可独立存在,也可被包括在 workspace 中。
官方文档内容以下:
A build setting is a variable that contains information about how a particular aspect of a product’s build process should be performed. For example, the information in a build setting can specify which options Xcode passes to the compiler.
You can specify build settings at the project or target level. Each project-level build setting applies to all targets in the project unless explicitly overridden by the build settings for a specific target.
build setting 中包括了 product 生成进程中所需的参数信息。你可以在 project-level 和 target-level 层指定 build settings。project-level 的 build settings 适用于 project 中的所有targets,但是当 target-level 的 build settings 重写了 project-level 的 build settings,以 target-level 中的 build settings 中的值为准。
Each target organizes the source files needed to build one product. A build configuration specifies a set of build settings used to build a target’s product in a particular way. For example, it is common to have separate build configurations for debug and release builds of a product.
1个 build configaration 指定了1套 build settings 用于生成某1 target 的 product,例如,在 Xcode 创建项目时默许就有两套独立的 build configarations, 分别用于生成 debug 和 release 模式下的 product。
In addition to the default build settings provided by Xcode when you create a new project from a project template, you can create user-defined build settings for your project or for a particular target. You can also specify conditional build settings. The value of a conditional build setting depends on whether one or more prerequisites are met. This mechanism allows you to, for example, specify the SDK to use to build a product based on the targeted architecture.
除创建工程时生成的默许 build settings,你也能够自定义 project-level 或 target-level 的 build settings.
关于继承关系,The Unofficial Guide to xcconfig files 这里也有详细的说明,强烈建议浏览。
现在就来看看如何使用自定义的 build settings 来到达本文开始处提到的需求.
目前公司中的开发大致分两个阶段,第1阶段:开发阶段,此时所打包都是使用 development 的证书,极光和友盟统计的账号都是使用开发者自己申请的账号,webservice 的地址使用开发环地步址;第2阶段:uat 阶段,此时属于预发版阶段,此时打包使用 ad-hoc 的证书,极光和友盟统计的账号使用公司申请生成账号,webservice 使用的特定的预发版环境;另外,打上传到 App Store 的生产包,使用 distribution 的证书,webservice 的地址使用生产环境的地址。
由此,可新建1种 build configuration, 由 Xcode 自动生成的 Release 复制而来,以下所示:
并命名为 PreRelease。
官方文档Adding a Build Configuration 中以下提到:
A configuration file is a plain text file with a list of build setting definitions, one per line. You can base a build configuration only on a configuration file that is in your project, not on an external file.
When you base a target or project’s build configuration on a configuration file, that build configuration automatically inherits the build setting definitions in that configuration file (and any configuration files it includes). If you then modify the value of any of those build settings in the target or project, the new value is used instead of the value in the configuration file.
Build settings defined at the target level override any values assigned to those build settings at the project level. Therefore, target-level configurations take precedence over any project-level configurations.
这里需要注意的是:当你的 target-level 或 project-levle 的 build configurations 基于配置文件时,build configuration 会自动继承配置文件(和配置文件中引入的配置文件)中定义的 build settings,但是如果你又在以后 target 或 project 中修改了配置文件中定义的 build settings 值,那末终究配置文件中的值会失效,实际使用的是 target 或 project 中设置的值。
这里鉴于公司的情况,新建了 Debug.xcconfig/PreRelease.xcconfig/Release.xcconfig 配置对应于开发阶段、预发版阶段、上传 AppStore 3种情况下的打包。
新建1个 xcconfig 目录,在该目录下新建配置文件:
根据项目情况,每一个配置文件中都包括一样的 key 值,内容大致以下:
//网络要求baseurl
WEBSERVICE_URL = @"http:\/\/127.0.0.1"
//友盟配置
UMENG_APPKEY = @"xxxvvv555999=="
//极光推送配置
JPUSH_DEVELOPMENT_APPKEY = @"nnncccvvvwww"
IS_PRODUCATION = NO
#include "Generator.xcconfig"
你可在配置文件中包括其他配置文件,其中 Generator.xcconfig 文件的内容是:
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) WEBSERVICE_URL='$(WEBSERVICE_URL)' MESSAGE_SYSTEM_URL='$(MESSAGE_SYSTEM_URL)' UMENG_APPKEY='$(UMENG_APPKEY)' IS_PRODUCATION='$(IS_PRODUCATION)'
其作用是将配置文件中定义的常量定义成预编译宏,以便于在代码中获得。
其中 GCC_PREPROCESSOR_DEFINITIONS, 文档以下:
Space-separated list of option specifications. Specifies preprocessor macros in the form foo (for a simple #define) or foo=1 (for a value definition). This list is passed to the compiler through the gcc -D option when compiling precompiled headers and implementation files.
GCC_PREPROCESSOR_DEFINITIONS 是 GCC 预编译头参数,通常我们可以在 Project 文件下的 Build Settings 对预编译宏定义进行默许赋值。在 Xcode7 下的路径为 Build Settings->Apple LLVM 7.x Preprocessing->Preprocessor Macros,
想必大家看这个宏的名字已知道它的作用了, 使用上和在 pch 头文件中添加宏定义没有太大的区分, 但有以下好处:
xcconfig 支持可以根据不同的 Configuration 选项配置不同的文件。不同的 xcconfig 可以指定不同的 Build Settings 里的属性值, 这模样我们就能够通过项目 xcconfig 去修改 GCC_PREPROCESSOR_DEFINITIONS 的值了(终究目的就到达了)。
配置文件中变量定义好以后,怎样让 Xcode 自动加载呢?以下图设置所示,是将 project-level 的 build settings 基于配置文件,3种情况的 configurations 分别选择与之对应的配置文件。
当我们想把 project-level 或 target-level 中的 Build Settings 的设置移动到 xcconfig 配置文件来设置时,是不是需要1个个手动输入呢?固然不是,直接在 Build Settings 当选中你想要在 xcconfig 中配置的键值对所在行(固然也能够选多行),command + c复制,然后到对应的 xcconfig 中去粘贴就行了,记得在 Build Settings 中改成你想要的值后再复制,如果为默许值的话则只可复制其键。如果需要改回去的话,还是选中这行,command + delete
就恢复默许值了。
现在我们将设置移动到了配置文件中,所有的配置文件都是键值对类型的文本文件,但是当同1个键同时存在于 target-level、project-level 和配置文件中时,究竟是哪个键值对起作用了呢?现在看看下图。
注意: Xcode以从左至右的顺序设置解析的优先级,从左至右优先级下降,最左侧的具有最高优先级,即 target-level > project-level > 自定义配置文件 > iOS 默许配置;且最左列 Resolved 列显示的是终究使用的值。那末如何使 Xcode 使用配置文件中的配置项呢?这需要选中要使用配置文件的行,点击 Delete 按键,你会发现项目的默许设置已被删除,且 xcconfig 的配置文件列被标记为绿色。标记为绿色代表该列的值生效,其值应当与 Resolved 列的值相同。
最后,你可以像以下示例使用 xcconfig 中定义的宏:
NSLog(@"webservice url: %@, umeng appkey: %@", WEBSERVICE_URL, UMENG_APPKEY);
通过以上步骤,就到达了使用 xcconfig 文件来配置开发不同阶段时的环境变量的目的了。
文中内容为自己学习总结,如有毛病的地方请指正。
如果觉得本文对你有帮助,就请用微信随便打赏我吧^_^
参考:
上一篇 一个操作系统的实现(7)-获取机器内存并进行合理分页
下一篇 css3中的部分属性