iOS自動打包併發布指令碼
本文最終實現的是使用指令碼打 Ad-hoc 包,併發布測試,當然稍微修改一下指令碼引數就可以打其他型別的 ipa 包了。另外該指令碼還實現了將生成的 ipa 包上傳至蒲公英進行測試分發。文中內容包括:
-
xcodebuild 簡介
-
使用xcodebuild和xcrun打包簽名
-
將打包過程指令碼化
xcodebuild 簡介
xcodebuild 是蘋果提供的打包專案或者工程的命令,瞭解該命令最好的方式就是使用 man xcodebuild 檢視其 man page. 儘管是英文,一定要老老實實的讀一遍就好了。
DESCRIPTION xcodebuild builds one or more targets contained in an Xcode project, or builds a scheme contained in an Xcode workspace or Xcode project.
Usage
To build an Xcode project, run xcodebuild from the directory containing your project (i.e. the directory containing the name.xcodeproj package). If you have multiple projects in the this directory you will need to use -project to indicate which project should be built. By default, xcodebuild builds the first target listed in the project, with the default build configuration. The order of the targets is a property of the project and is the same for all users of the project. To build an Xcode workspace, you must pass both the -workspace and -scheme options to define the build. The parameters of the scheme will control which targets are built and how they are built, although you may pass other options to xcodebuild to override some parameters of the scheme. There are also several options that display info about the installed version of Xcode or about projects or workspaces in the local directory, but which do not initiate an action. These include -list, -showBuildSettings, -showsdks, -usage, and -version.
總結一下:
-
需要在包含 name.xcodeproj 的目錄下執行 xcodebuild 命令,且如果該目錄下有多個 projects,那麼需要使用 -project 指定需要 build 的專案。
-
在不指定 build 的 target 的時候,預設情況下會 build project 下的第一個 target
-
當 build workspace 時,需要同時指定 -workspace 和 -scheme 引數,scheme 引數控制了哪些 targets 會被 build 以及以怎樣的方式 build。
-
有一些諸如 -list, -showBuildSettings, -showsdks 的引數可以檢視專案或者工程的資訊,不會對 build action 造成任何影響,放心使用。
那麼,xcodebuild 究竟如何使用呢? 繼續看文件:
NAME
xcodebuild -- build Xcode projects and workspaces
SYNOPSIS
-
xcodebuild [-project name.xcodeproj] [[-target targetname] ... | -alltargets] [-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value ...]
-
xcodebuild [-project name.xcodeproj] -scheme schemename [[-destination destinationspecifier] ...] [-destination-timeout value] [-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value ...]
-
xcodebuild -workspace name.xcworkspace -scheme schemename [[-destination destinationspecifier] ...] [-destination-timeout value] [-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [action ...] [buildsetting=value ...] [-userdefault=value ...]
-
xcodebuild -version [-sdk [sdkfullpath | sdkname]] [infoitem]
-
xcodebuild -showsdks
-
xcodebuild -showBuildSettings [-project name.xcodeproj | [-workspace name.xcworkspace -scheme schemename]]
-
xcodebuild -list [-project name.xcodeproj | -workspace name.xcworkspace]
-
xcodebuild -exportArchive -archivePath xcarchivepath -exportPath destinationpath -exportOptionsPlist path
-
xcodebuild -exportLocalizations -project name.xcodeproj -localizationPath path [[-exportLanguage language] ...]
-
xcodebuild -importLocalizations -project name.xcodeproj -localizationPath path
挑幾個我常用的形式介紹一下,較長的使用方式以序列號代替:
-
xcodebuild -showsdks: 列出 Xcode 所有可用的 SDKs
-
xcodebuild -showBuildSettings: 上述序號6的使用方式,檢視當前工程 build setting 的配置引數,Xcode 詳細的 build setting 引數參考官方文件Xcode Build Setting Reference , 已有的配置引數可以在終端中以 buildsetting=value 的形式進行覆蓋重新設定.
-
xcodebuild -list: 上述序號7的使用方式,檢視 project 中的 targets 和 configurations,或者 workspace 中 schemes, 輸出如下:
Information about project "NavTabBar": Targets: NavTabBar NavTabBarTests NavTabBarUITests Build Configurations: Debug Release Ad-hoc If no build configuration is specified and -scheme is not passed then "Release" is used. Schemes: NavTabBar
-
xcodebuild [-project name.xcodeproj] [[-target targetname] ... | -alltargets] build: 上述序號1的使用方式,會 build 指定 project,其中 -target 和 -configuration 引數可以使用 xcodebuild -list 獲得,-sdk 引數可由 xcodebuild -showsdks 獲得,[buildsetting=value ...] 用來覆蓋工程中已有的配置。可覆蓋的引數參考官方文件Xcode Build Setting Reference , action... 的可用選項如下, 打包的話當然用 build,這也是預設選項。
-
build
Build the target in the build root (SYMROOT). This is the default action, and is used if no action is given.
-
analyze
Build and analyze a target or scheme from the build root (SYMROOT). This requires specifying a scheme.
-
archive
Archive a scheme from the build root (SYMROOT). This requires specifying a scheme.
-
test
Test a scheme from the build root (SYMROOT). This requires specifying a scheme and optionally a destination.
-
installsrc
Copy the source of the project to the source root (SRCROOT).
-
install
Build the target and install it into the target's installation directory in the distribution root (DSTROOT).
-
clean
Remove build products and intermediate files from the build root (SYMROOT).
-
-
xcodebuild -workspace name.xcworkspace -scheme schemename build: 上述序號3的使用方式,build 指定 workspace,當我們使用 CocoaPods 來管理第三方庫時,會生成 xcworkspace 檔案,這樣就會用到這種打包方式.
使用xcodebuild和xcrun打包簽名
開始之前,可以新建一個測試工程 TestImg 來練習打包,在使用終端命令打包之前,請確認該工程也可以直接使用 Xcode 真機除錯成功。
然後,開啟終端,進入包含 TestImg.xcodeproj 的目錄下,執行以下命令:
xcodebuild -project TestImg.xcodeproj -target TestImg -configuration Release
如果 build 成功,會看到 ** BUILD SUCCEEDED ** 字樣,且在終端會打印出這次 build 的簽名信息,如下:
Signing Identity: "iPhone Developer: xxx(59xxxxxx)" Provisioning Profile: "iOS Team Provisioning Profile: *"
且在該目錄下會多出一個 build 目錄,該目錄下有 Release-iphoneos 和 TestImg.build 檔案,根據我們 build -configuration 配置的引數不同,Release-iphoneos 的檔名會不同。
在 Release-iphoneos 資料夾下,有我們需要的TestImg.app檔案,但是要安裝到真機上,我們需要將該檔案匯出為ipa檔案,這裡使用 xcrun 命令。
xcrun -sdk iphoneos -v PackageApplication ./build/Release-iphoneos/TestImg.app -o ~/Desktop/TestImg.ipa
這裡又冒出一個 PackageApplication, 我剛開始也不知道這是個什麼玩意兒,萬能的google告訴我,這是 Xcode 包裡自帶的工具,使用 xcrun -sdk iphoneos -v PackageApplication -help 檢視幫助資訊.
Usage: PackageApplication [-s signature] application [-o output_directory] [-verbose] [-plugin plugin] || -man || -help Options: [-s signature]: certificate name to resign application before packaging [-o output_directory]: specify output filename [-plugin plugin]: specify an optional plugin -help: brief help message -man: full documentation -v[erbose]: provide details during operation
如果執行成功,則會在你的桌面生成 TestImg.ipa 檔案,這樣就可以釋出測試了。如果你遇到以下警告資訊:
Warning: --resource-rules has been deprecated in Mac OS X >= 10.10! ResourceRules.plist: cannot read resources
請參考 stackoverflow這個回答
將打包過程指令碼化
工作中,特別是所做專案進入測試階段,肯定會經常打 Ad-hoc 包給測試人員進行測試,但是我們肯定不想每次進行打包的時候都要進行一些工程的設定修改,以及一系列的 next 按鈕點選操作,現在就讓這些操作都交給指令碼化吧。
-
指令碼化中使用如下的命令打包:
xcodebuild -project name.xcodeproj -target targetname -configuration Release -sdk iphoneos build CODE_SIGN_IDENTITY="$(CODE_SIGN_IDENTITY)" PROVISIONING_PROFILE="$(PROVISIONING_PROFILE)"
或者
xcodebuild -workspace name.xcworkspace -scheme schemename -configuration Release -sdk iphoneos build CODE_SIGN_IDENTITY="$(CODE_SIGN_IDENTITY)" PROVISIONING_PROFILE="$(PROVISIONING_PROFILE)"
-
然後使用 xcrun 生成 ipa 檔案:
`xcrun -sdk iphoneos -v PackageApplication ./build/Release-iphoneos/$(target|scheme).app"
-
清除 build 過程中產生的中間檔案
-
結合蒲公英分發平臺,將 ipa 檔案上傳至蒲公英分發平臺,同時在終端會列印上傳結果以及上傳應用後該應用的 URL。蒲公英分發平臺能夠方便地將 ipa 檔案儘快分發到測試人員,該平臺有開放 API,可避免人工上傳。
該指令碼的使用可使用 python autobuild.py -h 檢視,與 xcodebuild 的使用相似:
Usage: autobuild.py [options] Options: -h, --help: show this help message and exit -w name.xcworkspace, --workspace=name.xcworkspace: Build the workspace name.xcworkspace. -p name.xcodeproj, --project=name.xcodeproj: Build the project name.xcodeproj. -s schemename, --scheme=schemename: Build the scheme specified by schemename. Required if building a workspace. -t targetname, --target=targetname: Build the target specified by targetname. Required if building a project. -o output_filename, --output=output_filename: specify output filename
在指令碼頂部,有幾個全域性變數,根據自己的專案情況修改。
CODE_SIGN_IDENTITY = "iPhone Distribution: companyname (9xxxxxxx9A)"PROVISIONING_PROFILE = "xxxxx-xxxx-xxx-xxxx-xxxxxxxxx"CONFIGURATION = "Release"SDK = "iphoneos"USER_KEY = "15d6xxxxxxxxxxxxxxxxxx"API_KEY = "efxxxxxxxxxxxxxxxxxxxx"
其中,CODE_SIGN_IDENTITY 為開發者證書標識,可以在 Keychain Access -> Certificates -> 選中證書右鍵彈出選單 -> Get Info -> Common Name 獲取,類似 iPhone Distribution: Company name Co. Ltd (xxxxxxxx9A), 包括括號內的內容。
PROVISIONING_PROFILE: 這個是 mobileprovision 檔案的 identifier,獲取方式:
Xcode -> Preferences -> 選中申請開發者證書的 Apple ID -> 選中開發者證書 -> View Details... -> 根據 Provisioning Profiles 的名字選中打包所需的 mobileprovision 檔案 -> 右鍵選單 -> Show in Finder -> 找到該檔案後,除了該檔案字尾名的字串就是 PROVISIONING_PROFILE 欄位的內容。
當然也可以使用指令碼獲取, 此處參考命令列獲取mobileprovision檔案的UUID :
#!/bin/bashif [ $# -ne 1 ]then echo "Usage: getmobileuuid the-mobileprovision-file-path" exit 1fimobileprovision_uuid=`/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< $(/usr/bin/security cms -D -i $1)`echo "UUID is:"echo ${mobileprovision_uuid}
USER_KEY, API_KEY: 是蒲公英開放 API 的金鑰。
將autobuild.py指令碼放在你專案的根目錄下,進入根目錄,如下使用:
./autobuild.py -w yourname.xcworkspace -s schemename -o ~/Desktop/yourname.ipa
或者
./autobuild.py -p yourname.xcodeproj -t targetname -o ~/Desktop/yourname.ipa
該指令碼可在github 檢視,如有任何問題,請留言回覆。
常見問題:
-
找不到request module.
import requests ImportError: No module named requests
找不到request module,參考stackoverflow , 使用 $ sudo pip install requests或者sudo easy_install -U requests;
-
如果使用了上傳蒲公英,且安裝需要密碼,請開啟指令碼,搜一下腳本里的password,將其值設定為空。
========== update 2016-12-28 ==========
github上指令碼進行更新:
-
使用xcodebuild -exportArchive替換PackageApplication進行打包.
-
解析傳入引數使用argparse替換OptionParser.
-
去掉對PROVISIONING_PROFILE和CODE_SIGN_IDENTITY的配置,請使用Xcode8的自動證書管理。
-
新增exportOptions.plist檔案,用於設定匯出ipa檔案的引數,該檔案中的可配置引數可使用xcodebuild --help檢視。
-
指令碼傳入引數去掉--target和--output,ipa檔案預設會存放在Desktop建立諸如{scheme}{2016-12-28_08-08-10}格式的資料夾中。
假如你的專案目錄如下所示:
|____AOP | |____AppDelegate.h | |____AppDelegate.m | |____Base.lproj | | |____LaunchScreen.xib| | |____Main.storyboard | |____Images.xcassets | |____Info.plist | |____main.m | |____ViewController.h | |____ViewController.m |____AOP.xcodeproj|____autobuild | |____autobuild.py | |____exportOptions.plist
先進入autobuild目錄,使用指令碼打包的命令如下:
python autobuild.py -p ../AOP.xcodeproj -s AOP
指令碼執行完畢,若成功,則會在桌面生成ipa檔案。
若是打包xcworkspace專案,則打包命令格式如下所示:
python autobuild.py -w ../yourworkspace.xcworkspace -s yourscheme
exportOptions.plist檔案中的可選配置引數如下:
compileBitcode : BoolFor non-App Store exports, should Xcode re-compile the app from bitcode? Defaults to YES. embedOnDemandResourcesAssetPacksInBundle : BoolFor non-App Store exports, if the app uses On Demand Resources and this is YES, asset packs are embedded in the app bundle so that the app can be tested without a server to host asset packs. Defaults to YES unless onDemandResourcesAssetPacksBaseURL is specified. iCloudContainerEnvironmentFor non-App Store exports, if the app is using CloudKit, this configures the "com.apple.developer.icloud-container-environment" entitlement. Available options: Development and Production. Defaults to Development. manifest : DictionaryFor non-App Store exports, users can download your app over the web by opening your distribution manifest file in a web browser. To generate a distribution manifest, the value of this key should be a dictionary with three sub-keys: appURL, displayImageURL, fullSizeImageURL. The additional sub-key assetPackManifestURL is required when using on demand resources. method : String Describes how Xcode should export the archive. Available options: app-store, ad-hoc, package, enterprise, development, and developer-id. The list of options varies based on the type of archive. Defaults to development. onDemandResourcesAssetPacksBaseURL : StringFor non-App Store exports, if the app uses On Demand Resources and embedOnDemandResourcesAssetPacksInBundle isn't YES, this should be a base URL specifying where asset packs are going to be hosted. This configures the app to download asset packs from the specified URL. teamID : String The Developer Portal team to use for this export. Defaults to the team used to build the archive. thinning : String For non-App Store exports, should Xcode thin the package for one or more device variants? Available options:(Xcode produces a non-thinned universal app), (Xcode produces a universal app and all available thinned variants), or a model identifier for a specific device (e.g. "iPhone7,1"). Defaults to . uploadBitcode : Bool For App Store exports, should the package include bitcode? Defaults to YES. uploadSymbols : Bool For App Store exports, should the package include symbols? Defaults to YES.