iOS批量打包(shell)

iOS批量打包(shell)_第1张图片

写在前面

相信很多做APP开发的朋友都经历过这种情况:开发完成进入测试阶段会有很多各种的ipa包需要build,如果公司有个好的体贴的QA的话,那可以把打包的工作交给他,如果没有就只能开发来做了!什么开发版的正式服、测试服ipa,什么企业版的正式服、测试服ipa,什么...... 如果用XCode自带Archive的话我们需要点点点,期间还得等等等,然后还得上传各种ftp,蒲公英,etc. 所以有个脚本来帮助一次性打包并上传是极好的。

XCode打包

首先

在开发者网站注册APPID并且生成称对应的证书,描述文件,并且将证书和描述文件下载下来,证书导入钥匙串,描述文件导入XCode。至于怎么生成证书和描述文件就不啰嗦啦。

然后

在xcodeproj

  • ->General 配置好设置的APPID,选择对应的Team(如果不勾选xcode自动管理签名可不用填)
  • ->BuildSettings->Signing 配置好对应的Debug、Release证书
  • ->Scheme->Edit Scheme 选择对应的的Debug或者Release
  • ->调整好其他一些配置属性,比如:版本号,一些自定义宏等

最后

  • ->Product-Archive wait。。。。。。
  • ->Archive完成一般会有选择是Upload App Store还是选择Export,通常来说还是Export个ipa到本地
  • ->Export 选择是生成何种类型的ipa,有四个选项根据需要选择,如果需要多种选择可以直接重复Export,不用重新Archive
  • ->选择ipa类型,选择对应的Team,Next,Next,wait。。。选择存储位置,Export

Shell脚本

像这样一步一步配置,一步一步点击,还得wait,还得rebuild,again,again。。。像这种频繁手动修改配置是很不安全滴,作为一个开发者,时间很宝贵的好伐,这种重复的劳动完全可以省略嘛。

是时候说到正题了

首先

分析一下脚本需要做的工作有哪些:

  • 修改General配置
  • 修改自定义的一些配置
  • 修改BuildSetting配置
  • 修改Scheme-Archive-Build Configuration
  • 执行Archive
  • 选择Export类型 设置存储位置

然后

针对各种工作做出应对

  • 利用PlistBuddy
    General配置和一些自定义配置都可以放置在Plist文件里面进行,这样看起来清晰明了减少出错。在修改这些配置的时候我们可以利用Mac自带的PlistBuddy。
    针对不同的配置我们可以创建不同的配置文件,然后遍历这些文件,一个配置文件打次包就好了
  • xcodebuild
    xcodebuild命令是本脚本的主要部分,通过修改其参数可以对BuildSettings以及Scheme、Target等进行配置

干就完了

  • 熟悉了解PlistBuddy用法
    在终端中输入/usr/libexec/PlistBuddy --help查看,比较简单,细心可看懂。
  • 创建文件结构


    iOS批量打包(shell)_第2张图片

    其中build.sh是执行脚本,module文件夹很显然里面放置的是不同的配置啦,各个配置下的config.plist是要修改的配置,里面包含各个要修改的属性;exportPlist.plist是必须要有的配置文件,可以为空,但必须有;xxxx.mobileprovision是各个配置对应的描述文件,如果使用xcode里面配置的可以没有。

  • 开始Coding
  1. 创建一些全局方便使用,比如PlistBuddy位置,xcodebuild位置等
plistBuddy="/usr/libexec/PlistBuddy"           #PlistBuddy位置
xcodebuild="/usr/bin/xcodebuild"               #xcodebuild位置
security="/usr/bin/security"                   #security 用来访问钥匙串
codesign="/usr/bin/codesign"                   #签名工具
shellPath=`pwd`                                #当前路径
projectPath="$shellPath/.."                    #工程路径
pbxprojFile=''                                 #xcodeproj文件路径
projTypeIsWorkSpace=true                       #工程文件类型 默认.xcworkspace
buildTime=$(date +%Y-%m-%d-%H-%M)              #时间
  1. 既然我们要对xcode项目进行打包,那么我们首先要得有.xcodeproj文件吧,工程文件都没有还打个毛线包啊!
if [[ "$xcodeProject" == '' ]]; then
    xcodeProject=`find "$projectPath" -maxdepth 1  -type d -name "*.xcodeproj"`
fi
projectExtension=`basename "$xcodeProject" | cut -d'.' -f2`
if [[ "$projectExtension" != "xcodeproj" ]]; then
    echo "Xcode project 应该带有.xcodeproj文件扩展,.${projectExtension}不是一个Xcode project扩展!"
    exit 1
else
    pbxprojFile="$xcodeProject/project.pbxproj"
    if [[ ! -f "$pbxprojFile" ]]; then
        echo "项目文件:\"$pbxprojFile\" 不存在"
        exit 1;
    fi
    echo "发现pbxproj:$pbxprojFile"
fi

  1. 由于现在许多工程都是通过workSpace来进行管理的,所以需要先检查判断是否是workspace工程
# 这里通过在.xcodeproj文件所在文件夹下是否有以.xcworkspace后缀的文件来判断
xcworkspace=`find "$xcodeProject/.." -maxdepth 1  -type d -name "*.xcworkspace"`
if [[ -d "$xcworkspace" ]]; then
    projTypeIsWorkSpace=true
    echo "发现xcworkspace:$xcworkspace"
else
    projTypeIsWorkSpace=false;
fi
  1. update到最新代码(手动更新可以删除此段)
cd ..
echo ${pwd}
svn update
svnVersion=`svnversion |sed 's/^.*://' |sed 's/[A-Z]*$//'`
echo $svnVersion

先cd到工程所在路径,由于我们是svn管理代码的所以执行svn update 可能需要输入svn密码,然后获取到svnVersion是用来标记代码版本。

  1. 是时候表演真正的技术了
    此处是脚本的主要部分,主要有一下几个部分:
    遍历module文件夹获取各个配置里面的config文件;
    根据配置文件利用PlistBuddy修改配置;
    clean工程;
    Build工程;
    export
for y in $shellPath/module/*;
do
    #==============读取config文件====================#
    configFile=$y/config.plist
    if [[ "$configFile" == '' ]]; then
        echo "未找到config.plist文件!"
        exit 1
    fi
    echo "找到config.plist文件"
    configurations=`"$plistBuddy" -c "print :" "$configFile"`
    echo "$configurations"
    appVersion=`"$plistBuddy" -c "print :appVersion:" "$configFile"`

上面是遍历module和读取config.plist以及其中各个key的值。

    projectName=$(basename "$xcodeProject" .xcodeproj)
    infoPlistPath=$projectPath/$projectName/Info.plist
    echo "infoPlistPath = $infoPlistPath"
    #修改Info.plist内容
    if [[ -f "$infoPlistPath" ]]; then
        if [[ "$appVersion" != '' ]]; then
            $plistBuddy -c "Set :CFBundleShortVersionString $appVersion" "$infoPlistPath"
        fi
    fi

上面是根据config.plist来修改Info.plist的例子

# ===========   keychain 授权 =====================#
    #允许访问证书
    $security unlock-keychain -p $loginPwd "$HOME/Library/Keychains/login.keychain" 2>/tmp/log.txt
    if [[ $? -ne 0 ]]; then
        echo "security unlock-keychain 失败!请检查配置密码是否正确"
        exit 1
    fi
    $security unlock-keychain -p $loginPwd "$HOME/Library/Keychains/login.keychain-db" 2>/tmp/log.txt
    if [[ $? -ne 0 ]]; then
        echo "security unlock-keychain 失败!请检查配置密码是否正确"
    exit 1
    fi
# =================================================#

上面是用来获取钥匙串的授权的,其中loginPwd是在config里面配置读取的。不进行授权有可能会影响证书的访问,导致打包失败。

#==============检查证书和描述文件====================#
    profileUUID=''
    if [[ "$profileName" != "" ]]; then
        profilePath=$y/$profileName.mobileprovision
        if [[ ! -f "$profilePath" ]]; then
            echo "描述文件 $profilePath 不存在!"
            exit 1
        fi
        profileUUID=`$plistBuddy -c 'Print :UUID' /dev/stdin <<< $($security cms -D -i "$profilePath" 2>/tmp/log.txt)`
        echo "描述文件UUID  $profileUUID"
    fi
# =================================================#

对于自定义证书和描述文件的如果查找不到就会构建失败。

# ===============检查构建ipa存放路径=================#
    savePath=$projectPath/build/$buildTime
    if [[ ! -d "$projectPath/build" ]]; then
        mkdir $projectPath/build
    fi
    if [[ ! -d "$savePath" ]]; then
        mkdir $savePath
    fi
# =================================================#

马上就要出货了,出货之前一定要准备好放货的地方吧。我是根据时间生成一个文件夹,然后里面的ipa根据不同配置命名不同。

exportPlistPath=$y/exportPlist.plist
    if [[ "$exportPlistPath" == '' ]]; then
        echo "未找到exportPlist.plist文件!"
        exit 1
    fi

再检查下必须的exportPlist.plist文件在不在。

if [[ $projTypeIsWorkSpace != true ]]; then

        echo '*** 正在 清理工程 ***'
        xcodebuild clean -project "${xcodeProject}" -scheme "${schemeName}" -configuration "${buildConfiguration}" -sdk $sdk
        echo '*** 清理完成 ***'

        echo '*** 正在 archive ***'
        cmd="xcodebuild archive -archivePath ${savePath}/${schemeName}-${buildConfiguration}.xcarchive -project "${xcodeProject}" -scheme "${schemeName}" -configuration  "${buildConfiguration}" -sdk $sdk"
        if [[ $profileUUID != '' ]];then
            cmd="$cmd" PROVISIONING_PROFILE="${profileUUID}"
        fi
        if [[ $certificateName != '' ]];then
            cmd="$cmd" PROVISIONING_PROFILE="${profileUUID}" CODE_SIGN_IDENTITY="${certificateName}"
        fi
        if [[ $teamID != '' ]];then
        cmd="$cmd" DEVELOPMENT_TEAM="${teamID}"
        fi
        $cmd
        echo '*** archive done***'

        echo '*** 正在 exportArchive ***'
        xcodebuild -exportArchive -archivePath ${savePath}/${schemeName}-${buildConfiguration}.xcarchive \
        -configuration "${buildConfiguration}" \
        -exportPath ${savePath} \
        -exportOptionsPlist ${exportPlistPath} \
        -quiet || exit
        echo '*** exportArchive done***'

上面是利用xcodebuild对xcodeproj打包的主要部分,包括clean,修改Archive参数,exportArchive。
如果是workspace工程只需要修改project参数为workspace即可,如下例

        xcodebuild clean -workspace "${xcworkspace}" -scheme "${schemeName}" -configuration "${buildConfiguration}" -sdk $sdk

关于更多xcodebuild的参数配置可以通过在终端中输入xcodebuild -help查看。

if [[ $ftp != '' ]];then
        echo "***开始上传ipa到ftp服务器***"
        ftp -niv<<-!
        open 192.168.255.22 8888
        user xxxx xxxxx
        binary
        hash
        cd ${ftp}
        lcd ${savePath}
        prompt
        put ${schemeName}${buildConfiguration}.ipa
        close
        bye
!
        echo "***完成上传ipa到ftp服务器***"
        fi

最后一步上传ftp了,由于我们使用ftp提供测试下载安装。其他上传蒲公英或者App Store的可以自己添加。

要结束了

脚本比较长,格式有点乱,主要是给大家提供个思想,大家可以参考下写出自己的更完美更漂亮的。
如果有了更好的请一定要@我去学啊。[笑脸]

  • 附:
    package脚本下载地址

你可能感兴趣的:(iOS批量打包(shell))