iOS —— 兩套自動打包腳本

前言

項目每次更新要打十幾個包,廣發說傳承下來的自動打包腳本忽然很差使了,如今每次打包上傳都要弄到凌晨,之後更名叫稀發好了。看着他愈來愈禿的頭,我這父愛就藏匿不住,必需要幫他分擔(固然是被逼的)。json

這個項目十幾個包,不一樣圖標、App名字,手動打包不但慢,並且重複枯燥的工做出錯機率也指數上升。因此若是你的項目也要打幾個包的話,花時間學習自動打包仍是值得的。若是隻用打一個包,雖然自動打包時間會快點,但學習成本仍是在那,見仁見智了。api

重點是,利用重簽名修改自定義的圖片、App名字等,不用重複編譯,能極大縮短打包時間。數組

證書知識

網上關於證書配置不乏好文章,一搜一大堆,但大多都沒有介紹分別有什麼用。xcode

  • CSR:Certificate Singing Request,證書籤名請求文件。

包含電腦的信息。因此建立時不須要填任何和發佈等有關的信息。bash

  • Certificates證書:發佈者證書。Apple Develop的ID 對某部電腦的受權證書。

電腦擁有這個證書後,有權對該Apple Developer的ID下全部App進行真機測試、打包、發佈。注意這裏,並未指定App,換句話說,和App無關。併發

包含電腦的信息和Apple Developer的信息app

  • CSR和Certificates的聯繫

上面提到了Certificates包含了電腦的信息,這個信息來自於CSR。因此在建立Certificates時,須要提交CSR。curl

  • Certificates導出p12文件

上面提到,擁有此證書纔有權作那些事。若是另外一部電腦想發佈,也須要證書。若是又建立一個新證書也能解決,但通常一個開發者賬號建立一個發佈證書就夠了,並且蘋果對這證書數量有限制。這時候導出p12文件,至關於拷貝了一份證書(不佔蘋果限制數量)。給另外一部電腦安裝後,另外一部電腦就有權了。iphone

到這裏,筆者就迷惑了CSR包含了電腦的信息,而後又能拷貝給其餘電腦用,有什麼用呢。但願大佬能解惑。ide


上面提到的與App無直接關係,如下才與App創建起聯繫。

  • App IDs

在該Apple Developer下注冊App。這裏要填Name和Bundle ID。這裏的Bundle ID將在Xcode中匹配證書。

以前聽李大神說,新建一個新項目,而後改成公司項目中的Bundle ID,App也能真機測試,就是由於經過Bundle ID來匹配。

  • Provisioning Profiles:PP文件。.mobileprovision後綴。

包含appID,開發者證書。

建立時,開發版和發佈版有區別。前者要選設備,後者不用。

建立下載後,Xcode就會自動匹配,固然也能夠手動匹配。

  • 作項目時,若是不是你負責的,別人一般會發你.p12和.mobileprovision文件。前者受權你的電腦Apple Developer的ID權限,後者受權App權限。

自動打包

本文采用的是xcodebuild。

提及自動打包就腦袋疼。一直對命令行有恐懼,只能一步一步來了。先了解命令行命令,而後新建一個項目熟悉一下。

xcodebuild 簡介

xcodebuild 是xcode提供的打包項目或者工程的命令。

輸入man xcodebuild能夠查看文檔。

這裏引用大佬的總結。

輸入xcodebuild -h能夠查看幫助。

Usage: xcodebuild [-project <projectname>] [[-target <targetname>]...|-alltargets] [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings] [<buildsetting>=<value>]... [<buildaction>]...
       xcodebuild [-project <projectname>] -scheme <schemeName> [-destination <destinationspecifier>]... [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings] [<buildsetting>=<value>]... [<buildaction>]...
       xcodebuild -workspace <workspacename> -scheme <schemeName> [-destination <destinationspecifier>]... [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings] [<buildsetting>=<value>]... [<buildaction>]...
       xcodebuild -version [-sdk [<sdkfullpath>|<sdkname>] [<infoitem>] ]
       xcodebuild -list [[-project <projectname>]|[-workspace <workspacename>]] [-json]
       xcodebuild -showsdks
       xcodebuild -exportArchive -archivePath <xcarchivepath> -exportPath <destinationpath> -exportOptionsPlist <plistpath>
       xcodebuild -exportLocalizations -localizationPath <path> -project <projectname> [-exportLanguage <targetlanguage>...]
       xcodebuild -importLocalizations -localizationPath <path> -project <projectname>
複製代碼

xcodebuild嘗試

你們這時候能夠新建一個項目Test。而後在Xcode中,把公司項目(有證書)的Bundle Identifier複製過來,這時候你會發現證書匹配經過了。(若是你沒有證書,那看回證書知識,弄好再往下看)有了這個項目,就能夠感覺這些命令了。

打包方法一

筆者認爲這方法不如方法二,並且蘋果也廢棄了其中一個工具。

先編譯出.app,而後轉成.ipa。

終端進項目文件夾後,先來試試第一條編譯命令。

xcodebuild -project Test.xcodeproj -target Test -configuration Release

不出意外,會打印以上文字,包括簽名身份和配置文件。文件夾下有Test/build/Release-iphoneos/Test.app.dSYM

這時咱們還要用xcrun命令把其導出爲ipa文件,(但xcrun在Xcode8.3廢棄了,若是還要用看這篇 xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH

處理好後,執行下面命令轉成ipa

xcrun -sdk iphoneos PackageApplication build/Release-iphoneos/Test.app -o ~/Desktop/Test.ipa
複製代碼

打包方法二

先用archive,而後exprotArchive,相似於手動打包的界面步驟。

(先運行xcodebuild -list,記住Scheme)

終端進入項目文件夾後,運行xcodebuild archive -scheme Test -archivePath ~/Desktop/Test.xcarchive,注意這裏不打scheme會失敗。

筆者瞎猜以上和Xcode內打包對應着這個界面。

從上圖可看出,由於不一樣途徑發佈,因此要各自配置ExportOptions.plist。也就是用於xcodebuild -exportArchive -archivePath <xcarchivepath> -exportPath <destinationpath> -exportOptionsPlist <plistpath>中最後一個。

有兩種途徑配置。

  • 經過手動打包,複製過去。
  • 本身新建一個plist文件,加入相關鍵值對。(前提是你知道怎麼加)。
ExportOptions.plist文件中有如下字段,配置以下:

method:字符串,爲打包的類型,分爲app-store,ad-hoc,enterprise和development,根據本身實際打包狀況填寫。

provisioningProfiles:字典,Xcode9須要,鍵值對爲{bundleid:描述文件名},描述文件名最好使用其對應的UUID。

signingCertificate:證書類型,開發環境爲iPhone Developer,生產環境爲iPhone Distribution。

signingStyle:自動仍是手動(manual與automatic),填寫manual便可。

stripSwiftSymbols:填寫爲YES。

teamID:爲開團隊ID,在鑰匙串中點擊證書詳情能夠查看到。

uploadBitcode:爲YES便可。

uploadSymbols:爲YES便可。
複製代碼

筆者仍是建議手動打包,複製過去再作修改(之後其餘項目只要稍微改動就能用,不用再次手動打包後複製)。由於經過圖形界面,能更好理解這些字段的意義以及對應的操做。

筆者選取了Enterprise的截圖。其餘由於筆者沒有證書,就靠各位嘗試了。

而後終端中接着運行

xcodebuild -exportArchive -archivePath ~/Desktop/Test.xcarchive -exportPath ~/Desktop/Test.api -exportOptionsPlist ./ExportOptions.plist
複製代碼

xcodebuild學到這就會打包了,其餘不經常使用的方法,網上學習資源少,筆者也不想探究了。下面進入打包腳本。


自動打包腳本

筆者參考師兄@Tsui_YuenHong的文章關於 iOS 批量打包的總結,本身設置了一份腳本,用了蘋果建議的新方法以及補充了一些師兄腳本的不足點。

先說明一下筆者的悲慘遭遇。筆者之前也打過包上傳App-Store,整個過程愉愉快快。可是這項目,一共有20多個包,更新一次版本常常動不動就打十多個包。這樣打下來,頭髮就沒了。因爲代碼基本是同樣的,因此利用重簽名,能極大程度縮短打包時間。

筆者的項目打包有如下需求。

簡單點說就是針對不一樣的用戶定製相應的自定義圖標、功能等。

  1. 能夠替換 bundle 信息
  2. 替換音頻圖片資源
  3. 能夠執行不一樣代碼
  4. 生成相應的plist文件
  5. 上傳到蒲公英分發平臺

思路:

  1. 先編譯出.app文件。
  2. 使用命令 defaults write 來修改項目中的 plist 文件,來達到修改 bundleName/bundleDisplayName等鍵值對,實現自定義App名字、展現名字功能,而且生成相應的plist文件。
  3. 使用cp命令來替換圖片資源。
  4. 重簽名。
  5. 導出ipa。

筆者遇到的問題:

切換圖標的坑

先了解官方建議圖標尺寸。固然其餘尺寸,App圖標也會接受,自動適應。

方案一(未解決)

  • 筆者嘗試用這種方案。原理就是用同名的圖片覆蓋包中的圖片,重簽名,達到修改圖標的目的。可是包內圖片覆蓋之後,安裝下來圖標卻沒有改變(可能要修改Info.plist中的Icon files (iOS 5)(然而這個字段就是AppIcon???不知道底層還有什麼配置),筆者就不繼續嘗試了)。

方案二

  • 此方法要把圖標放在項目中,不要放在xcassets中。

  • AppIcon的名字必定要對應上!由於後面命令行cp時要所有替換,不然難以預測會出現什麼問題,就像下圖。(筆者的項目中,只弄了60@2x和60@3x的圖。)

  • 打包出來後,AppIcon圖標在.app文件目錄中,不在BundleResources中。

關於能夠執行不一樣代碼。

重簽名

建議你們先看這篇文章。 iOS應用程序的重簽名(打包)

弄出來entitlements.plist,重簽名要用到。


題外話

筆者重簽名仍是遇到了坑,打包出來的軟件下載時進度條轉了一圈,但沒法最終完成。查了一段時間,才知道緣由是重簽名不成功。因此說腳本要重簽名失敗必須終止。

附帶一篇iTunes降級文章,,PP助手好像沒更新仍是什麼,只能用舊版iTunes來調試吧,真是累啊。將 iTunes 降回 12.6.3 可下載應用安裝包版本教程【Windows | Mac】


腳本

師兄的腳本一(運行時間256s)比筆者的腳本二(運行時間306s)快。

但腳本一採用的是蘋果廢棄的方法,之後出問題就試試腳本二吧。

兩種腳本不一樣之處在於:腳本一先出來.app,後出來.ipa;腳本二先出來Archive包(包裏有.app),後出來.ipa。

  • 腳本一

準備好Entitlements.plist(本文有獲取教程,Cmd+f搜"重簽名要用到")。而且確保本機能運行xcrun(本文Cmd+f搜"在Xcode8.3廢棄")。

編譯後用xcrun導出ipa,最後重簽名。

腳本在師兄的文章關於 iOS 批量打包的總結裏貼出來了。

筆者在用該腳本時遇到圖標更換失敗的問題,和腳本無關,與項目配置有關,解決方法看回上面。

但筆者認爲該腳本存在一些問題的。例如重簽名等操做失敗後未終止腳本,致使筆者上傳到蒲公英後下載失敗一頭霧水。這問題很嚴重。不過只要適當判斷,加個exit就能解決。

  • 腳本二

準備好Entitlements.plist(本文有獲取教程,Cmd+f搜"重簽名要用到")和ExportOptions.plistist``(本文有獲取教程,Cmd+f搜"有兩種途徑配置")。

先用archive,而後exprotArchive(相似於手動打包流程),最後重簽名。

下面貼出腳本,注意裏面不少地方筆者用Project代替了。

# 1.Configuration Info

# 項目路徑 需修改
projectDir="你的項目路徑"

# 打包生成路徑 建議桌面
ipaPath="ipa生成路徑"

# 圖標路徑 需修改
iconPath="圖標路徑"

# 如下文件用於重簽名生成ipa,需修改
Entitlements=$ipaPath/Entitlements.plist
ExportOptions=$ipaPath/ExportOptions.plist

# 版本號
bundleVersion="2.0.0"

# 選擇打包序號 多選則以空格隔開 如("1" "2" "3")
appPackNum=("1" "2")

# 蒲公英分發參數 不分發可忽略 默認不分發 下面的兩個KEY是默認測試的網址對應KEY
ISUPLOAD=0
USERKEY="xxx"
APIKEY="xxx"

# ---------------------------可選 若是須要替換 app 的 icon --------------------------------- #

# 配置App信息數組 格式:"AppName(和工程中appInfo.Plist對應)" "icon" "Url中的AppName"(由於AppName爲中文,此處用英文)
#Schemes:
# 1.app1 app1Icon app1UrlName
# 2.app2 app2Icon app2UrlName
# 3.app3 app3Icon app3UrlName

# --------------------------------------------------------------------------------------- #

# 打包個數
appPackNumLength=${#appPackNum[*]}

appInfos=(
          "app1" "app1Icon" "app1UrlName"
          "app2" "app2Icon" "app2UrlName"
          "app3" "app3Icon" "app3UrlName"
          )

appInfosLength=${#appInfos[*]}

# Scheme Name
schemeName="xx"

# 開始時間
beginTime=`date +%s`

# 生成 xcarchive 路徑,建議桌面
mkdir ${ipaPath}/Payload
rm -rf ${ipaPath}/Payload/*
buildDir="${ipaPath}/Payload"

# 使用的時候要關掉自動簽名 改成手動簽名
# Build 生成 xcarchive
xcodebuild archive -workspace ${projectDir}/YouXiaoYun.xcworkspace -scheme ${schemeName} -archivePath ${buildDir}/Project.xcarchive
#
if [[ $? = 0 ]]; then # $? 表示上一條命令返回值。若是上一條命令成功執行,返回0,不然返回1.
    echo "\033[31m 編譯成功\n \033[0m"
else
    echo "\033[31m 編譯失敗\n \033[0m"
    exit 0
fi

# 建立打包目錄
mkdir ${ipaPath}/AllPack

# 本地存放所有 IPA 的路徑
allIPAPackPath="${ipaPath}/allPack"

# 如下二選一
# 1.----所有打包----
#for (( i=0; i<appInfosLength; i+=3 )); do

# 2.----自定義打包----
for (( j=0; j<$appPackNumLength; j++)); do i=`expr ${appPackNum[$j]} - 1` i=`expr $i \* 3`

# App Bundle Name (CFBundleName)
appName=${appInfos[${i}]}

# App DisPlay Name
appDisplayName=${appInfos[${i}]}

# App Icon Name
appIconName=${appInfos[$i+1]}

# App Download Name
appDownloadName=${appInfos[$i+2]}

# 建立不一樣 app ipa 目錄
mkdir $allIPAPackPath/$appName
rm -rf $allIPAPackPath/$appName/*

echo "\033[31m appName:$appName appIconName:$appIconName appDownloadName:$appDownloadName\n \033[0m"

# 將對應的 icon 複製到須要修改的 app 的目錄下
cp -Rf $iconPath/$appName/* ${buildDir}/Project.xcarchive/Products/Applications/Project.app

if [[ $? = 0 ]]; then
 echo "\033[31m $appName 修改 icon 成功\033[0m"
else
 echo "\033[31m $appName 修改 icon 失敗\033[0m"
 exit 0
fi

# 修改 Plist
defaults write $ipaPath/Payload/xx.app/info.plist "CFBundleName" $appName
defaults write $ipaPath/Payload/xx.app/info.plist "CFBundleDisplayName" $appDisplayName

if [[ $? = 0 ]]; then
  echo "\033[31m $appName 修改 Plist 成功\033[0m"
else
  echo "\033[31m $appName 修改 Plist 失敗\033[0m"
  exit 0
fi

# 重簽名
xattr -cr ${buildDir}/Project.xcarchive/Products/Applications/Project.app
codesign -f -s "xx co., LTD" --entitlements $Entitlements ${buildDir}/Project.xcarchive/Products/Applications/Project.app
if [[ $? = 0 ]]; then
    echo "\033[31m $appName 重簽名成功\n \033[0m"
else
    echo "\033[31m $appName 重簽名失敗\n \033[0m"
    exit 0
fi

# 生成 ipa
xcodebuild -exportArchive -archivePath $ipaPath/Payload/Project.xcarchive -exportPath ${ipaPath}/$appDownloadName.ipa -exportOptionsPlist $ExportOptions

if [[ $? = 0 ]]; then
    echo "\033[31m \n $appName 生成 IPA 成功 \n\n\n\n\n\033[0m"
else
    echo "\033[31m \n $appName 生成 IPA 失敗 \n\n\n\n\n\033[0m"
    exit 0
fi

# 建立 Plist
plist_path=$allIPAPackPath/$appName/$appDownloadName.plist

cat << EOF > $plist_path
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>items</key>
    <array>
        <dict>
            <key>assets</key>
            <array>
                <dict>
                    <key>kind</key>
                    <string>software-package</string>
                    <key>url</key>
                    <string>https://xxxxxxxxxxxx/$appDownloadName.ipa</string>
                </dict>
                <dict>
                    <key>kind</key>
                    <string>display-image</string>
                    <key>url</key>
                    <string>https://xxxxxxxxxxxx/${appIconName}.png</string>
                </dict>
                <dict>
                    <key>kind</key>
                    <string>full-size-image</string>
                    <key>url</key>
                    <string>https://xxxxxxxxxxxx/${appIconName}.png</string>
                </dict>
            </array>
            <key>metadata</key>
            <dict>
                <key>bundle-identifier</key>
                <string>你的bundid</string>
                <key>bundle-version</key>
                <string>$bundleVersion</string>
                <key>kind</key>
                <string>software</string>
                <key>title</key>
                <string>$appDownloadName</string>
            </dict>
        </dict>
    </array>
</dict>
</plist>
EOF

# 移動
mv ${ipaPath}/$appDownloadName.ipa ${allIPAPackPath}/$appName

done

# 6.上傳蒲公英分發平臺

if [[ $ISUPLOAD = 1 ]]; then
    echo "\n 開始上傳蒲公英... \n"
    curl -F "file=@$AllIPAPackPath/$appName/$appDownloadName.ipa/Project.ipa" \
    -F "uKey=$USERKEY" \
    -F "_api_key=$APIKEY"\
    http://www.pgyer.com/apiv1/app/upload
    #判斷上傳結果
    if [[ $? = 0 ]]; then
        echo "\n ~~~~~~~\^o^/~~~~上傳到蒲公英成功~~~~\^o^/~~~ \n"
    else
        echo "\n ~~~~~\(╯-╰)/~~~~~~~上傳到蒲公英失敗~~~~~\(╯-╰)/~~~~~ \n"
    fi
fi

# 清除無關文件
rm -rf $ipaPath/Payload

# 結束時間
endTime=`date +%s`
echo -e "打包時間$[ endTime - beginTime ]秒"
複製代碼

參考

相關文章
相關標籤/搜索