![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnaugzX0V2ajFGcvRXdh9CX0V2ajFGcvRXdh9CXn1WavwVZt5SY05WZpZnL3d3dvw1LcpDc0RHaiojIsJye.jpg)
網上有大把的文章講了自動打包,其實無非就是那幾條指令,但是我覺得有必要繼續了解一下一個app包(即應用)的組成和app可執行檔案的建構過程。這個裡面非常複雜,也參考了一些文章,僅将自己了解的大概梳理出來備忘。
應用的建構過程群組成
想象一下平時的打包過程,在Xcode中選擇對應的appid,bundleid,還要選擇正确的配置檔案(provisioning profile),然後點選
run
,我們看到Xcode上面有内容在不斷的更新,正如猜想的,更新的内容實際就是app包編譯的過程。
這個過程大概經過了:配置(編譯器确定目前系統環境)-> 确定标準庫和頭檔案的位置->确定依賴關系->頭檔案預編譯(precompilation)->預處理(preprocessing)->編譯(compilation)->連接配接(Linking)->打包,大緻步驟是這些,但其中還有一些過程是沒有講的。
對于iOS的包來講,在建構完成之後還會自動調用
codesign
指令進行簽名,這個時候我們之前選擇的bundleid啊,配置檔案啊等等就排上用場了。經過簽名後的應用是個相對來講安全的應用,通過簽名確定了包的來源合法,也能確定包的内容是否被修改過(理論知識上篇已講過)。最後的包的本質實際上是一個Mach-O格式的二進制可執行檔案(簽名的資料就在這個二進制檔案中)和一些資源檔案。
Mach-O可執行檔案
Mach是一種作業系統核心。它的大緻曆史是:Mach核心被NeXT公司的NeXTSTEP作業系統使用,NeXT是喬布斯蘋果被趕出蘋果後建立的公司。1996年,喬布斯将NeXTSTEP帶回蘋果,成為了OS X的核心基礎。在Mach上,一種可執行的檔案格是就是Mach-O(Mach Object file format)。iOS是從OS X演變而來,是以同樣支援Mach-O格式的可執行檔案。
搞iOS的肯定知道ipa包,它實際上就是一個zip壓縮包,可以用mac自帶的歸檔解壓工具進行解壓。解壓之後會有一個
Payload
檔案夾,其中有個
XXX.app
這樣的
.app
檔案,它實際上是檔案夾,它裡面除了有個各種資源、圖檔等,還有個和包名相同的檔案——這個就是二進制可執行檔案。可以用
file
指令檢視檔案類型,下圖是微信包的截圖:
從上面看是支援arm7和arm64兩種處理器架構的通用程式包,裡面的格式是Mach-O。将微信的可執行檔案
WeChat
用Sublime打開,二進制開始部分如下:
開頭的4個位元組是cafebabe,這被稱為“魔數”,反映檔案的類型。查了下相關文章,OS X上還有如下幾個辨別:
cafebabe
feedface
feadfacf
還有一個格式,就是以#!開頭的腳本
cafebabe就是跨處理器架構的通用格式,feedface和feedfacf則分别是某一處理器架構下的Mach-O格式,腳本的就很常見了,比如#!/bin/bash開頭的shell腳本。
Mach-O可執行檔案包含頭部資訊和加載指令。才疏學淺,這部分也沒有深入了解,本篇也無法繼續深入講這塊了。
其他資源檔案
解壓後的包中除了可執行檔案還有其他資源檔案,圖檔啊,plist啊等等。蘋果對安全确實重視,這些資源檔案其實大多數也是需要被設定簽名的,可以見到的是包中還有一個
_CodeSignature
檔案夾,這個檔案夾中的
CodeResources
檔案中存儲了被簽名的程式包中所有需要被簽名檔案的簽名。更詳細的介紹參見《代碼簽名探析》,從這些細節不難看出蘋果對于安全的重視。
自動打包
蘋果自帶的xcodebuild指令行工具就可以打包,但是這裡我更加推薦facebook出品的xctool,xctool的初衷就是要替代蘋果的xcodebuild,它們的指令參數都是一樣的,相比較xcodebuild,xctool有以下特點:
1.相比較xcodebuild輸出的log雜亂,xctool更有結構
2.xctool有人性化的顔色輸出
3.facebook聲稱xctool更快,據說能快2、3倍
4.完全用Ojbective-C實作
當然xctool隻支援Xcode6及以上,并且
Xcode Command Line Tools
安裝好。
xctool
xctool是可以使用homebrew安裝的,或者下源碼然後運作
xctool.sh
腳本,homebrew安裝指令如下:
brew install xctool
實戰
接下來是實戰篇,按照我的設想,如果想要實作自動化,需要攻克幾個點:
1.自動打包
2.重新簽名
3.分發部署
其中,自動打包是基礎,打包完之後可以根據母包重新簽名生成相似的包,生成的包可以自動部署。隻要攻克這三個點就能實作全自動化,當然就需要寫腳本了,帶着這個性質我參考了一些文章并且在網上找到了一些腳本。最終,驗證了這些東西都是實際可行的。但,下面的實戰用到的腳本,一部分是網上找的,一部分是同僚寫的,當時雖然逐個研究了但是卻沒有精力在這個上,這部分的工作最後是同僚做的。
為了講的更清楚,建立了一個項目
PackageExample
(Demo已上傳到這裡),并且使用了CocoaPods(實驗起見僅引用了AFNetworking),項目的證書是dev狀态的。
PackageExample
項目在我機器上的路徑和目錄如下截圖:
和
PackageExample
同目錄的還有
PackageShell
,裡面的
buildipa.sh
為編譯腳本,由于最後的目标是要做成可以随意配置的,是以還有一個
PackageConfig
檔案夾,裡面有配置檔案
packageExample.mobileprovision
和
packageExample.plist
,配置檔案主要用來簽名,plist檔案的内容為可配置的,例如裡面有app_Prefix、app_Name、app_ID等資訊。
Package
檔案夾為打的包的存放的地方。
完整的編譯腳本如下:
#!/bin/sh
#從plist檔案中讀取ipa包名和配置檔案名
profile_Name=`/usr/libexec/PlistBuddy -c "print profile_Name" ./PackageConfig/packageExample.plist`
ipa_Name=`/usr/libexec/PlistBuddy -c "print app_Name" ./PackageConfig/packageExample.plist`
#進入工程目錄
cd ../PackageExample
echo "go to packageExample workspace path"
#報名時根據時間戳命名的,是以這裡有用到
buildTime=$(date +%Y%m%d%H%M)
profile="${profile_Name}"
echo $profile $ipa_Name
#一下方法主要是建立打包的路徑和最後導出的ipa的路徑
if [ ! -d "../PackageShell/Package" ]; then
mkdir ../PackageShell/Package
fi
if [ ! -d "../PackageShell/Package/ArchiveProduction" ]; then
mkdir ../PackageShell/Package/ArchiveProduction
fi
if [ ! -d "../PackageShell/Package/ArchiveProduction/QA" ]; then
mkdir ../PackageShell/Package/ArchiveProduction/QA
echo "Create ArchiveProduction path"
fi
if [ ! -d "../PackageShell/Package/ipa" ]; then
mkdir ../PackageShell/Package/ipa
fi
if [ ! -d "../PackageShell/Package/ipa/QA" ]; then
mkdir ../PackageShell/Package/ipa/QA
echo "Create ipa path"
fi
buildConfiguration="QA"
buildPath="../PackageShell/Package/ArchiveProduction/QA/${ipa_Name}_${buildTime}.xcarchive"
ipaName="../PackageShell/Package/ipa/QA/${ipa_Name}_${buildTime}.ipa"
#先進行clean操作
xctool -workspace PackageExample.xcworkspace -scheme PackageExample -configuration ${buildConfiguration} clean
#打包的指令
xctool -workspace PackageExample.xcworkspace -scheme PackageExample -configuration ${buildConfiguration} archive -archivePath ${buildPath}
#導出ipa包的指令,
xcodebuild -exportArchive -exportFormat IPA -archivePath ${buildPath} -exportPath ${ipaName} -exportProvisioningProfile "$profile"
做一些解釋,腳本的開頭有
PlistBuddy
指令,它是Mac下一個用來讀寫plist檔案的工具,在/usr/libexec/下。
xctool -workspace PackageExample.xcworkspace -scheme PackageExample -configuration ${buildConfiguration} clean
,由于項目是workspace,是以這裡必須要對應,如果是project則是project,clean的目的是進行清理緩存等。
xctool -workspace PackageExample.xcworkspace -scheme PackageExample -configuration ${buildConfiguration} archive -archivePath ${buildPath}
,
archive
指令主要用來打包,最後包的格式為
xcarchive
。可以進入這個包裡,目錄結構如圖:
主要是産生了
dsYM
和
.app
檔案,并且可以看到的是它是已經經過簽名的。雖然從指令中沒有指定profile,但是我看到編譯的log輸出有以下這段:
由
Sign PackageExample.app
,推測這步是進行簽名了,至于為什麼指令中沒有指定也可以編譯那是因為在Xcode中進行過手動設定(?:猜測是)。最後一步導入ipa主要用
xcodebuild
指令,至少在當時我找到的是這個指令而不是xctool。經過導出的ipa包,簡單點的,可以郵件群發給同僚進行測試。
小結
至此,差不多介紹完自動打包的一種方案。但其實還可以延伸,主要反映在兩點上:
1.雖然能夠成功打一個包,但是本系列文章第一篇開始部分中提到的,如何快速複制兩個很相似但又不同的包?
2.導出來的ipa包,用郵件群發是否仍然麻煩,能否繼續實作自動化?
上面的兩點實際上都能很好的解決,也就是前面說到的要攻克
2.重新簽名
和
3.分發部署
,下篇文章會介紹我的解決思路,裡面涉及重新簽名和一些上傳工具。
轉載于:https://my.oschina.net/hejunbinlan/blog/721184