分包配置

思维导图

catelog

Xcode 默认配置

Xcode 在生成项目时已经帮我们配置好了两个环境,并且已经在同一个scheme下做好了配置:

scheme

#Debug

测试环境,一般 Build、Run、Test 和 Analyze,都在这个环境中进行。

#Release

生产环境,Profile 和 Archive 打包上传商店时,使用这个环境。

查看Build Settings,你能看到每个设置下都分两种环境,可以做不同的设置。

有时我们需要的不止这两种环境,可能还需要企业版,又或者需要刷排名引流,这时就需要我们自己配置这些分包了。分包配置的大致原理是:同一个 TARGET 中设置不同的 Configurations,从而区分各种环境。下面将介绍具体的配置步骤~

1.配置 PROJECT

1.1.info

PROJECT->info->Configurations,点下方+,复制一份Debug或者Rlease的配置,重新命名,如InHouse

info-configurations

1.2.Build Settings

PROJECT->Build Settings,点顶部搜索框左边的+,Add User-Defined Settings,设置一个自定义的宏,如APP_NAME,分别输入名称。

buildset-userdefine

2.配置 TARGETS

TARGETS会自动继承PROJECT中的配置;反过来,对TARGETS所做的修改并不会主动映射到PROJECT中,需要手动复制。不复制也可以,不影响正常使用,因为 Xcode 会以TARGETS中的配置为准。

2.1.Build Settings

TARGETS->Build Settings中翻到底,User-Defined选项中自动继承了PROJECTAPP_NAME的配置。同样可以在这里点顶部的+,Add User-Defined Settings,添加新的配置项,如APP_BUNDLE_ID。在TARGETS->info中修改 Bundle display name 为${APP_NAME}。这样就可以给不同分包起不同的名字,或者不同的 Bundle Identifier。

APP_NAME

2.3.配置 preprocessor Macros

这是预处理的宏,后面代码中可作为标记区分不同环境。可自行设置:

Macros

2.4.代码中使用

以 UIabel 上的文字显示为例,要求不同环境中显示对应的环境名:

1
2
3
4
5
6
7
8
9
10
11
12
13
- #ifdef DEBUG
//Debug
_mLable.text = @"DEBUG";
#elif M_InHouse
//InHouse
_mLable.text = @"InHouse";
#elif M_Release
//Release
_mLable.text = @"Release";
#else
//Invalid
_mLable.text = @"默认值";
#endif

这里就是通过使用#ifdef#elif#else来判断是否有某个宏定义,而这些宏定义正是之前我们在 preprocessor Macros 中定义好的一些标记。运行查看效果即可~

3.配置 Scheme

Scheme->Manage Schemes->齿轮,复制一份并重新命名为Release或者InHouse

Manage Schemes

Edit Scheme,将 Build/Run/Test/Profile/Analyze/Archive 的 Build Configuration 设置成PROJECT中的 Configurations 中对应的名字,如RleaseInHouse

Edit Scheme

这一步配置 scheme 是为打包时更容易的区分环境,以防失误导致打错包。同时,如果你使用了脚本进行打包或者给不同分包替换图片素材时,也可以通过这个 scheme 进行区分。

4.配置 Pod 工程

如果工程集成了三方库,那么Pods工程也需要针对分包进行配置:

pods

这里的Configurations与原工程中一致即可。

5.脚本替换素材

我的工程目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.
├── AutoBuild
│   ├── ExportOptions.plist
│   ├── Header.plist
│   ├── replace_res.sh
│   └── res
│   ├── drawable
│   ├── icon
│   └── launcher
├── Majia
│   ├── AppDelegate.h
│   ├── AppDelegate.m
│   ├── Assets.xcassets
│   │   ├── AppIcon.appiconset
│   │   ├── Contents.json
│   │   └── LaunchImage.launchimage
│   ├── Info.plist
│   ├── main.m
│   └── res
├── Majia.xcodeproj
├── Majia.xcworkspace
├── Podfile
├── Podfile.lock
├── Pods
└──autobuild.sh

根据不同分包的需要,使用脚本替换素材replace_res.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/sh

#works for Xcode 7.0+ only

#获取命令行中接收到的scheme
TARGET_SCHEMES=$1

if [ ! -n "$TARGET_SCHEMES" ]; then
echo ">>>> TARGET_SCHEMES is missing!!!"
exit
fi

echo ">>>>>>>>>>>> Start replacing RES at $(date) <<<<<<<<<<<<<<<"

AUTOBUILD_PATH=$PWD
PROJECT_ROOT_PATH="$AUTOBUILD_PATH/.."

#导出配置
EXPORT_ICON_PATH="$AUTOBUILD_PATH/res/icon"
EXPORT_LAUNCHER_PATH="$AUTOBUILD_PATH/res/launcher"
EXPORT_DRAWABLE_PATH="$AUTOBUILD_PATH/res/drawable"

#icon Assets assets
ICON_ASSETS="$PROJECT_ROOT_PATH/Majia/Assets.xcassets/AppIcon.appiconset/"
LAUNCHER_ASSETS="$PROJECT_ROOT_PATH/Majia/Assets.xcassets/LaunchImage.launchimage/"
DRAWABLE_ASSETS="$PROJECT_ROOT_PATH/Majia/res/"

#replace icons
cp -R -a "$EXPORT_ICON_PATH/$TARGET_SCHEMES/." $ICON_ASSETS
#replace launchers
cp -R -a "$EXPORT_LAUNCHER_PATH/$TARGET_SCHEMES/." $LAUNCHER_ASSETS
#replace drawables
cp -R -a "$EXPORT_DRAWABLE_PATH/$TARGET_SCHEMES/." $DRAWABLE_ASSETS

echo ">>>>>>>>>>>> Finish replacing RES at $(date) <<<<<<<<<<<<<<<"

在终端里 cd 到根目录下的AutoBuild目录执行该脚本:

1
$./replace_res.sh InHouse

脚本后的参数是你想替换素材的分包scheme

6.脚本打包

cd 到根目录下,执行下面的打包脚本autobuild.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/bin/sh

#works for Xcode 7.0+ only

echo ">>>>>>>>>>>> Start at $(date) <<<<<<<<<<<<<<<"

PROJECT_ROOT_PATH=$PWD
AUTOBUILD_PATH="$PROJECT_ROOT_PATH/AutoBuild"

CURRENT_DATE=$(date +%Y_%m%d_%H%M)
WORKSPACE_NAME="Majia.xcworkspace"

#导出配置
HEADER_PLIST="$AUTOBUILD_PATH/Header.plist"
EXPORT_PLIST="$AUTOBUILD_PATH/ExportOptions.plist"

#Info key
KEY_SCHEME="KEY_SCHEME"
KEY_APP_NAME="KEY_APP_NAME"
KEY_TEAM_ID="KEY_TEAM_ID"
KEY_DEV_ID="KEY_DEV_ID"

#Flavors
InHouse={$KEY_SCHEME:"InHouse",$KEY_APP_NAME:"InHouse",$KEY_TEAM_ID:"your_team_ID",$KEY_DEV_ID:"your_team"}
Release={$KEY_SCHEME:"Release",$KEY_APP_NAME:"Release",$KEY_TEAM_ID:"your_team_ID",$KEY_DEV_ID:"your_team"}

#SELECT FLAVORS
FLAVORS=($Release,$InHouse)

#Parse method
parse_json(){
echo $1 | sed 's/.*'$2':\([^,}]*\).*/\1/'
}

#build release apps directory
BUILD_DIR="$PROJECT_ROOT_PATH/Build"
RELEASE_DIR="$BUILD_DIR/Products"

rm -rdf $BUILD_DIR

#final binarys' directory
OUT_BINARY_DIR="$PROJECT_ROOT_PATH/binarys_$CURRENT_DATE"

if [ ! -d $OUT_BINARY_DIR ]; then
mkdir $OUT_BINARY_DIR
fi

for ((i = 0; i < ${#FLAVORS[@]}; i++))
do

#parse elements
TARGET_SCHEMES=$(parse_json ${FLAVORS[$i]} $KEY_SCHEME)
TARGET_APP_NAMES=$(parse_json ${FLAVORS[$i]} $KEY_APP_NAME)
TARGET_TEAM_IDS=$(parse_json ${FLAVORS[$i]} $KEY_TEAM_ID)
TARGET_DEV_IDS=$(parse_json ${FLAVORS[$i]} $KEY_DEV_ID)

#reset export options plist
rm $EXPORT_PLIST

cat $HEADER_PLIST >> $EXPORT_PLIST

echo "<plist version=\"1.0\">" >> $EXPORT_PLIST
echo "<dict>" >> $EXPORT_PLIST
echo "<key>teamID</key>" >> $EXPORT_PLIST
echo "<string>$TARGET_TEAM_IDS</string>" >> $EXPORT_PLIST
echo "<key>method</key>" >> $EXPORT_PLIST

echo ">>>>>>>>>>>>>>>>>>>>>>>> target scheme $TARGET_SCHEMES"

if [ $TARGET_SCHEMES = "InHouse" ]; then
echo "<string>enterprise</string>" >> $EXPORT_PLIST
echo ">>>>>>>>>>>>>>>>>>>>>>>> enterprise Done"
else
echo "<string>app-store</string>" >> $EXPORT_PLIST
echo ">>>>>>>>>>>>>>>>>>>>>>>> app-store Done"
fi

echo "<key>uploadSymbols</key>" >> $EXPORT_PLIST
echo "<true/>" >> $EXPORT_PLIST
echo "</dict>" >> $EXPORT_PLIST
echo "</plist>" >> $EXPORT_PLIST

echo ">>>>>>>>>>>>>>>>>>>>>>>> Reset export options Done"

cd $AUTOBUILD_PATH
./replace_res.sh $TARGET_SCHEMES

# return root
cd $PROJECT_ROOT_PATH
echo ">>>>>>>>>>>>>>>>>>>>>>>> Reset res Done"

#export files
ARCHIVE_FILE="$OUT_BINARY_DIR/$TARGET_APP_NAMES.xcarchive"
DSYMS_FILE="$TARGET_APP_NAMES.dSYMs.zip"

#clean prject
xcodebuild -workspace $WORKSPACE_NAME -scheme $TARGET_SCHEMES -configuration $TARGET_APP_NAMES clean

#build & archive
xcodebuild archive -workspace $WORKSPACE_NAME -scheme $TARGET_SCHEMES -configuration $TARGET_APP_NAMES -archivePath $ARCHIVE_FILE

cd $ARCHIVE_FILE
zip -r $DSYMS_FILE "dSYMs"
mv $DSYMS_FILE $OUT_BINARY_DIR

# return root
cd $PROJECT_ROOT_PATH

#export
xcodebuild -exportArchive -archivePath $ARCHIVE_FILE -exportPath $OUT_BINARY_DIR -exportOptionsPlist $EXPORT_PLIST

#rename ipa file failed since creating ipa file is asynchronized
echo "apple id paired" >> "$OUT_BINARY_DIR/$TARGET_APP_NAMES_$TARGET_DEV_IDS"

echo ">>>>>>>>>>>>>>>>>>>>>>>> $TARGET_SCHEMES single loop Done"

done

echo ">>>>>>>>>>>> Finish at $(date) <<<<<<<<<<<<<<<"

根据需要修改脚本中的 teamID 和开发者证书信息,修改将要打包的 scheme,cd 到工程根目录执行脚本:

1
$./autobuild.sh

此脚本做了以下几件事:

  • 生成打包所需的 ExportOptions.plist;
  • 自动执行 replace_res.sh 脚本替换素材,你无须手动执行了;
  • 根据指定的 scheme 执行 archive;
  • 导出dSYM文件;
  • 导出 ipa。

7.小缺点

根据我自己的使用情况来看,配置过多分包时,在 Xcode 中打开Build Settings会非常卡。这可能是因为 Xcode 中的各种配置从本质上来说都是保存在 plist 中,加载此配置文件时,要读取N个分包的节点,是需要花费一定时间。


相关参考:

#©项目代码


分包配置
https://davidlii.cn/2019/06/18/majia.html
作者
Davidli
发布于
2019年6月18日
许可协议