iOS 应用打包命令一览

文章转载自:http://www.jianshu.com/p/5d59966eaecc

文章排版部分根据自己的理解做了一些修改。

各种命令的简介

使用命令打包iOS 应用一般会用到 xcodebulid 和 xcrun。 

xcodebuild主要是用来编译工程。 

xcrun 则是打包出ipa安装包。 

altool 适用于提交到AppStore 的。

想要知道更多关于xcodebuild 命令参数,则可以使用xcodebuild -help 查看; 

想要知道更多关于xcrun 命令参数,则可是用xcrun -help 查看。

另外,官方文档中有对 Workspace、Project、Scheme、Target更详细的讲解,地址是:Xcode Concepts

altool 这个工具实际上是ApplicationLoader,打开Xcode-左上角Xcode-Open Developer Tool-Application Loader,altool的路径是:

/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool

如果使用时,报如下错误:

altool[] *** Error:

Exception while launching iTunesTransporter: Transporter not found at path: /usr/local/itms/bin/iTMSTransporter.

You should reinstall the application.

建立软链:ln -s /Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/itms /usr/local/itms

如果想要在脚本中修改或者读取plist文件的内容,可以使用PlistBuddy,PlistBuddy是Mac里一个用于命令行下读写plist文件的工具,在/usr/libexec/目录下。

下面是一段读取与修改 plist 中版本号的shell脚本:

#!/bin/sh# PlistBuddy程序的绝对路径PlistBuddyPath=/usr/libexec/PlistBuddy# 工程中的plist 文件路径appInfoPlistPath="/Volumes/SourceCode/showstart_ios/ShowStart_3.0/Info.plist"# 读取bundleShortVersion 版本号bundleShortVersion=$($PlistBuddyPath -c "print CFBundleShortVersionString" ${appInfoPlistPath})# 读取bundleVersion 版本号bundleVersion=$($PlistBuddyPath -c "print CFBundleVersion" ${appInfoPlistPath})# 在终端中打印版本号echo "$bundleShortVersion"echo "$bundleVersion"buildNumber="3.69"# 重新设置 plist文件中的bundleVersion版本号bundleVersion=$($PlistBuddyPath -c "Set :CFBundleVersion$buildNumber" ${appInfoPlistPath})# 再次读取bundleVersion 版本号bundleVersion=$($PlistBuddyPath -c "print CFBundleVersion" ${appInfoPlistPath})# 打印版本号echo "$bundleVersion"

Xcode 8之前的打包命令

在Xcode 8之前打包,都是使用xcodebuild+xcrun 来打包ipa包。比如:

xcodebuild -workspace XXX -scheme XXX -configuration Release

xcrun -sdk iphoneos PackageApplication -v "/XXX/XXX.app" -o "/XXX/XXX"

需要注意的是,如果我们同时安装了多个Xcode,比如我这里同时安装的Xcode 7 和 Xcode 8,使用 xcodeuild+xcrun 来打包ipa包 时,会出现如下错误:

2016-11-07 13:43:04.724 xcodebuild[22235:709735] CoreSimulator is attempting to unload a stale CoreSimulatorService job. Detected Xcode.app relocation or CoreSimulatorService version change. Framework path (/Applications/Xcode.app/Contents/Developer/Library/PrivateFrameworks/CoreSimulator.framework) and version (209.19) does not match existing job path (/Applications/Xcode_8.app/Contents/Developer/Library/PrivateFrameworks/CoreSimulator.framework/Versions/A/XPCServices/com.apple.CoreSimulator.CoreSimulatorService.xpc/Contents/MacOS/com.apple.CoreSimulator.CoreSimulatorService) and version (303.8).

2016-11-07 13:43:04.982 xcodebuild[22235:709735] Failed to locate a valid instance of CoreSimulatorService in the bootstrap. Adding it now.

2016-11-07 13:43:04.996 xcodebuild[22235:709735] *** Assertion failure in -[SimServiceContext reloadServiceIfMovedOrAbortIfWeAreInvalid], /BuildRoot/Library/Caches/com.apple.xbs/Sources/CoreSimulator/CoreSimulator-209.19/CoreSimulator/SimServiceContext.m:536

** INTERNAL ERROR: Uncaught exception **

Uncaught Exception: The loaded com.apple.CoreSimulator.CoreSimulatorService job does not match our expectations: pathOfLoadedJob: /Applications/Xcode_8.app/Contents/Developer/Library/PrivateFrameworks/CoreSimulator.framework/Versions/A/XPCServices/com.apple.CoreSimulator.CoreSimulatorService.xpc/Contents/MacOS/com.apple.CoreSimulator.CoreSimulatorService, our frameworkPath: /Applications/Xcode.app/Contents/Developer/Library/PrivateFrameworks/CoreSimulator.framework

我在stackoverflow上找到了解决方案: 

在终端中执行如下命令:

launchctl remove com.apple.CoreSimulator.CoreSimulatorService || true

stackoverflow 上答案地址: 

CoreSimulator is attempting to unload a stale CoreSimulatorService job 

Random build failures on Teamcity 

关于 xcodebuild+xcrun 的更多 参数 和介绍,在上面简介中已经列出,这里就不再赘述了。

Xcode 8 以及 之后的打包命令

安装Xcode 8之后,使用xcodebuild+xcrun 打包时, 会提示 让我们使用 -exportArchive 命令来构建。

关于 -exportArchive,在 xcodebuild -help 中有如下提示:

xcodebuild -exportArchive -archivePath -exportPath -exportOptionsPlist ······-exportOptionsPlist PATH specifies a path to a plist file that configures archive exporting

如何获取工程的CODE_SIGN_IDENTITY和PROVISIONING_PROFILE

右键 xxx.xcodeproj 显示包内容 然后打开project.pbxproj文件 

command F 搜索 CODE_SIGN_IDENTITY 和  PROVISIONING_PROFILE

PROVISIONING_PROFILE 使用uuid或者名称都可以。 

因为我这里打包用的Release模式所以,我在查找CODE_SIGN_IDENTITY和PROVISIONING_PROFILE都是找的Release模式配置。 

使用atool时 最终输出的xml 中包含 success-message表示成功,如果包含product-errors表示失败。

我们可以将要执行的命令,写进一个shell脚本文件中,这样更方便执行。 

给一个文件添加执行权限的命令是:chmod +x xcodebuild.sh


还有更多其他的文件权限,如 读、写权限。可以看Linux 命令中的 第10条 chmod 命令

进入脚本所在的目录,执行脚本,有两种方式

// 第一种sh xxxx.sh//               第二种./xxxx.sh


脚本中执行if 条件判断的格式:

if []

then

.......//执行的命令

else

.......//执行的命令

fi


完整的脚本如下:

#!/bin/shecho "~~~~~~~~~~~~~~~~开始执行脚本~~~~~~~~~~~~~~~~"# 开始时间beginTime=`date +%s`

DATE=`date '+%Y-%m-%d-%T'`#需要编译的 targetNameTARGET_NAME="xxxx"#编译模式 工程默认有 Debug Release CONFIGURATION_TARGET=Release#编译路径BUILDPATH=~/Desktop/${TARGET_NAME}_${DATE}#archivePathARCHIVEPATH=${BUILDPATH}/${TARGET_NAME}.xcarchive#输出的ipa目录IPAPATH=${BUILDPATH}#证书名CODE_SIGN_IDENTITY="xxxxx"#描述文件PROVISIONING_PROFILE_NAME="xxxx"#苹果账号AppleID="xxxx"AppleIDPWD="xxxx"#导出ipa 所需plistADHOCExportOptionsPlist=./ADHOCExportOptionsPlist.plist

AppStoreExportOptionsPlist=./AppStoreExportOptionsPlist.plist

ExportOptionsPlist=${ADHOCExportOptionsPlist}# 是否上传蒲公英UPLOADPGYER=false# 是否上传AppStoreUPLOADAPPSTore=falseecho "~~~~~~~~~~~~~~~~选择打包方式~~~~~~~~~~~~~~~~"echo "        1 ad-hoc (默认)"echo "        2 AppStore "# 读取用户输入并存到变量里read parameter

sleep 0.5method="$parameter"# 判读用户是否有输入 if [ -n "$method" ]then    if [ "$method" = "1" ]

    then

    PROVISIONING_PROFILE_NAME="xxxx"    ExportOptionsPlist=${ADHOCExportOptionsPlist}    elif [ "$method" = "2" ]

    then    UPLOADAPPSTore=true    PROVISIONING_PROFILE_NAME="xxxx"    ExportOptionsPlist=${AppStoreExportOptionsPlist}    else    echo "参数无效...."    exit 1    fielse    ExportOptionsPlist=${ADHOCExportOptionsPlist}fiif [ $UPLOADAPPSTore = false ]then    echo "~~~~~~~~~~~~~~~~是否上传蒲公英~~~~~~~~~~~~~~~~"    echo "        1 不上传 (默认)"    echo "        2 上传 "    read para

    sleep 0.5    if [ -n "$para" ]

    then        if [ "$para" = "1" ]

        then

        UPLOADPGYER=false        elif [ "$para" = "2" ]

        then        UPLOADPGYER=true        else        echo "参数无效...."        exit 1        fi    else        UPLOADPGYER=false    fifiecho "~~~~~~~~~~~~~~~~开始编译~~~~~~~~~~~~~~~~~~~"echo "~~~~~~~~~~~~~~~~开始清理~~~~~~~~~~~~~~~~~~~"# 清理 避免出现一些莫名的错误xcodebuild clean -workspace ${TARGET_NAME}.xcworkspace \

-configuration \${CONFIGURATION} -alltargetsecho "~~~~~~~~~~~~~~~~开始构建~~~~~~~~~~~~~~~~~~~"#开始构建xcodebuild archive -workspace ${TARGET_NAME}.xcworkspace \

-scheme ${TARGET_NAME} \

-archivePath ${ARCHIVEPATH} \

-configuration ${CONFIGURATION_TARGET} \

CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY}" \

PROVISIONING_PROFILE="${PROVISIONING_PROFILE_NAME}"echo "~~~~~~~~~~~~~~~~检查是否构建成功~~~~~~~~~~~~~~~~~~~"# xcarchive 实际是一个文件夹不是一个文件所以使用 -d 判断if [ -d "$ARCHIVEPATH" ]thenecho "构建成功......"elseecho "构建失败......"rm -rf $BUILDPATHexit 1fiendTime=`date +%s`

ArchiveTime="构建时间$[ endTime - beginTime ]秒"echo "~~~~~~~~~~~~~~~~导出ipa~~~~~~~~~~~~~~~~~~~"beginTime=`date +%s`

xcodebuild -exportArchive \

-archivePath ${ARCHIVEPATH} \

-exportOptionsPlist ${ExportOptionsPlist} \

-exportPath ${IPAPATH}echo "~~~~~~~~~~~~~~~~检查是否成功导出ipa~~~~~~~~~~~~~~~~~~~"IPAPATH=${IPAPATH}/${TARGET_NAME}.ipaif [ -f "$IPAPATH" ]thenecho "导出ipa成功......"elseecho "导出ipa失败......"# 结束时间endTime=`date +%s`echo "$ArchiveTime"echo "导出ipa时间$[ endTime - beginTime ]秒"exit 1fiendTime=`date +%s`

ExportTime="导出ipa时间$[ endTime - beginTime ]秒"# 上传AppStoreif [ $UPLOADAPPSTore = true ]then   

    altoolPath="/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool"    ${altoolPath} --validate-app \

    -f ${IPAPATH} \

    -u ${AppleID} \

    -p ${AppleIDPWD} \

    -t ios --output-format xml

        if [ $? = 0 ]

        then        echo "~~~~~~~~~~~~~~~~验证ipa成功~~~~~~~~~~~~~~~~~~~"            ${altoolPath} --upload-app \

            -f ${IPAPATH} \

            -u ${AppleID} \

            -p ${AppleIDPWD} \

            -t ios --output-format xml

            if [ $? = 0 ]

            then            echo "~~~~~~~~~~~~~~~~提交AppStore成功~~~~~~~~~~~~~~~~~~~"            else            echo "~~~~~~~~~~~~~~~~提交AppStore失败~~~~~~~~~~~~~~~~~~~"            fi        else        echo "~~~~~~~~~~~~~~~~验证ipa失败~~~~~~~~~~~~~~~~~~~"        fielse    # 上传蒲公英        if [ $UPLOADPGYER = true ]

    then        echo "~~~~~~~~~~~~~~~~上传ipa到蒲公英~~~~~~~~~~~~~~~~~~~"        curl -F "file=@$IPAPATH" \

        -F "uKey=xxxxx" \

        -F "_api_key=xxxx" \

        -F "password=xxxxx" \

        -F "isPublishToPublic=xxxx" \

        https://www.pgyer.com/apiv1/app/upload --verbose

        if [ $? = 0 ]

        then        echo "~~~~~~~~~~~~~~~~上传蒲公英成功~~~~~~~~~~~~~~~~~~~"        else        echo "~~~~~~~~~~~~~~~~上传蒲公英失败~~~~~~~~~~~~~~~~~~~"        fi    fifiecho "~~~~~~~~~~~~~~~~配置信息~~~~~~~~~~~~~~~~~~~"echo "开始执行脚本时间:${DATE}"echo "编译模式:${CONFIGURATION_TARGET}"echo "导出ipa配置:${ExportOptionsPlist}"echo "打包文件路径:${ARCHIVEPATH}"echo "导出ipa路径:${IPAPATH}"echo "$ArchiveTime"echo "$ExportTime"exit 1

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容