iOS-自动化打包方案

技 术 文 章 / 超 人


自动化打包方案1:xcodebuild打包

使用xcodebuild自动化打包给我的感觉就是用命令行来控制Xcode进行编译打包,xcodebuild打包有3种,一种是adHoc测试打包ipa,一个是上传AppStore打包,一个企业级别打包。具体区别请看下面的步骤中说明
了解xcodebuild打包先从终端操作开始,废话不多说,撸起袖子干。

  • 步骤1:
    首先打开终端 cd到当前工程目录

  • 步骤2:
    在终端中输入一下内容来完成编译
    xcodebuild archive -workspace XXX.xcworkspace -scheme XXX -configuration Release -archivePath ./myArchivePath CONFIGURATION_BUILD_DIR ./dir ODE_SIGN_IDENTITY=证书 PROVISIONING_PROFILE=描述文件UUID

key 说明
-workspace XXX.xcworkspace XXX.xcworkspace需要编译工程的工作空间名称,如果工程不是.xcworkspace的,可以不需要-workspace XXX.xcworkspace这段话
-scheme XXX XXX是工程名称,-scheme XXX是指定构建工程的名称
-configuration Release 填入打包的方式是Debug或Release,就跟在Xcode中编译前需要在Edit scheme的Build configuration中选择打出来的包是Debug还是Release包一样,-configuration就是配置编译的Build configuration
-archivePath ./myArchivePath 配置生成.xcarchive的路径, ./表示生成在当前目录下,myArchivePath是生成的.Archive文件名称
ODE_SIGN_IDENTITY=证书 配置打包的指定证书,如果该工程的Xcode已经配置好了证书,那么不加入这段话也可以,打包出来的证书就是Xcode中配置好的。
PROVISIONING_PROFILE=描述文件UUID 配置打包的描述文件,同上,Xcode已经配置好了就不用在填入这段话了
CONFIGURATION_BUILD_DIR 配置编译文件的输出路径,如果需要用到.xcarchive文件内部的dSYM等文件,可以使用改字段指定输出路径。

如果工程是勾选了Automatically manage signing,那么就不用在配置ODE_SIGN_IDENTITY和PROVISIONING_PROFILE


Automatically manage signing

获取证书名:


在电脑钥匙串的证书查找需要使用的证书

获取描述文件UUID:
首先在Finder中前往/Users/用户名/Library/MobileDevice/Provisioning Profiles路径

前往

然后在Provisioning Profiles文件夹中选择打包需要的描述文件,一般描述文件的文件名都是由UUID组成的,如果文件名不是由UUID组成的,可以在终端中cd到Provisioning Profiles路径,输入/usr/bin/security cms -D -i 23ec4472-bfc4-4128-a96c-2018021f52f3.mobileprovision,23ec4472-bfc4-4128-a96c-2018021f52f3.mobileprovision是描述文件的名称,然后在终端的解析结果中找到UUID
描述文件

在终端中解析描述文件,查找UUID

输入步骤2的命令后,终端会输出十多秒,在你指定的路径下生成.xcarchive文件


.xcarchive文件

右键点击.xcarchive文件的显示包内容,其中包含dSYM和app


.xcarchive文件内容
  • 步骤3:配置打包的ExportOptions.plist文件
    可以在任意一个Xcode工程中新建一个ExportOptions.plist文件。adHoc和AppStore的配置文件内容不一样
    image.png

adHoc的配置内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>compileBitcode</key>//是否编译bitcode
    <true/>
    <key>method</key>
    <string>ad-hoc</string>/
    <key>provisioningProfiles</key>
    <dict>
        <key>文件bundle id</key>
        <string>Adhoc_ID</string>
    </dict>
    <key>signingCertificate</key>//证书签名
    <string>这里填证书签名</string>
    <key>signingStyle</key>
    <string>manual</string>
    <key>stripSwiftSymbols</key>
    <true/>
    <key>teamID</key>
    <string>AANCCUK4M3</string>//TeamID
    <key>thinning</key>
    <string>&lt;none&gt;</string>
</dict>
</plist>
adHoc的配置内容

App Store配置内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>app-store</string>
    <key>provisioningProfiles</key>
    <dict>
        <key>这里填应用的bundle id</key>
        <string>这里填对应budle id的证书名</string>
    </dict>
    <key>signingCertificate</key>
    <string>这里填签名证书</string>
    <key>signingStyle</key>
    <string>manual</string>
    <key>stripSwiftSymbols</key>
    <true/>
    <key>teamID</key>
    <string>这里是teamID</string>
    <key>uploadBitcode</key>
    <false/>
    <key>uploadSymbols</key>
    <false/>
</dict>
</plist>
App Store配置内容

如果实在不知道plist文件如何写,可以自己先手动打一个AdHoc和Appstore的包,生成的文件中就会有一个ExportOptions.plist文件,看看里面的区别,也可以拿过来直接用。

  • 步骤4:工程路径下的终端中输入xcodebuild -exportArchive -archivePath ./myArchivePath.xcarchive -exportOptionsPlist ./ExportOptions.plist -exportPath ./out ,这一步实际就是Xcode编译号后在工程中勾选打包的选择。只是用配置文件的方式来抵销手动选择。
key 说明
-archivePath ./myArchivePath.xcarchive 指定需要打包的.xcarchive路径,./myArchivePath.xcarchive表示在当前终端路径下的myArchivePath.xcarchive文件
-exportOptionsPlist ./ExportOptions.plist 指定打包需要的ExportOptions.plist配置文件路径
-exportPath ./out 指定打包输出的路径, ./out表示打包结果输出在终端的当前路径下的out文件家中。如果没有out文件夹会自动创建一个

这样就完成了终端里的打包。

当你明白打包的具体步骤后,我们就可以把上面的步骤放在shell脚本中,然后在终端用一个命令来执行shell脚本来实现自动打包,更加简便。
制作脚本:

首先:cd到需要自动打包的工程下
然后:在终端中输入touch xcodebuild.sh创建xcodebuild.sh脚本文件
然后:双击打开脚本写入下面 脚本内容(请确保所有版本的plist配置文件都写好了)
最后:在终端中输入 ./xcodebuild.sh运行脚本,按照步骤完成打包选择(如果运行的时候出现Permission denied,请先在终端中执行chmod a+x *.文件的后缀名 后,在运行。
)

脚本内容

#author by heyujia
#脚本所在的目录必须和WorkSpace或者说工程主目录所在的目录在同一个目录层级中

#配置参数

#workspace的名字,如果没有则不需要这段话,我测试工程不是一个工作空间所以就没用,如果需要用的话,还需要在编译阶段的脚本代码里加上 -workspace ${Project_Name}.xcworkspace
#Workspace_Name="WorkSpace名字"


#工程名字
Project_Name="Demo"


#配置打包方式Release或者Debug
Configuration="Release"



#基础主路径
BUILD_PATH=./build


#不同版本的基础子路径
#adHoc
ADHOC_PATH=${BUILD_PATH}/adHoc
#appStore
APPSTORE_PATH=${BUILD_PATH}/appStore
#enterprise
ENTERPRISE_PATH=${BUILD_PATH}/enterprise

#配置编译文件的存放地址
#adHoc
CONFIGURATION_BUILD_PATH_ADHOC=${ADHOC_PATH}/${Configuration}-iphoneos
#appStore
CONFIGURATION_BUILD_PATH_APPSTORE=${APPSTORE_PATH}/${Configuration}-iphoneos
#企业
CONFIGURATION_BUILD_PATH_ENTERPRISE=${ENTERPRISE_PATH}/${Configuration}-iphoneos

#下面是获取上传到第三方统计崩溃日志的文件,如果没有用到可以删除该部分
#adHoc
DSYM_PATH_ADHOC=${CONFIGURATION_BUILD_PATH_ADHOC}/${Project_Name}.app.dSYM
DSYM_ZIP_PATH_ADHOC=${ADHOC_PATH}/${Project_Name}.app.dSYM.zip
DSYM_COPY_PATH_ADHOC=${ADHOC_PATH}/copy
#appStore
DSYM_PATH_APPSTORE=${CONFIGURATION_BUILD_PATH_APPSTORE}/${Project_Name}.app.dSYM
DSYM_ZIP_PATH_APPSTORE=${APPSTORE_PATH}/${Project_Name}.app.dSYM.zip
DSYM_COPY_PATH_APPSTORE=${APPSTORE_PATH}/copy
#企业
#appStore
DSYM_PATH_ENTERPRISE=${CONFIGURATION_BUILD_PATH_ENTERPRISE}/${Project_Name}.app.dSYM
DSYM_ZIP_PATH_ENTERPRISE=${ENTERPRISE_PATH}/${Project_Name}.app.dSYM.zip
DSYM_COPY_PATH_ENTERPRISE=${ENTERPRISE_PATH}/copy



#配置打包结果输出的路径
#AdHoc版本
AdHocPrijectOutPath=${ADHOC_PATH}/adHocOut
#AppStore版本
AppStorePrijectOutPath=${APPSTORE_PATH}/appStoreOut
#企业版本
EnterprisePrijectOutPath=${ENTERPRISE_PATH}/enterpriseOut


#如果工程中配置了Automatically manage signing,那么就不需要证书名和描述文件名,请确保工程中配置的证书名和描述文件是你打包想要用的
#ADHOC证书名#描述文件
ADHOCCODE_SIGN_IDENTITY="iPhone Distribution: xxxx"
ADHOCPROVISIONING_PROFILE_NAME="xxxxx-xxxx-xxxx-xxxx-xxxxxx"

#AppStore证书名#描述文件
APPSTORECODE_SIGN_IDENTITY="iPhone Distribution: xxxxx"
APPSTOREROVISIONING_PROFILE_NAME="xxxxx-xxxx-xxxx-xxxx-xxxxxx"

#企业(enterprise)证书名#描述文件
ENTERPRISECODE_SIGN_IDENTITY="iPhone Distribution: xxxx"
ENTERPRISEROVISIONING_PROFILE_NAME="xxxxx-xxxx-xxx-xxxx"





#加载各个版本的plist文件,为了实现一个脚本打包所有版本,这里对不同对版本创建了不同的plist配置文件。等号后面是文件路径,一般把plist文件放在与脚本同一级别的文件层中。我这里测试用所以plist文件都一样,实际使用是请分开配置为不同文件
ADHOCExportOptionsPlist="./ExportOptions.plist"
AppStoreExportOptionsPlist="./ExportOptions.plist"
EnterpriseExportOptionsPlist="./ExportOptions.plist"


#在终端中提示 根据输入的序号不同,打包成不同版本的ipa
echo "~~~~~~~~~~~~选择打包方式(输入序号)~~~~~~~~~~~~~~~"
echo "  1 adHoc"
echo "  2 AppStore"
echo "  3 Enterprise"

# 读取用户在终端中输入并存到变量里
read parameter
sleep 0.5
method="$parameter"

# 判读用户是否有输入
if [ -n "$method" ]
then
if [ "$method" = "1" ]
then
#这里都执行命令中是在xcworkspace工程中执行的,如果工程不是xcworkspace,可以把-workspace的内容删掉,加入了证书和描述文件,如果不需要请删除
#如果用户选择的是1,就执行adhoc脚本
#首先清除原来的文件夹
rm -rf ${BUILD_PATH}
#创建文件夹,路径需要一层一层创建,不然会创建失败
mkdir ${BUILD_PATH}
mkdir ${ADHOC_PATH}
#编译文件
mkdir ${CONFIGURATION_BUILD_PATH_ADHOC}
#打包输出的文件
mkdir ${AdHocPrijectOutPath}
#copy
mkdir ${DSYM_COPY_PATH_ADHOC}
#编译
xcodebuild archive -scheme $Project_Name -configuration $Configuration -archivePath ${ADHOC_PATH}/$Project_Name-adhoc.xcarchive CONFIGURATION_BUILD_DIR=${CONFIGURATION_BUILD_PATH_ADHOC}
#如果需要单独设置证书和描述文件需要在编译时加入下面这句话
#CODE_SIGN_IDENTITY="${ADHOCCODE_SIGN_IDENTITY}" PROVISIONING_PROFILE="${ADHOCPROVISIONING_PROFILE_NAME}" PRODUCT_BUNDLE_IDENTIFIER="${AdHocBundleID}"
#打包
xcodebuild  -exportArchive -archivePath ${ADHOC_PATH}/$Project_Name-adhoc.xcarchive -exportOptionsPlist $ADHOCExportOptionsPlist -exportPath ${AdHocPrijectOutPath}
# 选择是压缩还是复制,复制的方法可以用于上传文件到指定服务器,比如上传到git
# zip -r 目标路径  源文件路径 ,开始压缩dSYM文件
zip -r ${DSYM_ZIP_PATH_ADHOC} ${DSYM_PATH_ADHOC}
# cp -r 源文件路径 目标路径 , 把压缩包拷贝到指定地方
cp -r ${DSYM_ZIP_PATH_ADHOC} ${DSYM_COPY_PATH_ADHOC}
# 复制 dSYM 包里的 XXX 文件 上传到指定的地方
#TARGET_PATH=${DSYM_COPY_PATH}/${TARGET}.app.dSYM/Contents/Resources/DWARF/${TARGET}
#cp ${TARGET_PATH} ${EXPORT_DIR}
elif [ "$method" = "2" ]
then
#如果用户选择的是2,就执行appstore脚本
#首先清除原来的文件夹
rm -rf ${BUILD_PATH}
#创建文件夹,路径需要一层一层创建,不然会创建失败
mkdir ${BUILD_PATH}
mkdir ${APPSTORE_PATH}
#编译文件
mkdir ${CONFIGURATION_BUILD_PATH_APPSTORE}
#打包输出的文件
mkdir ${AppStorePrijectOutPath}
#copy
mkdir ${DSYM_COPY_PATH_APPSTORE}
xcodebuild archive -scheme $Project_Name -configuration $Configuration -archivePath ${APPSTORE_PATH}/$Project_Name-appstore.xcarchive CONFIGURATION_BUILD_DIR=${CONFIGURATION_BUILD_PATH_APPSTORE}
xcodebuild  -exportArchive -archivePath ${APPSTORE_PATH}/$Project_Name-appstore.xcarchive -exportOptionsPlist $AppStoreExportOptionsPlist -exportPath ${AppStorePrijectOutPath}
#创建copy文件夹
mkdir ${DSYM_COPY_PATH_APPSTORE}
# 选择是压缩还是复制,复制的方法可以用于上传文件到指定服务器,比如上传到git
# zip -r 目标路径  源文件路径 ,开始压缩dSYM文件
zip -r ${DSYM_ZIP_PATH_APPSTORE} ${DSYM_PATH_APPSTORE}
# cp -r 源文件路径 目标路径 , 把压缩包拷贝到指定地方
cp -r ${DSYM_ZIP_PATH_APPSTORE} ${DSYM_COPY_PATH_APPSTORE}
#验证ipa是否打包成功
if [ -e $AppStorePrijectOutPath/$Project_Name.ipa ]; then
echo '----ipa包已生成----'
open $AppStorePrijectOutPath
echo '----打包ipa完成----'
echo '**---------------**'
echo '****开始发布ipa包****'
echo '**---------------**'
#验证后上传到App Store
# 将-u 后面的XXX替换成自己的AppleID的账号,-p后面的XXX替换成自己的密码
altoolPath="/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool"
"$altoolPath" --validate-app -f ${exportIpaPath}/${scheme_name}.ipa -u XXX -p XXX -t ios --output-format xml
"$altoolPath" --upload-app -f ${exportIpaPath}/${scheme_name}.ipa -u  XXX -p XXX -t ios --output-format xml
else
echo '----ipa包导出失败----'
fi


elif [ "$method" = "3" ]
then
#如果用户选择的是3,就执行企业脚本
#首先清除原来的文件夹
rm -rf ${BUILD_PATH}
#创建文件夹,路径需要一层一层创建,不然会创建失败
mkdir ${BUILD_PATH}
mkdir ${ENTERPRISE_PATH}
#编译文件
mkdir ${CONFIGURATION_BUILD_PATH_ENTERPRISE}
#打包输出的文件
mkdir ${EnterprisePrijectOutPath}
#copy
mkdir ${DSYM_COPY_PATH_ENTERPRISE}
xcodebuild archive -scheme $Project_Name -configuration $Configuration -archivePath ${ENTERPRISE_PATH}/$Project_Name-enterprise.xcarchive CONFIGURATION_BUILD_DIR=${CONFIGURATION_BUILD_PATH_ENTERPRISE}
xcodebuild  -exportArchive -archivePath ${ENTERPRISE_PATH}/$Project_Name-enterprise.xcarchive -exportOptionsPlist $EnterpriseExportOptionsPlist -exportPath ${EnterprisePrijectOutPath}
#创建copy文件夹
mkdir ${DSYM_COPY_PATH_ENTERPRISE}
# 选择是压缩还是复制,复制的方法可以用于上传文件到指定服务器,比如上传到git
# zip -r 目标路径  源文件路径 ,开始压缩dSYM文件
zip -r ${DSYM_ZIP_PATH_ENTERPRISE} ${DSYM_PATH_ENTERPRISE}
# cp -r 源文件路径 目标路径 , 把压缩包拷贝到指定地方
cp -r ${DSYM_ZIP_PATH_ENTERPRISE} ${DSYM_COPY_PATH_ENTERPRISE}
# 将 dSYM 包里的 demo 文件 上传到指定地点 
TARGET_PATH=${DSYM_COPY_PATH}/${Project_Name}.app.dSYM/Contents/Resources/DWARF/${Project_Name} cp ${TARGET_PATH} ${EXPORT_DIR}
else
#如果是其他输入,则在终端中提示参数无效并退出
echo "参数无效...."
exit 1
fi
fi

注意:在写脚本的时候,要注意=号的前后不要有空格,我写OC代码风格都是喜欢 =号 前后空格,这样间距美观。但是脚本里如果有空格会造成命令无效。


自动化打包方案2

...未完待续