一、说明
最近,给小伙伴们做了一个,有关 xcodebuild 自动打包的技术分享,在整理脚本的过程中,遇到了一些问题,并把问题做了一下整理,希望给遇到相同问题的小伙伴做一个参考
二、完整的shell脚本
1.xcodebuild 生成IPA 包,并上传到蒲公英、fir.im、AppStore 的shell脚本代码
#!/bin/sh
# WallPaperScript.sh
#计时
SECONDS=0
#取当前时间字符串添加到文件结尾
now=$(date +"%Y%m%d-%H:%M")
# 获取 setting.plist 文件路径
setting_path=./setting.plist
# 项目名称
project_name=$(/usr/libexec/PlistBuddy -c "print project_name" ${setting_path})
# 项目路径
project_path=$(/usr/libexec/PlistBuddy -c "print project_path" ${setting_path})
# workspace/xcodeproj 路径(根据项目是否使用cocoapod,确定打包的方式)
if [ -d "./${project_name}.xcworkspace" ];then # 项目中存在workspace
workspace_path="${project_path}/${project_name}.xcworkspace"
else # 项目中不存在 workspace
workspace_path="${project_path}/${project_name}.xcodeproj"
fi
# scheme名称
scheme_name=$(/usr/libexec/PlistBuddy -c "print scheme_name" ${setting_path})
# 项目版本
project_version=$(/usr/libexec/PlistBuddy -c "print project_version" ${setting_path})
# 开发者账号
dev_account=$(/usr/libexec/PlistBuddy -c "print dev_account" ${setting_path})
# 开发者密码
dev_password=$(/usr/libexec/PlistBuddy -c "print dev_password" ${setting_path})
# 配置打包方式:Release/ad-hoc/Debug
configuration=$(/usr/libexec/PlistBuddy -c "print configuration" ${setting_path})
# 发布地址:蒲公英->PGY,苹果->APPStore, fir.im->FI
upload_address=$(/usr/libexec/PlistBuddy -c "print upload_address" ${setting_path})
# ipa包名称:项目名+版本号+打包类型
ipa_name=$(/usr/libexec/PlistBuddy -c "print ipa_name" ${setting_path})
# ipa包路径
ipa_path2=$(/usr/libexec/PlistBuddy -c "print ipa_path" ${setting_path})/${now}
ipa_path="${ipa_path2}-V${project_version}-${upload_address}"
# 打包配置plist文件路径 (初始化)
plist_path=$(/usr/libexec/PlistBuddy -c "print plist_path" ${setting_path})
# 编译build路径
archive_path="${ipa_path}/${project_name}.xcarchive"
# 上传到蒲公英设置
user_key=$(/usr/libexec/PlistBuddy -c "print user_key" ${setting_path})
api_key=$(/usr/libexec/PlistBuddy -c "print api_key" ${setting_path})
password=$(/usr/libexec/PlistBuddy -c "print password" ${setting_path})
# 上传fir.im 设置
fir_token=$(/usr/libexec/PlistBuddy -c "print fir_token" ${setting_path})
#打包方式配置
if [ ${upload_address} == "APPStore" ];then # 发布到 AppStore 配置 Release
configuration="Release"
plist_path=${project_path}/exportAppstore.plist
elif [ ${upload_address} == "PGY" ] ||[ ${upload_address} == "FI" ];then # 发布到第三方平台可 配置 Release、Debug
if [ ${configuration} == "Release" ];then
plist_path=${project_path}/exportAdHoc.plist
else
plist_path=${project_path}/exportDevelopment.plist
fi
else # 只打包,不发布到任何平台
if [ ${configuration} == "Release" ];then
plist_path=${project_path}/exportAppstore.plist
else
plist_path=${project_path}/exportDevelopment.plist
fi
fi
echo '=============正在清理工程============='
xcodebuild clean -configuration ${configuration} -quiet || exit
echo '清理完成-->>>--正在编译工程:'${configuration}
# 通过workspace方式打包
if [ -d "./${project_name}.xcworkspace" ];then # 项目中存在workspace
xcodebuild archive -workspace ${workspace_path} -scheme ${scheme_name} \
-configuration ${configuration} \
-archivePath ${archive_path} -quiet || exit
else #通过xcodeproj 方式打包
xcodebuild archive -project ${workspace_path} -scheme ${scheme_name} \
-configuration ${configuration} \
-archivePath ${archive_path} -quiet || exit
fi
# 检查是否构建成功(build)
if [ -d "$archive_path" ] ; then
echo '=============项目构建成功============='
else
echo '=============项目构建失败============='
exit 1
fi
echo '编译完成-->>>--开始ipa打包'
xcodebuild -exportArchive -archivePath ${archive_path} \
-configuration ${configuration} \
-exportPath ${ipa_path} \
-exportOptionsPlist ${plist_path} \
-quiet || exit
if [ -e ${ipa_path}/${ipa_name}.ipa ]; then
echo '=============ipa包导出成功============'
open $ipa_path
else
echo '=============ipa包导出失败============'
fi
echo '打包ipa完成-->>>--开始发布ipa包'
if [ ${upload_address} == "APPStore" ];then # 发布到APPStore
echo '发布ipa包到 =============APPStore============='
altoolPath="/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool"
"$altoolPath" --validate-app -f ${ipa_path}/${ipa_name}.ipa -u ${dev_account} -p ${dev_password} -t ios --output-format xml
"$altoolPath" --upload-app -f ${ipa_path}/${ipa_name}.ipa -u ${dev_account} -p ${dev_password} -t ios --output-format xml
if [ $? = 0 ];then
echo "=============提交AppStore成功 ============="
else
echo "=============提交AppStore失败 ============="
fi
elif [ ${upload_address} == "PGY" ];then # 发布到蒲公英平台
echo '发布ipa包到 =============蒲公英平台============='
curl -F "file=@${ipa_path}/${ipa_name}.ipa" -F "uKey=${user_key}" -F "_api_key=${api_key}" -F "password=${password}" https://www.pgyer.com/apiv1/app/upload
if [ $? = 0 ];then
echo "=============提交蒲公英成功 ============="
else
echo "=============提交蒲公英失败 ============="
fi
elif [ ${upload_address} == "FI" ];then # 发布到fir.im 平台
echo '发布ipa包到 =============fir.im平台============'
# 需要先在本地安装 fir 插件,安装fir插件命令: gem install fir-cli
fir login -T ${fir_token} # fir.im token
fir publish ${ipa_path}/${ipa_name}.ipa
if [ $? = 0 ];then
echo "=============提交fir.im成功 ============="
else
echo "=============提交fir.im失败 ============="
fi
else # 未配置发布地址
echo "=============未发布 ipa包(打包方式:$configuration) 到任何平台============="
fi
# 输出总用时
echo "执行耗时: ${SECONDS}秒"
exit 0
2.需要的plist 配置文件信息
(1)下面是setting.plist 配置文件信息
project_name:项目的名字
project_path:项目路径
project_version:项目的版本号
scheme_name:scheme
ipa_name:要生成的IPA的名字
ipa_path:生成IPA 文件路径
plist_path:配置文件信息路径
configuration:打包方式(这里只配置了 Release、Debug,把IPA包上传到AppStore配置为Release,上传到蒲公英、fir.im配置为 Release 或者 Debug 都可以)
upload_address:上传地址(AppStore/PGY(蒲公英)/FI(fir.im)/None(也可以不填写),只生成IPA包,不发布到任何平台)
user_key:蒲公英 user_key
api_key: 蒲公英 api_key
password:蒲公英下载安装包时需要的密码(选填或者传空字符串)
fir_token:fir.im token (先把fir插件安装到本地,才可以使用此命令)
dev_account:苹果开发者账号
dev_password:苹果开发者密码
(2)下面是exportAppStore.plist 配置文件信息
com.dating.luowallpaper(bundleId):对应的发布 配置概要文件
method:app-store
uploadBitcode:配置是否上传 bitcode ,xcode配置默认 YES
uploadSymbols:是否上传 dSYMs
teamID:发布证书 的 teamID , 即 App ID Prefix
(3) 下面是exportAdHoc.plist 配置文件信息
com.dating.luowallpaper(bundleId):对应的 Ad-Hoc 配置概要文件
(4) 下面是exportDevelopment.plist 配置文件信息
com.dating.luowallpaper(bundleId):对应的 development 配置概要文件
teamID: 发布证书 的 teamID ,即 App ID Prefix(注意不要写成,开发证书对应的teamID)
三、执行脚本文件之前需要注意的事项
1、shell脚本文件、setting.plist、exportAppStore.plist、exportAdHoc.plist 、exportDevelopment.plist 这五个文件要放到项目根目录下
2、选择手动配置 provisioning profiles 文件,根据打包的方式不同,在xcode中配置不同的 配置概要文件(AppStore / AdHoc /development ),不要选择自动配置,否则会打包失败 ,请看下图
3、为了保证我们每次打的IPA包都是唯一的,需要对Xcode进行设置,保证我们每次archive的时候,build 自动加 1 ,具体的设置可以参考下面的 网址:https://www.cnblogs.com/wengzilin/p/4648177.html?utm_source=tuicool&utm_medium=referral
4.为了保证 fir 命令正常执行,先在本地安装 fir 插件,安装fir插件命令: gem install fir-cli
四、执行脚本
打开终端,cd 到项目的根目录,然后执行 ./xxx.sh 脚本,如果配置信息没问题,就会自动在配置好的 setting.plist 的ipa_path 路径下生成 一个文件夹,里面包含5个文件(DistributionSummary.plist、ExportOptions.plist、Packaging.log、xxx.ipa、xxx.xcarchive),执行完脚本会自动打开文件夹,根据配置好的信息,把IPA包发布到对应的平台
五、总结
这是自己最近给小伙伴做的一次基于xcodebuild自动打包技术的分享,希望各位小伙伴可以用的到,如果有什么疑问欢迎大家一起讨论,共同学习进步~
追加
最近用xcode 9.4 版本测试了一下自动打包时的证书配置,在TARGETS配置选项选择 Automatically manage signing 时,也可以正常打 debug 和 release 的 IPA安装包。前提是要 把 Development 和 Distribution 对应的 Provisioning Profiles 文件安装到本地 ,即使选择自动配置证书,但是使用脚本打包的时候依然需要 Provisioning Profiles 文件,如果本地没有Provisioning Profiles 文件,在导出 IPA 包的时候会提示,缺少对应的 rovisioning Profiles 文件的错误,最终,会导致导出 IPA 包失败。
demo