關於 iOS 批量打包的總結

Tsui YuenHong發表於2016-11-01

如果你曾經試過做多 target 的專案,到了測試人員要測試包的時候,你就會明白什麼叫“生不如死”。雖然 Xcode 打包很方便,但是當你機械重複打 N 次包的時候,就會覺得這純粹是浪費時間的工作。所以這時候自動化打包就顯得尤為重要(其實就算只有一個 target,就算使用 Xcode 打包很方便,也應該構建自動化打包,因為你可以節省大量時間)。

構建自動化打包指令碼

xcodebuild

使用 xcodebuild -h 來看看 xcodebuild 到底是幹啥的

這裡我只擷取了 usage 部分,option 部分太多沒有擷取。

這裡介紹幾條畢竟常用的命令

1. xcodebuild -list …

xcodebuild -list [[-project ]|[-workspace ]] [-json]

usage: 輸出 project 中的 targets 和 configurations,或者 workspace 中 schemes。
-project-workspace 是輸出指定內容,不輸入預設輸出當前目錄下。-json 是以 json 格式輸出。

example:

2. xcodebuild -project …

xcodebuild [-project ] [[-target ]...|-alltargets] [-configuration ] [-arch ]... [-sdk [|]] [-showBuildSettings] [=]... []...

usage:

-project: 指定 project 名字,預設首個 project。

-target: 指定對應的 target ,預設首個 target。

-configuration: 選擇Debug 或 Release,預設 Release,當然如果你有自定義的配置的,就應該選你配置的,上面 -list 中有輸出。

-showBuildSettings: 顯示工程的配置。

=: 修改工程的配置檔案。

buildaction ... : 如下,預設為 build

example:

  • $ xcodebuild -project 你的專案名字.xcodeproj -target 你的 target 名字 -configuration release

這行命令表示編譯 xx.xcodeproj 的 xx target。在 terminal 中會看到編譯過程,如果成功最後會輸出 ** BUILD SUCCEEDED **。最後會在當前目錄下生成 build/Release-iphoneos/xx.app

  • $ xcodebuild -project 你的專案名字.xcodeproj -target 你的 target 名字 -configuration release -showBuildSettings

這行命令使用 -showBuildSettings 是不會 build 專案的,只是輸出工程的配置。這裡輸出的的內容有(內容過多,只擷取部分)

如果要修改配置檔案,就直接最命令最後加上你要修改的內容。
例如在這行命令最後加上指定證書

  • $ xcodebuild -project 你的專案名字.xcodeproj -target 你的 target 名字 -configuration release PROVISIONING_PROFILE="你證書的id"

其中的欄位是上面 -showBuildSettings 顯示的欄位,也可以看官網介紹

3. xcodebuild -workspace …

xcodebuild -workspace -scheme [-destination ]... [-configuration ] [-arch ]... [-sdk [|]] [-showBuildSettings] [=]... []...

除了 workspace 和 scheme 之外其餘選項都和上條命令相同。

-workspace: 指定 workspace 名字,預設首個 workspace

-scheme: 指定對應的 scheme ,預設首個 scheme

4 . xcodebuild -exportArchive …

這裡順便介紹一下 archive 命令,因為在下面使用 PackageApplication 會出一個警告說推薦使用 -exportArchive。所以我們就來嘗試一下使用 archive 來生成 app。

首先使用一下命令來生成 .xcarchive 檔案
xcodebuild archive -workspace xx.xcworkspace -scheme xx -archivePath xx.xcarchive
可以看出新增上 archive 命令和最後加入 -archivePath 生成archivePath的路徑即可。
然後該路徑下會生成一個 xx.archivePath,裡面包括三個檔案,xx.app.dsym檔案(可用於bugly等監控bug的平臺),info.plist(儲存打包的一些資訊),還有我們的 xx.app 檔案。

其次使用 -exportArchive 生成 ipa 包

xcodebuild -exportArchive -archivePath xx.xcarchive -exportPath xx -exportFormat ipa

-archivePath: xx.archivePath 的路徑

-exportPath: 輸出路徑

-exportFormat: 生成型別,這裡選擇我們需要的 ipa

這樣就利用我們的 xcodebuild 命令來生成 ipa 包

xcrun

這裡也使用 xcrun 來生成 ipa 包即可

xcrun -sdk iphoneos PackageApplication build/Release-iphoneos/xx.app -o ~/Desktop/xx.ipa

但是,在 macos10.12 和 Xcode8 的環境下會出現一個警告

warning: PackageApplication is deprecated, use xcodebuild -exportArchive instead.

說明 PackageApplication 已經被棄用了。

不過其實這一步可以幾乎等價於將 xx.app 放入一個 payload 的資料夾下然後壓縮資料夾為 xx.ipa,當然這樣做缺失一些資訊,不過並不影響程式的執行。

初步小結

綜上,我們有兩種方法來生成我們需要的 ipa 包。

  1. 使用 xcodebuild 命令來編譯我們的專案生成 app,然後再用 xcrun 將 app 轉 ipa。
  2. 使用 xcodebuild archive 命令來直接生成我們需要的 ipa。

雖然現在網上幾乎都是使用 xcodebuild + xcrun 來來生成 ipa 包,不過既然官方說 PackageApplication is deprecated,那還是推薦使用第二種方法,一步到位。

自動化打包正式開始

這裡從我工作室的一個專案切入,這個專案需要最終生成 18 個 ipa 包,但是他們幾乎是共用一套程式碼的,不同的地方在於bundleName/bundleDisplayName/bundleid 等,以及一些資原始檔的不同,例如 icon 等。所以可想而知如果選擇手動打包的痛苦,並且當你打包到一半發現某個地方錯了要重新打包 ……

這裡說一下自動化打包1.0解決思路:

  1. 使用命令 defaults write 來修改專案中的 plist 檔案,來達到修改 bundleName/bundleDisplayName/bundleid… 的目的。
  2. 使用命令 cp 來替換資原始檔。
  3. 使用 xcodebuild -workspace .. 編譯出 app 包。
  4. 使用 xcrun ... 生成 ipa 。

這是我最開始想到的思路,最終執行時間大概為每個包2.5m(時間主要浪費在編譯),然後一套下來也要半個多小時。雖然比起手動打快了不少,但還是太慢了。畢竟自動化的目的不僅僅是自動,還要速度。

既然問題出在編譯上,那我的思路就往編譯一次多次使用這個方向上面思考。然後想到了既然只是資原始檔和plist的不同,沒有涉及到程式碼的更換(不過這個專案後期不同 app 會執行不同一套程式碼,不過也有解決辦法),這裡就出現了自動化打包2.0的版本。

  1. 使用 xcodebuild -workspace .. 編譯出 app 包。
  2. 使用命令 defaults write 來修改專案中的 plist 檔案,來達到修改 bundleName/bundleDisplayName/bundleid… 的目的。
  3. 使用命令 cp 來替換資原始檔。
  4. 重簽名 codesign -f -s "iPhone Distribution: xx co., LTD" --entitlements $Entitlements $ipaPath/Payload/YouXiaoYun.app
  5. 使用 xcrun ... 生成 ipa 。

和1.0大致相似,不過並不是每次生成 ipa 都需要編譯一次。而是編譯一次,然後直接修改 app 下內容,不過這裡會出現簽名錯誤的問題,因為在編譯的最後會用證書幫 app 簽名,如果你直接替換資源然後就生成 ipa 的話會導致 ipa 無法安裝。

那這時候神奇的重簽名技術就出來(重簽名用在正途上的真少見…hhhh,關於重簽名的文章 google 一下就會很多),使用 codesign 命令就可以幫修改過資源的 app 重簽名。
最終使用2.0的時間基本是在5-6分鐘左右。果然能機器完成的工作絕對不要手動完成,從半天到30分鐘到最後的6分鐘,節省下來的時間可以讓你學習到更多。

上面說到如果不同 app 間會用到不同的程式碼。例如 app A 裡面的 title 叫 A 部門,app B 裡面 title 又叫 B 部門,這樣就不會通過命令列直接修改到程式碼,不過我想到的是維護一個 plist 檔案,plist 檔案可以這樣設計的,每個不同 app 的 bundleName 都設定字典的鍵,然後字典下就可以是你自定義的內容。然後每次啟動 app 就根據 bundleName 來尋找對應的字典,然後 title 就賦值為 plist 下 title 的值。如果不同程式碼就根據 code1 裡面的值來 switch 不同的程式碼。

11228408-e1aa7e98b1d1edb6

最終程式碼

以下是完整的指令碼檔案,部分資訊需要自己替換。
以下指令碼適用於一次打 N 個包,適用情況:

  1. 可以替換 bundle 資訊
  2. 替換音訊圖片資源
  3. 可以執行不同程式碼
  4. 生成相應的plist檔案
  5. 上傳到蒲公英分發平臺

當然也可以打一個包,適當刪除某些程式碼即可。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

關於 iOS 批量打包的總結 關於 iOS 批量打包的總結

相關文章