注:此文現在已經落伍,iOS自動化打包持續集成構建推薦使用 Fastlane + Jenkins。
作為開發人員,免不了要為測試人員打包,讓其測試。而打包這個行為是非常無聊的,特別是在每個新版本上線前一兩天,總會出現一些莫名其妙的bug
,然后這兩天打包活動也是特別頻繁。一天要重復好幾次同樣的動作,作為一個程序員,去做這樣的事情,是完全無法容忍的。自動化打包
,好在有你。所以今天就來談一談iOS應用自動化打包
,但是本篇文章主要談的是打單一的測試包,并不是在講持續集成
。
xcodebuild & xcrun
Xcode
提供了一套構建打包的命令,就是xcodebuild
和xcrun
。xcodebuild
將對應的項目打包成.app
文件,xcrun
將對應的.app
文件轉換為對應的.ipa
文件。了解這兩套命令可以查看對應的 xcodebuild官方文檔、xcrun官方文檔 ,或者在終端輸入man xcodebuild
及man xcrun
命令,查看對應的man page
。下面挑出來這兩個命令的一部分為例大致介紹一下他們的使用方法。
xcodebuild
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
以上命令中最常用的應該就是SYNOPSIS
中的前三行,其中分別對應.project
和.xcworkspace
類型的工程。除了這三個,我先講一下第七行的xcodebuild -list
這個命令。
xcodebuild -list命令介紹
以我們自己的工程為例在終端切入到工程文件夾,然后使用xcodebuild -list
這個命令輸出信息為:
Information about project "yeemiao":
Targets:
yeemiao
yeemiao-inhouse
yeemiaoTests
yeemiaoInhouseTests
Build Configurations:
Debug
Release
If no build configuration is specified and -scheme is not passed then "Release" is used.
Schemes:
yeemiao
yeemiao-inhouse
-
Targets:
我們的工程有四個Targets
,yeemiao
是發布App Store
的,yeemiao-inhouse
是對應的測試版本,下面兩個則是對應的性能測試。 -
Build Configurations:
由于我們在Targets中區分了測試版和正式版,這里面就沒有在添加一個Build Configurations
,而是系統默認的兩個Debug
和Release
版本。 -
Schemes:
上面顯示的兩個Schemes
默認是.xcodeproj
的,如果你使用xcodebuild -list -workspace yeemiao.xcworkspace
去查看就能看到第三方庫對應的Schemes
.
xcodebuild前三行命令介紹
了解了以上三個知識,在來看SYNOPSIS
中的前三行命令就很容易理解了
-
-project -workspace
:這兩個對應的就是項目的名字也就是說哪一個工程要打包。如果有多個工程,這里又沒有指定,則默認為第一個工程。 -
-target
:打包對應的targets,如果沒有指定這默認第一個。 -
-configuration
:如果沒有修改這個配置,默認就是Debug和Release這兩個版本,沒有指定默認為Release版本。 -
buildsetting=value ...
:使用此命令去修改工程的配置。但是在實際應用中,我選擇了讀取文件去修改一個配置,而沒有應用此種方法。 -
-scheme
:指定打包的scheme。
一個Demo的簡單使用
在進入實際的使用之前,先用一個簡單的Demo
演示一下。
首先創建一個工程命名為Toyun
,然后確保此工程可以真機調試。打開終端進入Toyun
這個工程下,然后運行以下命令:
xcodebuild -project Toyun.xcodeproj -target Toyun -configuration Release
此行命令的意思是將Toyun
這個工程targets
對應的也是Toyun
,打包成Release
版本。當終端出現** BUILD SUCCEEDED **
字樣時,表示成功。這時候在去Toyun
這個工程的文件夾下,你會發現多了一個名為build
的文件夾,此下面兩個子文件夾,Release-iphoneos
和Toyun.build
。Release-iphoneos
文件夾下有Toyun.app
這個文件。這就是xcodebuild
命令的作用,最終生成.app
文件。但是我們需要的是.ipa
文件,這時在終端下面執行此行命令
xcrun -sdk iphoneos -v PackageApplication ./build/Release-iphoneos/Toyun.app -o ~/Desktop/Toyun.ipa
此行命令的意思為,將Release-iphoneos
文件夾下的Toyun.app
文件轉換為Toyun.ipa
文件并且放在桌面上。iphoneos
是使用的sdk
,PackageApplication
為使用的開發者工具。此時你回到桌面可以看到Toyun.ipa
文件,則為成功。
實際使用自動化打包
通過上面簡單Demo
的練習,我們已經可以使用短短的兩行命令來打出我們需要的.ipa文件
了。但是這據我們實際使用還有一段距離,在實際應用中情況復雜多變。這里以我們自己的打測試包的過程為例來說明實際中的一些情況。我寫此自動化打包程序選的是Shell腳本
,當然你也可以選擇其他的語言去寫。
打包流程
首先說一下我們打包的流程。先從svn
上拉取最新的代碼,然后修改對應的測試版本號,選擇對應的證書和描述文件然后開始archive打包
,打包完成后,需要export
出對應的ipa文件
,而且我們下載安裝包使用了itms-services協議
,這個時候就要去修改導出來的測試包包名和協議相關的.plist文件
。然后上傳到服務器,這時測試根據協議生成的鏈接去下載對應的測試包開始測試。這個整套流程走下來,大概需要10分鐘。
將打包流程準換為腳本語言
#! /bin/bash
# 傳入這次的版本號
version_string=$1
# build號 我們是使用前時間作為build號的 2016041517 即為16年4月15號17點
build_number=$(date +%Y%m%d%H)
# 清空上一次的文件夾
rm -rf ~/Desktop/project
# 創建要工作的文件夾
mkdir ~/Desktop/project
# 進入要工作的文件夾
cd ~/Desktop/project
# 去svn上拉取最新的代碼 如果你們使用的git或其他版本控制則修改對應的拉取代碼命令即可
svn export svn://
# 下面是一些用到的變量給抽取出來了
# 工程環境路徑
workspace_path=~/Desktop/project/yeemiao2016/yeemiao
# 打包項目名字
scheme_name=yeemiao-inhouse
# 打包使用的證書
CODE_SIGN_IDENTITY="替換為你們的證書名字"
# 打包使用的描述文件 這描述文件的名字不是自己命名的那個名字,而是對應的8b11ac11-xxxx-xxxx-xxxx-b022665db452這個名字
PROVISIONING_PROFILE="替換為你們的描述文件的名字"
# 指定yeemiao.app的輸出位置 也就是Demo中build文件夾的位置
build_path=~/Desktop/project/build
# 指定yeemiao.ipa的輸出位置
ipa_path=~/Desktop/project
# info.plist文件的位置
info_plist=~/Desktop/project/yeemiao2016/yeemiao/yeemiaoInhouse-Info.plist
# 下面是讀取.plist文件的位置然后修改版本號和build號,這點沒有使用xcodebuild提供的命令,在上面也有敘述
# 修改版本號
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $version_string" ${info_plist}
# 修改build號
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $build_number" ${info_plist}
# 生成yeemiao.app, 在build_path路徑下面
xcodebuild -workspace ${workspace_path}.xcworkspace -scheme ${scheme_name} -configuration Release clean -sdk iphoneos build CODE_SIGN_IDENTITY="${CODE_SIGN_IDENTITY}" PROVISIONING_PROFILE="${PROVISIONING_PROFILE}" SYMROOT="${build_path}"
# 生成yeemiao.ipa, 在ipa_path路徑下面
xcrun -sdk iphoneos -v PackageApplication ${build_path}/Release-iphoneos/yeemiao.app -o ${ipa_path}/yeemiao_ios_${version_string}.ipa
# itms-services協議需要使用的.plist文件的位置
plist_path=~/Desktop/project/yeemiao_ios_${version_string}.plist
# 生成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>替換對應的路徑</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>com.threegene.yeemiao.inhouse</string>
<key>bundle-version</key>
<string>1.0.0</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>小豆苗</string>
</dict>
</dict>
</array>
</dict>
</plist>
EOF
# .ipa文件的位置
ipa_file_path=~/Desktop/project/yeemiao_ios_${version_string}.ipa
# .plist文件的位置
plist_file_path=~/Desktop/project/yeemiao_ios_${version_string}.plist
# 這里就要把.ipa和.plist文件上傳到對應的服務器上,當然這一步也是可以使用命令來完成的。
# 這里要看你們要把測試包上傳到哪兒,Fir、蒲公英、七牛等一般都提供了命令上傳文件的方式。
# 如果需要修改數據庫中測試包的指向,也可以開一個網絡請求接口然后使用curl命令共同集成到測試包中。
# 同樣可以增加一些判斷(判斷需要上次的文件存在不存在)和一些Log輸出來讓此腳本更為清晰安全和準確。
腳本最終完善之后,就可以敲一下enter鍵
,整個打包過程就完成了。比我我給這段程序命名為autoArchive.sh
。然后我在打包的時候只需要在終端輸入命令:
~ ./autoArchive.sh 3.0.0000
其他
在寫此腳本的時候也遇到了一些問題,其中一個就是當時我們的xcshareddata數據
是沒有提交到svn
上的,然后在指向打包命令那一行,腳本就會卡死不動。后來提交了xcshareddata
,此問題也就好了。
網絡上也有對自動化打包進行的各種封裝,其中比較出名的就是facebook出的xctool。這個工具規范了輸出的log日志
,而且一些錯誤信息也更為清晰一些。還是可以安裝體驗一下的。