树下敲代码的超人 关注
2.3 2018.03.01 16:53* 字数 776 阅读 8200评论 22喜欢 62
技 术 文 章 / 超 人
自动化打包方案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.xcworkspaceXXX.xcworkspace需要编译工程的工作空间名称,如果工程不是.xcworkspace的,可以不需要-workspace XXX.xcworkspace这段话
-scheme XXXXXX是工程名称,-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的配置内容
compileBitcode//是否编译bitcodemethodad-hoc/provisioningProfiles文件bundle idAdhoc_IDsigningCertificate//证书签名这里填证书签名signingStylemanualstripSwiftSymbolsteamIDAANCCUK4M3//TeamIDthinning
adHoc的配置内容
App Store配置内容:
methodapp-storeprovisioningProfiles这里填应用的bundle id这里填对应budle id的证书名signingCertificate这里填签名证书signingStylemanualstripSwiftSymbolsteamID这里是teamIDuploadBitcodeuploadSymbols
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或者DebugConfiguration="Release"#基础主路径BUILD_PATH=./build#不同版本的基础子路径#adHocADHOC_PATH=${BUILD_PATH}/adHoc#appStoreAPPSTORE_PATH=${BUILD_PATH}/appStore#enterpriseENTERPRISE_PATH=${BUILD_PATH}/enterprise#配置编译文件的存放地址#adHocCONFIGURATION_BUILD_PATH_ADHOC=${ADHOC_PATH}/${Configuration}-iphoneos#appStoreCONFIGURATION_BUILD_PATH_APPSTORE=${APPSTORE_PATH}/${Configuration}-iphoneos#企业CONFIGURATION_BUILD_PATH_ENTERPRISE=${ENTERPRISE_PATH}/${Configuration}-iphoneos#下面是获取上传到第三方统计崩溃日志的文件,如果没有用到可以删除该部分#adHocDSYM_PATH_ADHOC=${CONFIGURATION_BUILD_PATH_ADHOC}/${Project_Name}.app.dSYMDSYM_ZIP_PATH_ADHOC=${ADHOC_PATH}/${Project_Name}.app.dSYM.zipDSYM_COPY_PATH_ADHOC=${ADHOC_PATH}/copy#appStoreDSYM_PATH_APPSTORE=${CONFIGURATION_BUILD_PATH_APPSTORE}/${Project_Name}.app.dSYMDSYM_ZIP_PATH_APPSTORE=${APPSTORE_PATH}/${Project_Name}.app.dSYM.zipDSYM_COPY_PATH_APPSTORE=${APPSTORE_PATH}/copy#企业#appStoreDSYM_PATH_ENTERPRISE=${CONFIGURATION_BUILD_PATH_ENTERPRISE}/${Project_Name}.app.dSYMDSYM_ZIP_PATH_ENTERPRISE=${ENTERPRISE_PATH}/${Project_Name}.app.dSYM.zipDSYM_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"#在终端中提示 根据输入的序号不同,打包成不同版本的ipaecho"~~~~~~~~~~~~选择打包方式(输入序号)~~~~~~~~~~~~~~~"echo" 1 adHoc"echo" 2 AppStore"echo" 3 Enterprise"# 读取用户在终端中输入并存到变量里readparametersleep 0.5method="$parameter"# 判读用户是否有输入if[ -n"$method"]thenif["$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}#copymkdir${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}#copymkdir${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 ];thenecho'----ipa包已生成----'open$AppStorePrijectOutPathecho'----打包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 xmlelseecho'----ipa包导出失败----'fielif["$method"="3"]then#如果用户选择的是3,就执行企业脚本#首先清除原来的文件夹rm -rf${BUILD_PATH}#创建文件夹,路径需要一层一层创建,不然会创建失败mkdir${BUILD_PATH}mkdir${ENTERPRISE_PATH}#编译文件mkdir${CONFIGURATION_BUILD_PATH_ENTERPRISE}#打包输出的文件mkdir${EnterprisePrijectOutPath}#copymkdir${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"参数无效...."exit1fifi
注意:在写脚本的时候,要注意=号的前后不要有空格,我写OC代码风格都是喜欢 =号 前后空格,这样间距美观。但是脚本里如果有空格会造成命令无效。
自动化打包方案2
...未完待续
谈钱伤感情,不要花钱打赏,如果觉得文章对您真的有帮助,请评论一句就好,这样我才知道有您的支持。谢谢
赞赏支持
日记本
© 著作权归作者所有
举报文章
关注树下敲代码的超人
写了 79685 字,被 283 人关注,获得了 653 个喜欢
不论成败,坚信自己。 风里雨里 成都 欢迎大家~
喜欢
62
更多分享
22条评论 只看作者
按时间倒序按时间正序
king锋
7楼 · 2019.01.16 14:27
基本的套路会了,有个使用scheme打包的问题。项目目前配置了多个scheme进行区分如"dev环境 ,test环境 ,release环境",打包的时候使用"-scheme xxxx" 命令 但是打出的包 全部是release环境的 请各位大佬不吝赐教!
赞 回复
king锋:
补充下 比如当前的scheme是"xxxx_dev",打包命令行指定的是"-scheme xxxx_dev" 是与项目配置的scheme一一对应的
2019.01.16 14:29 回复
添加新评论
谭瞎
6楼 · 2018.12.05 21:37
真好
赞 回复
小米咸鱼
5楼 · 2018.12.03 13:50
ld: library not found for -lAFNetworking
clang: error: linker command failed with exit code 1 (use -v to see invocation)
** ARCHIVE FAILED **
这个怎么解决呀?
赞 回复
树下敲代码的超人:
@小米咸鱼 你看看项目AFNetworking有没有问题。路径等等,具体情况你要自己查。这个不是脚本的问题哈
2018.12.03 16:33 回复
小米咸鱼:
@树下敲代码的超人 Xcode运行,打包都正常
2018.12.03 16:35 回复
emp_heng:
@小米咸鱼 最后你是怎么解决了的呢,遇到同样的问题,排查中
2019.02.13 17:36 回复
添加新评论
我的水杯快到了
4楼 · 2018.11.15 11:40
请问ExportOptions.plist文件怎么创建啊?需要创建AdHOC和App Store两个吗?把这创建的plist文件放在哪个位置呢?
赞 回复
lxiaokai
3楼 · 2018.11.14 11:48
方案2呢(手动滑稽)
赞 回复
树下敲代码的超人:
@lxiaokai 很久没研究自动化打包了。目前想到的其他方案跟方案1是一样的,都是通过脚本操作,只是脚本内容不一样。所以也就没加上去。等想到了一种不一样的方案再加上去。
2018.11.14 13:48 回复
lxiaokai:
@树下敲代码的超人 xcodebuild -exportArchive -archivePath ./myArchivePath.xcarchive -exportOptionsPlist ./ExportOptions.plist -exportPath ./out
2018-11-14 18:44:16.452 xcodebuild[60949:3979019] [MT] IDEDistribution: -[IDEDistributionLogging _createLoggingBundleAtPath:]: Created bundle at path '/var/folders/r8/g1wdb7h16s11rs_vhczw6fs80000gp/T/gfss_2018-11-14_18-44-16.451.xcdistributionlogs'.
error: exportArchive: The data couldn’t be read because it isn’t in the correct format.
Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value., NSFilePath=/var/folders/r8/g1wdb7h16s11rs_vhczw6fs80000gp/T/ipatool-json-filepath-H6ZbZD}
** EXPORT FAILED **
遇到过吗?上网说关闭bitcode也不行,但是同样的脚本,给我同事使用就可以打包出来
2018.11.14 18:49 回复
我的水杯快到了:
@lxiaokai Couldn't load -exportOptionsPlist: The data couldn’t be read because it isn’t in the correct format.我遇见的是报这个错,不知道怎么创建ExportOptions.plist文件,求大佬帮助
2018.11.15 11:50 回复
添加新评论 还有9条评论, 展开查看
路过你的全部
2楼 · 2018.04.28 14:08
总结的很好,楼主有时间可以了解下Jenkins自动打包,他可以帮我们做很多事,没这么麻烦,最近研究了下,XCODE新版本不允许jenkins读钥匙圈了,就换成了你上面的那两句终端命令,有点类似!
赞 回复