zoukankan      html  css  js  c++  java
  • iOS 应用打包命令一览

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

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

    各种命令的简介

    使用命令打包iOS 应用一般会用到 xcodebulidxcrun
    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文件的内容,可以使用PlistBuddyPlistBuddy是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 <xcarchivepath> -exportPath <destinationpath> -exportOptionsPlist <plistpath>
    
    ······
    
    -exportOptionsPlist PATH            specifies a path to a plist file that configures archive exporting

    如何获取工程的CODE_SIGN_IDENTITYPROVISIONING_PROFILE

    右键 xxx.xcodeproj 显示包内容 然后打开project.pbxproj文件
    command F 搜索 CODE_SIGN_IDENTITYPROVISIONING_PROFILE

    PROVISIONING_PROFILE 使用uuid或者名称都可以。
    因为我这里打包用的Release模式所以,我在查找CODE_SIGN_IDENTITYPROVISIONING_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/sh
    
    echo "~~~~~~~~~~~~~~~~开始执行脚本~~~~~~~~~~~~~~~~"
    # 开始时间
    beginTime=`date +%s`
    DATE=`date '+%Y-%m-%d-%T'`
    #需要编译的 targetName
    TARGET_NAME="xxxx"
    #编译模式 工程默认有 Debug Release 
    CONFIGURATION_TARGET=Release
    #编译路径
    BUILDPATH=~/Desktop/${TARGET_NAME}_${DATE}
    #archivePath
    ARCHIVEPATH=${BUILDPATH}/${TARGET_NAME}.xcarchive
    #输出的ipa目录
    IPAPATH=${BUILDPATH}
    
    #证书名
    CODE_SIGN_IDENTITY="xxxxx"
    #描述文件
    PROVISIONING_PROFILE_NAME="xxxx"
    
    #苹果账号
    AppleID="xxxx"
    AppleIDPWD="xxxx"
    
    #导出ipa 所需plist
    ADHOCExportOptionsPlist=./ADHOCExportOptionsPlist.plist
    AppStoreExportOptionsPlist=./AppStoreExportOptionsPlist.plist
    
    ExportOptionsPlist=${ADHOCExportOptionsPlist}
    
    # 是否上传蒲公英
    UPLOADPGYER=false
    # 是否上传AppStore
    UPLOADAPPSTore=false
    
    echo "~~~~~~~~~~~~~~~~选择打包方式~~~~~~~~~~~~~~~~"
    echo "        1 ad-hoc (默认)"
    echo "        2 AppStore "
    
    # 读取用户输入并存到变量里
    read parameter
    sleep 0.5
    method="$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
        fi
    else
        ExportOptionsPlist=${ADHOCExportOptionsPlist}
    fi
    
    if [ $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
        fi
    fi
    
    
    echo "~~~~~~~~~~~~~~~~开始编译~~~~~~~~~~~~~~~~~~~"
    echo "~~~~~~~~~~~~~~~~开始清理~~~~~~~~~~~~~~~~~~~"
    # 清理 避免出现一些莫名的错误
    xcodebuild clean -workspace ${TARGET_NAME}.xcworkspace 
    -configuration 
    ${CONFIGURATION} -alltargets
    
    echo "~~~~~~~~~~~~~~~~开始构建~~~~~~~~~~~~~~~~~~~"
    #开始构建
    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" ]
    then
    echo "构建成功......"
    else
    echo "构建失败......"
    rm -rf $BUILDPATH
    exit 1
    fi
    endTime=`date +%s`
    ArchiveTime="构建时间$[ endTime - beginTime ]秒"
    
    
    echo "~~~~~~~~~~~~~~~~导出ipa~~~~~~~~~~~~~~~~~~~"
    
    beginTime=`date +%s`
    
    xcodebuild -exportArchive 
    -archivePath ${ARCHIVEPATH} 
    -exportOptionsPlist ${ExportOptionsPlist} 
    -exportPath ${IPAPATH}
    
    echo "~~~~~~~~~~~~~~~~检查是否成功导出ipa~~~~~~~~~~~~~~~~~~~"
    IPAPATH=${IPAPATH}/${TARGET_NAME}.ipa
    if [ -f "$IPAPATH" ]
    then
    echo "导出ipa成功......"
    else
    echo "导出ipa失败......"
    # 结束时间
    endTime=`date +%s`
    echo "$ArchiveTime"
    echo "导出ipa时间$[ endTime - beginTime ]秒"
    exit 1
    fi
    
    endTime=`date +%s`
    ExportTime="导出ipa时间$[ endTime - beginTime ]秒"
    
    # 上传AppStore
    if [ $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失败~~~~~~~~~~~~~~~~~~~"
            fi
    else
        # 上传蒲公英    
        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
        fi
    fi
    
    echo "~~~~~~~~~~~~~~~~配置信息~~~~~~~~~~~~~~~~~~~"
    echo "开始执行脚本时间: ${DATE}"
    echo "编译模式: ${CONFIGURATION_TARGET}"
    echo "导出ipa配置: ${ExportOptionsPlist}"
    echo "打包文件路径: ${ARCHIVEPATH}"
    echo "导出ipa路径: ${IPAPATH}"
    
    echo "$ArchiveTime"
    echo "$ExportTime"
    exit 1
  • 相关阅读:
    (转)iOS-Runtime知识点整理
    iOS开发--SQLite重要框架FMDB的使用
    iOS开发--数据库管理CoreData的使用
    iOS超全开源框架、项目和学习资料汇总--数据库、缓存处理、图像浏览、摄像照相视频音频篇
    【导航条滚动透明】一个分类搞定
    成熟的程序员应该掌握的4个知识点
    iOS开发之浅谈MVVM的架构设计与团队协作
    Leetcode-One Edit Distance
    Leetcode-Read N Characters Given Read4 II
    Leetcode-Read N Characters Given Read4
  • 原文地址:https://www.cnblogs.com/wanghang/p/6298823.html
Copyright © 2011-2022 走看看