Shell腳本——Xcode腳本打包

最近有好一段時間沒有整理博客了筑公,也不是因為忙雳窟,就是太懶∠宦牛或者說程序員都自帶懶屬性??封救,表現(xiàn)在對于一些機械性重復性的工作,寧愿一次性多花些精力去封裝捣作、去寫出各種各樣的工具來替自己干活誉结,也不愿意多次重復勞動(就算那是很簡單的工作)。這不券躁,我結合最近的工作惩坑,研究著寫了兩份Shell腳本,一是關于Xcode腳本打包也拜,還有一個是關于crash log解析(這個將在下一篇文章說明)以舒。


Shell打包腳本實現(xiàn)了如下功能

  1. 指定打包項目的Build號,Version版本號——Version號可選擇自增或自定義(在測試階段打包時慢哈,每次手動改變Version號很是麻煩蔓钟,而且不方便管理;而如果能打包時通過腳本參數(shù)控制岸军,so easy~)
  2. 導出xcarchive文件奋刽,通過xcarchive文件得到dSYM文件瓦侮,這是很重要的。查找線上crash時佣谐,缺它不可肚吏!crash log解析請看這里。
  3. 打包生成ipa文件狭魂,這個就是最終需要的渠道包了罚攀。

另外打包腳本可以根據(jù)項目配置,每一次成功打包后雌澄,都會生成對應目錄斋泄,并生成記錄本次打包的log日志文件。


打包腳本

#!/bin/bash

#--------------------------------------------------------------------------------
# 腳本說明:
# 1镐牺、實現(xiàn)功能:
#     1)炫掐、指定打包項目的Build號,Version版本號(Version號可選擇自增或自定義)
#     2)睬涧、導出xcarchive文件
#     3)募胃、打包生成ipa文件
# 2、使用方式:
#     1)畦浓、將ReleaseDir文件夾痹束,放到跟所要打包的項目的根目錄(TestDemo)同級別的目錄下
#     2)、cd至ReleaseDir讶请,運行腳本./Release.sh TestDemo祷嘶,并選擇輸入相關參數(shù),開始打包
#     3)夺溢、完成打包后论巍,生成的目標文件在如下目錄:
#          /ReleaseDir/ArchivePath/TestDemo/1.0.0/2017_03_03_10:37:34
#         (/ReleaseDir/ArchivePath/打包項目名稱/打包版本號/打包時間)
#--------------------------------------------------------------------------------
#
#--------------------------------------------------------------------------------
# 打包project
#        ./Release.sh  <Project directory name> [-s <Name>] [-e] [-d] [-a] [-b <Build number>]
# 打包workspace
#        ./Release.sh  <Project directory name> [-w] [-s <Name>] [-e] [-d] [-b <Build number>] [-v <Version number>]
# 參數(shù)說明:
#     <Project directory name>    第一個參數(shù):所要打包的項目的根目錄文件夾名稱         
#     -w                         workspace打包,不傳默認為project打包
#     -s <Name>                對應workspace下需要編譯的scheme(不傳默認取xcodeproj根目錄文件名)
#     -e                         打包前是否先編譯工程(不傳默認不編譯)
#     -d                         工程的configuration為 Debug 模式风响,不傳默認為Release
#     -a                         打包环壤,Version版本號自動+1(針對多次打測試包時的版本號修改)
#    -b <Build Num>              Build版本號,指定項目Build號
#    -v <Version Num>            Version版本號钞诡,指定項目Version號
#  注意,參數(shù)-a 與 -v 互斥湃崩,只能選擇傳其中一種參數(shù)S怠!
#--------------------------------------------------------------------------------
#
#--------------------------------------------------------------------------------
# ReleaseDir文件目錄說明:
#
# |___TestDemo                                所要打包的項目的根目錄
# |___ReleaseDir                              打包相關資源的根目錄
#    |___Release.sh                           Release.sh打包腳本
#    |___ExportOptions.plist                  -exportOptionsPlist 配置文件
#    |___ArchivePath                          打包文件輸出路徑
#       |___TestDemo                          打包項目名稱
#          |___1.0.0                          打包版本號
#             |___2017_03_02_16/23/28         打包時間(格式:年_月_日_時/分/秒)
#                |___TestDemo_1.0.0.xcarchive 導出的.xcarchive文件
#                |___TestDemo.ipa             導出的.ipa文件
#                |___LogPath                  打包日志
#
#--------------------------------------------------------------------------------

#計時
SECONDS=0
#--------------------------------------------
# 參數(shù)判斷
#--------------------------------------------
# 如果參數(shù)個數(shù)少于1
if [ $# -lt 1 ];then
    echo -e  "\033[31m第一個參數(shù)請輸入 Xcode project 文件所在的根目錄文件夾名稱T芏痢朵诫!\033[0m"
    exit 2
fi

# 腳本文件所在根目錄
Release_path=$(pwd)
Project_dir=$1
Project_path=""

if [ "`pwd`" != "/" ]; then
    cd ..
    Root_path=$(pwd)
    Project_path="${Root_path}/${Project_dir}"
else
    echo -e "\033[31m腳本路徑錯誤\033[0m"
    exit 1;
fi

if [ ! -d "${Project_path}" ];then
    echo -e "\033[31m首參數(shù)必須是有效的文件夾名稱!薄扁!\033[0m"
    exit 2
fi

#Xcode project 文件路徑
cd ${Project_path}
Valid_dic=false
for i in `ls`;
do 
    #獲取文件后綴名
    extension=${i##*.}
    if [[ ${extension} == "xcodeproj" ]]; then
        Valid_dic=true
    elif [[ ${extension} == "xcworkspace" ]]; then
        Valid_dic=true
    fi
done

if [[ ${Valid_dic} == false ]]; then
    echo -e "\033[31m請輸入包含xcodeproj或xcworkspace的文件夾名稱<舴怠废累!\033[0m"
    exit 2
fi

Archive_type="project"
Scheme_name="default"
Edit="NO"
Configuration="Release"
Auto_increment_version_num="NO"
Build_str="custom"
Version_str="custom"

# 參數(shù)處理
param_pattern=":ws:edab:v:"
OPTIND=2
while getopts $param_pattern optname
  do
    case "$optname" in
      "w")        
        Archive_type="workspace"    
        ;;
      "s")
        tmp_optind=$OPTIND
        tmp_optname=$optname
        tmp_optarg=$OPTARG

        OPTIND=$OPTIND-1
        if getopts $param_pattern optname ;then
            echo  -e "\033[31m選項參數(shù)錯誤 $tmp_optname\033[0m"
            exit 2
        fi
        OPTIND=$tmp_optind
        Scheme_name=$tmp_optarg
        ;;
      "e")        
        Edit="YES"  
        ;;     
      "d")        
        Configuration="Debug"   
        ;;
      "a")
        Auto_increment_version_num="YES"
        ;;
      "b")
        tmp_optind=$OPTIND
        tmp_optname=$optname
        tmp_optarg=$OPTARG

        OPTIND=$OPTIND-1
        if getopts $param_pattern optname ;then
            echo  -e "\033[31m選項參數(shù)錯誤 $tmp_optname\033[0m"
            exit 2
        fi
        OPTIND=$tmp_optind
        Build_str=$tmp_optarg
        ;;
      "v")        
        tmp_optind=$OPTIND
        tmp_optname=$optname
        tmp_optarg=$OPTARG

        OPTIND=$OPTIND-1
        if getopts $param_pattern optname ;then
            echo  -e "\033[31m選項參數(shù)錯誤 $tmp_optname\033[0m"
            exit 2
        fi
        OPTIND=$tmp_optind
        Version_str=$tmp_optarg
        ;;
      "?")
        echo -e "\033[31m選項錯誤: $OPTARG\033[0m"
        exit 2
        ;;
      ":")
        echo -e "\033[31m選項 $OPTARG 必須帶參數(shù)\033[0m"
        exit 2
        ;;
      *)
        echo -e "\033[31m參數(shù)錯誤\033[0m"
        exit 2
        ;;
    esac
  done

# echo "Project_path = ${Project_path}"
#app文件名稱
appname=$(basename ./*.xcodeproj)
#通過app文件名獲得工程target名字
target_name=$(echo $appname | awk -F. '{print $1}')
#app文件中Info.plist文件路徑
App_infoplist_path=${Project_path}/${target_name}/Info.plist
# 獲取version值
Version_initial=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" ${App_infoplist_path})
# 獲取build值
Build_initial=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" ${App_infoplist_path})

if [[ ${Scheme_name} == "default" ]]; then
    Scheme_name=${target_name}
fi

echo "*************************************************"
echo -e "\033[36m* 打包項目: ${target_name}\033[0m"
echo "*************************************************"
echo ''

# 將數(shù)字123轉換為1.2.3的格式輸出
Num_str=""
caculate(){
    Parameter_num=$1;
    if [[ ${Parameter_num} < 10 ]]; then
        if [[ ${Num_str} == "" ]]; then
            Num_str="${Parameter_num}"
        else
            Num_str="${Parameter_num}.${Num_str}"
        fi
    else
        #商
        quotient="$[${Parameter_num}/10]"
        #余數(shù)
        remainder="$[${Parameter_num}%10]"
        if [[ ${Num_str} == "" ]]; then
            Num_str="${remainder}"
        else
            Num_str="${remainder}.${Num_str}"
        fi
        if [[ ${quotient} > 0 ]]; then
            caculate ${quotient}
        fi
    fi
}

#--------------------------------------------
# 處理Version版本號
#--------------------------------------------
# Version版本號自增
if [[ ${Auto_increment_version_num} == "YES" ]]; then
    if [[ ${Version_str} != "custom" ]]; then
        echo  -e "\033[31m選項-a 與 -v 不能同時存在\033[0m"
        exit 2
    else
        #取Version版本號
        Version_str=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" ${App_infoplist_path})
        #把Version_str字符串根據(jù).分割為數(shù)組
        Array=($(echo $Version_str | tr '.' ' ' | tr -s ' '))
        #數(shù)組長度
        Array_length=$(echo ${#Array[@]})
        # 獲取版本號數(shù)字
        Version_num=0
        for (( i = 0; i < ${Array_length}; i++ )); do
            index_num=${Array[$i]}
            sum_num="$[10**(${Array_length}-${i}-1)]"
            index_num="$[${index_num}*${sum_num}]"
            Version_num="$[${Version_num}+${index_num}]"
        done

        Version_num="$[$Version_num+1]"
        Num_str=""
        caculate ${Version_num}
        Version_str=${Num_str}
    fi
fi

#--------------------------------------------
# 修改Version版本號以及Build號
#--------------------------------------------
if [[ ${Version_str} != "custom" ]]; then
    echo "初始Version = ${Version_initial}"
    /usr/libexec/Plistbuddy -c "Set CFBundleShortVersionString $Version_str" "${App_infoplist_path}"
    Version_result=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" ${App_infoplist_path})
    echo "Version改變后 = ${Version_result}"
fi
if [[ ${Build_str} != "custom" ]]; then
    echo "初始Build = ${Build_initial}"
    /usr/libexec/Plistbuddy -c "Set CFBundleVersion $Build_str" "${App_infoplist_path}"
    Build_result=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" ${App_infoplist_path})
    echo "Build改變后 = ${Build_result}"
fi

if [ $? != 0 ]; then
    /usr/libexec/Plistbuddy -c "Set CFBundleShortVersionString $Version_initial" "${App_infoplist_path}"
    /usr/libexec/Plistbuddy -c "Set CFBundleVersion $Build_initial" "${App_infoplist_path}"
    echo -e "\033[31m*************     修改版本號出錯     **************\033[0m"
    exit 2
fi

#--------------------------------------------
# 準備打包
#--------------------------------------------
ExportOptionsPlist="${Release_path}/ExportOptions.plist"
#取當前時間字符串
Now=$(date +"%Y_%m_%d_%H:%M:%S")
Project_version=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" ${App_infoplist_path})
Version_output_path="${Release_path}/ArchivePath/${target_name}/${Project_version}"
IPA_path="${Version_output_path}/${Now}"
Archive_file_name="${target_name}_${Project_version}"
Archive_path="${IPA_path}/${Archive_file_name}.xcarchive"

mkdir -p "${IPA_path}"
Log_path="${IPA_path}/LogPath"

echo "************* xcodebuild clean 項目 **************"

# 清除項目
# xcodebuild clean -configuration ${Configuration} &>/dev/null
xcodebuild clean -configuration ${Configuration} >> $Log_path
# if [[ ${Edit} == "YES" ]]; then
    # cd "~/Library/Developer/Xcode"
    # user=$USER
    # Xcode_path="/Users/${user}/Library/Developer/Xcode"
    # cd ${Xcode_path}
    # for i in `ls`;
    # do 
    #   if [[ ${i} == "DerivedData" ]]; then
    #       if [ -d "${i}" ];then
    #           # 刪除~/Library/Developer/Xcode/DerivedData文件夾
    #           rm -rf ${i}
    #       fi
    #   fi
    # done
# fi

revertVersionNum(){
    /usr/libexec/Plistbuddy -c "Set CFBundleShortVersionString $Version_initial" "${App_infoplist_path}"
    /usr/libexec/Plistbuddy -c "Set CFBundleVersion $Build_initial" "${App_infoplist_path}"
    rm -rf "${IPA_path}"
    files=`ls ${Version_output_path}`
    if [ -z "$files" ]; then
        # 該版本號下沒打過包,把該版本號文件夾刪除 
        rm -rf "${Version_output_path}"
    fi
} 

if [ $? = 0 ]; then
    echo -e "\033[32m************* xcodebuild clean 完成 **************\033[0m"
    echo ''
    cd ${Project_path}
else
    revertVersionNum;
    echo -e "\033[31m************* xcodebuild clean 失敗 **************\033[0m"
    echo ''
    exit 1;
fi

Workspace_name="${Project_path}/${target_name}.xcworkspace"
Project_name="${Project_path}/${target_name}.xcodeproj"
if [[ ${Edit} == "YES" ]]; then
    if [[ ${Archive_type} == "workspace" ]];then
        #編譯workspace
        xcodebuild -workspace "${Workspace_name}" -scheme "${Scheme_name}" -configuration "${Configuration}" >> $Log_path
    else
        #編譯project
        xcodebuild -configuration "${Configuration}" >> $Log_path
    fi

    if [ $? = 0 ]; then
        echo -e "\033[32m************* xcodebuild 編譯 完成 **************\033[0m"
        echo ''
    else
        revertVersionNum;
        echo -e "\033[31m************* xcodebuild 編譯 失敗 **************\033[0m"
        echo ''
        exit 1;
    fi
fi

echo -e "\033[36m*************    打包 版本號 ${Project_version}    **************\033[0m"
echo "************* 開始導出xcarchive文件  *************"
if [[ ${Archive_type} == "workspace" ]];then
    #打包workspace
    xcodebuild archive -workspace "${Workspace_name}" -scheme "${Scheme_name}" -configuration "${Configuration}" -archivePath "${Archive_path}" >> $Log_path
else
    #打包project
    xcodebuild archive -project "${Project_name}" -scheme "${Scheme_name}" -configuration "${Configuration}" -archivePath "${Archive_path}" >> $Log_path
fi
if [ $? = 0 ]; then
    echo -e "\033[32m************* 導出xcarchive文件 完成 **************\033[0m"
    echo ''
else
    revertVersionNum;
    echo -e "\033[31m************* 導出xcarchive文件 失敗 **************\033[0m"
    echo ''
    exit 1;
fi

echo "*************   開始導出 ipa 文件    **************"
# xcodebuild -exportArchive -archivePath "${Archive_path}" -exportPath "${IPA_path}" -exportOptionsPlist "${ExportOptionsPlist}" &>/dev/null
xcodebuild -exportArchive -archivePath "${Archive_path}" -exportPath "${IPA_path}" -exportOptionsPlist "${ExportOptionsPlist}" >> $Log_path
if [ $? = 0 ]; then
    echo -e "\033[32m*************    導出 ipa 包完成     **************\033[0m"
    echo ''
else
    revertVersionNum;
    echo -e "\033[31m*************    導出 ipa 包失敗     **************\033[0m"
    echo ''
    exit 1;
fi
#輸出總用時
echo -e "\033[32m*************  打包完成. 耗時: ${SECONDS}s   **************\033[0m"
echo ''

腳本詳解

  • 開始部分脱盲,對輸入?yún)?shù)進行了判斷邑滨,腳本命令:[]表示可選參數(shù),<>表示必填參數(shù)

    ./Release.sh  <Project directory name> [-w] [-s <Name>] [-e] [-d] [-a] [-b <Build number>] [-v <Version number>]
    
  • 第二步钱反,判斷并修改Build號以及Version號掖看,-b <Build number> -v <Version number>,分別取對應的值面哥;如果是-a則Version號自增哎壳,在舊版本號的基礎上+1,其中的主版本號尚卫、副版本號归榕、發(fā)布號默認采用的是10進制規(guī)則,舉例

1.0.0 執(zhí)行-a后為 1.0.1
1.1.9 執(zhí)行-a后為 1.2.0

  • 導出xcarchive文件吱涉,這里要區(qū)分是project項目刹泄,還是workspace項目,如果你使用了CocoPads管理項目邑飒,那么打包的就是workspace項目
    if [[ ${Archive_type} == "workspace" ]];then
    #打包workspace
    xcodebuild archive -workspace "${Workspace_name}" -scheme "${Scheme_name}" -configuration "${Configuration}" -archivePath "${Archive_path}" >> $Log_path
    else
    #打包project
    xcodebuild archive -project "${Project_name}" -scheme "${Scheme_name}" -configuration "${Configuration}" -archivePath "${Archive_path}" >> $Log_path
    fi
    ${Workspace_name}是.xcworkspace文件的完整路徑(${Project_name}一樣)循签,${Scheme_name}表示項目Scheme的名稱,${Configuration}有兩個值:Debug和Release疙咸,${Archive_path}是生成的xcarchive文件的導出路徑县匠,>> $Log_path表示將log日志輸出到Log_path文件

  • 生成ipa文件
    xcodebuild -exportArchive -archivePath "${Archive_path}" -exportPath "${IPA_path}" -exportOptionsPlist "${ExportOptionsPlist}" >> $Log_path
    ${ExportOptionsPlist}指向ReleaseDir文件夾下的ExportOptions.plist文件,可以在文件內填寫跟打包相關的配置

    QQ20170303-150057@2x.png

    compileBitcode:不上架App Store撒轮,Xcode是否啟用Bitcode重新編譯乞旦,默認為YES。
    method:歸檔類型题山,包括app-store兰粉、ad-hoc、
    package顶瞳、enterprise玖姑、development以及developer-id。
    uploadBitcode:上線App Store是否開啟Bitcode慨菱,默認為YES焰络。
    uploadSymbols:上線App Store,是否開啟符號序列化符喝,這是與查crash相關的闪彼,默認為YES。

關于更多的xcodebuild指令协饲,可以通過xcodebuild -help查看畏腕。


最后附上兩張打包成功的圖片

QQ20170303-151520@2x.png

QQ20170303-151638@2x.png

腳本資源??看這里缴川。另外補充一點,腳本打包前請先在Xcode描馅,General—Targets—Signing中選擇好對應的證書把夸。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市流昏,隨后出現(xiàn)的幾起案子扎即,更是在濱河造成了極大的恐慌,老刑警劉巖况凉,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谚鄙,死亡現(xiàn)場離奇詭異,居然都是意外死亡刁绒,警方通過查閱死者的電腦和手機闷营,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來知市,“玉大人傻盟,你說我怎么就攤上這事∩┍” “怎么了娘赴?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長跟啤。 經常有香客問我诽表,道長,這世上最難降的妖魔是什么隅肥? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任竿奏,我火速辦了婚禮,結果婚禮上腥放,老公的妹妹穿的比我還像新娘泛啸。我一直安慰自己,他們只是感情好秃症,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布候址。 她就那樣靜靜地躺著,像睡著了一般种柑。 火紅的嫁衣襯著肌膚如雪宗雇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天莹规,我揣著相機與錄音,去河邊找鬼泌神。 笑死良漱,一個胖子當著我的面吹牛舞虱,可吹牛的內容都是我干的。 我是一名探鬼主播母市,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼矾兜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了患久?” 一聲冷哼從身側響起椅寺,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒋失,沒想到半個月后返帕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡篙挽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年荆萤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铣卡。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡链韭,死狀恐怖,靈堂內的尸體忽然破棺而出煮落,到底是詐尸還是另有隱情敞峭,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布蝉仇,位于F島的核電站旋讹,受9級特大地震影響,放射性物質發(fā)生泄漏量淌。R本人自食惡果不足惜骗村,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望呀枢。 院中可真熱鬧胚股,春花似錦、人聲如沸裙秋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摘刑。三九已至进宝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枷恕,已是汗流浹背党晋。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人未玻。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓灾而,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扳剿。 傳聞我的和親對象是個殘疾皇子旁趟,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內容