前言
工作中总会遇到一些这样那样的需求, 比如需要打包一个 Appstore版
+ 企业版
. 但是却总要手动修改 Bundle Id
等等的这些信息, 比较麻烦(当然马甲包也可以这么搞),最重要的万一某一个宏忘记手动切换了,但是测试又没测出来就上架了 Appstore ,那问题就大了. 于是就有了这篇文章.
简介
这里用到的方法主要是对 target
进行复制, 并且使用脚本自动化的修改条件宏来通过 条件编译
达到我们的目的.
复制 target
右键点击需要复制的 target
, 点击 Duplicate
.就会复制出一份新的 target
.
此时选择新的
target
编译运行正常情况是能够直接通过的.Target 的配置
复制一些需要区别配置或者不同代码的文件.
-
AppDelegate
需要配置一些第三方的 key.比如友盟
个推
等.为了避免麻烦我直接拿出来分别写 -
Assets.xcassets
里面有不同的图片资源, 也需要复制一份. -
Info.plist
工程一些配置信息. -
main.m
里面需要配置AppDelegate
.(下面会讲) Main.Storyboard
LaunchScreen.storyboard
根据自身需求决定哪些文件需要 copy 新的.
文件配置
因为同一个工程内部不能有 同名的类
, 所以复制出来的 AppDelegate
需要修改一下名称 比如 NewAppDelegate
.这里就用到了 main.m
.
需要在 main.m
中做如下修改:
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([NewAppDelegate class]));
}
}
类/文件的归属配置:
这里是重点,配置不对将会很麻烦,甚至导致工程跑步起来.
此处以 main.m
为例:
选中 main.m
文件之后, Xcode 右侧区域中会出现 Target Membership
栏目. 如图所示:
此时选中的 target
就是该文件的归属, 通俗点就是在哪个 target
里面生效.
同一个文件也可以同时归属多个 target
.
大部分文件都可以通过这种方式来设置. 比如:
class
, xib
, storyboard
, xcassets
等.
如果编译时候某个类找不到了,就可以在这个地方把对应的 target 勾选中就可以了.
条件宏的自动化
分别创建宏的 头文件 Config.h
和 脚本文件 Config.sh
.
配置脚本
在 Build Phases
中点击左上角 +
新建一个 Run Script
.
在如图的位置写上执行脚本的路径
// $PROJECT_DIR 是工程根目录, 根据情况来写
$PROJECT_DIR/Config/Config.sh
脚本
在 Config.sh
中写入如下脚本:
// 开关配置的头文件路径, 根据情况来
HeaderPath=$SRCROOT/Config/ProjectConfig.h
// 通过判断 Bundle Id 来区分当前编译的是哪个 Target
if [ $PRODUCT_BUNDLE_IDENTIFIER == "com.example.app1" ]; then
// 把开关宏的值输入到配置文件内
echo "#define TARGET_SWITCH 0" '// app1' > $HeaderPath
elif [ $PRODUCT_BUNDLE_IDENTIFIER == "com.example.app2" ]; then
echo "#define TARGET_SWITCH 1" '// app2' > $HeaderPath
elif [ $PRODUCT_BUNDLE_IDENTIFIER == "com.example.app3" ]; then
echo "#define TARGET_SWITCH 2" '// app2' > $HeaderPath
else
echo "// 未配置" > $HeaderPath
fi
此时选择不同的 target
, 不管Run
还是 Build
, 在 Config.h
中就会自动在
#define TARGET_SWITCH 0
#define TARGET_SWITCH 1
...
#define TARGET_SWITCH n
之间自动切换了.
脚本的原理就是判断不同 target 的 bundle id 在 Config.h 写入不同的宏.
关于脚本怎么写, 可以自己学习一下 Shell
结束
到此, 你就可以根据 TARGET_SWITCH
的值来对不同的 target
区别编译不同的代码了.
补充: 虽然这个比较方便,但是却有可能因为某一个 target 的代码无法编译通过而导致其他的 target 也无法编译通过,因此要做好不同 target 代码的屏蔽.