"用戶會感激代碼簽名帶來的好處" – Apple Developer Library: Code Signing Guide
在 iOS 或 OS X 平臺上進(jìn)行應(yīng)用開發(fā)時,你所需要使用的 API 大多設(shè)計得簡潔明了。你可以輕易地實(shí)現(xiàn)酷炫的動畫效果,便捷地進(jìn)行應(yīng)用發(fā)布前測試,或是用 Core Data 將數(shù)據(jù)安全的存儲在本地。但是總有一天,你會碰上代碼簽名 (code signing) 和配置文件 (provisioning),大多數(shù)情況下,這會是你在心里問候某些人祖宗的開始。
如果你已經(jīng)在 iOS 上開發(fā)過應(yīng)用,那么你多半已經(jīng)與代碼簽名或設(shè)備配置文件打過交道了。即使是 OS X 開發(fā)者,如果你想發(fā)布自己的應(yīng)用到 Mac App Store 上去或者想?yún)⑴c蘋果的開發(fā)者項目,那么也不得不開始為自己的代碼進(jìn)行簽名。
大多數(shù)時候代碼簽名看上去像是一個難以理解的神秘黑盒。在這篇文章里我會盡可能揭示盒子內(nèi)部的運(yùn)作機(jī)理。
通常來說,我們無法直接看到代碼簽名的運(yùn)作過程,它們隱藏在 iOS 系統(tǒng)內(nèi)部和 SDK 之中。但我們可以通過觀察設(shè)置代碼簽名所需工具的運(yùn)作方式,來找出一些線索。除此之外,我們還可以參考 OS X 上的代碼簽名運(yùn)作方式,畢竟 iOS 和 OS X 系出同源,我們可以從他們的對比之中得到很多有用的信息。
OS X 上代碼簽名技術(shù)和相應(yīng)的 API 是在 Mac OS X Leopard 10.5 上首次出現(xiàn)的,這剛好是第一臺 iPhone 發(fā)布的時候。這并非巧合,因?yàn)樵?iOS 上,代碼簽名起到的作用更加重要。iPhone 是在眾多游戲主機(jī)之后第一個大規(guī)模出售并且從頭就開始使用代碼簽名的計算平臺。只有在越獄之后,iOS 才能運(yùn)行沒有簽名的代碼。越獄使應(yīng)用可以繞過代碼簽名和沙盒安全機(jī)制的全部限制,這會是一個非常危險的行為。
作為一個 iOS 開發(fā)者,在你開發(fā)使用的機(jī)器上應(yīng)該已經(jīng)有一個證書,一個公鑰,以及一個私鑰。這些是代碼簽名機(jī)制的核心。像 SSL 一樣,代碼簽名也依賴于采用 X.509 標(biāo)準(zhǔn)的公開密鑰加密。
在 OS X 上,X.509 的基本組成部分(譯者注:例如證書等)都是由一個叫鑰匙串訪問的工具來進(jìn)行管理。打開你開發(fā)機(jī)器上的鑰匙串訪問應(yīng)用,選擇類別選項下的“我的證書(My Certificates)”,你可以看到所有你持有的私鑰相對應(yīng)的證書。要用一個證書設(shè)置代碼簽名,你必須擁有私鑰,所以所有你擁有私鑰的證書都會被列在這里。如果你擁有一個證書的私鑰,你可以展開證書并將它的私鑰顯示出來:
http://wiki.jikexueyuan.com/project/objc/images/17-1.png" alt="" />
如果你要導(dǎo)出證書,例如為了備份(強(qiáng)烈建議進(jìn)行),一定要記得展開證書那一條顯示出私鑰并將兩行都選中。
還有一種可以用來快速地顯示出你的系統(tǒng)中能用來對代碼進(jìn)行簽名的認(rèn)證的方法,那就是利用用途廣泛的命令行工具 security
:
$ security find-identity -v -p codesigning
1) 01C8E9712E9632E6D84EC533827B4478938A3B15 "iPhone Developer: Thomas Kollbach (7TPNXN7G6K)"
概括的講,一個證書是一個公鑰加上許多附加信息,這些附加信息都是被某個認(rèn)證機(jī)構(gòu)(Certificate Authority 簡稱 CA)進(jìn)行簽名認(rèn)證過的,認(rèn)證這個證書中的信息是準(zhǔn)確無誤的。對于 iOS 開發(fā)來說這個認(rèn)證機(jī)構(gòu)就是蘋果的認(rèn)證部門 Apple Worldwide Developer Relations CA。認(rèn)證的簽名有固定的有效期,這就意味著當(dāng)前系統(tǒng)時間需要被正確設(shè)置,因?yàn)樽C書是基于當(dāng)前時間進(jìn)行核對。這也是為什么將系統(tǒng)時間設(shè)定到過去會對 iOS 造成多方面破壞的原因之一。
http://wiki.jikexueyuan.com/project/objc/images/17-2.png" alt="" />
對于 iOS 開發(fā)來說,一般會有兩個證書:一個帶有前綴 iPhone Developer
,另一個帶有前綴 iPhone Distribution
。前者用于使應(yīng)用可以在你的測試設(shè)備上運(yùn)行,后者是在提交應(yīng)用到 APP store 時用到。一個證書的用途取決于它所包含的內(nèi)部信息,在鑰匙串訪問中雙擊打開一個證書文件,你可以看到許多詳細(xì)條目,拖動到最下面有一條標(biāo)記著 Apple Developer Certificate (Submission)
, 或者 Apple Developer Certificate (Development)
,具體你會看到哪一種,取決于你所打開的證書是哪一種類型,iOS 系統(tǒng)會利用這個信息來判斷你的應(yīng)用是運(yùn)行在開發(fā)模式下還是發(fā)布模式,并據(jù)此判斷以切換應(yīng)用運(yùn)行規(guī)則。
為了讓擁有公鑰的證書起作用,我們需要有私鑰。私鑰是你在為組成應(yīng)用的二進(jìn)制文件進(jìn)行簽名時派上用場的。沒有私鑰,你就無法用證書和公鑰對任何東西設(shè)置簽名。
簽名過程本身是由命令行工具 codesign
來完成的。如果你在 Xcode 中編譯一個應(yīng)用,這個應(yīng)用構(gòu)建完成之后會自動調(diào)用 codesign
命令進(jìn)行簽名,codesign
也正是給你提供了許多格式友好并且有用錯誤信息的那一個工具。你可以在 Xcode 的 project settings 中設(shè)置代碼簽名信息。
http://wiki.jikexueyuan.com/project/objc/images/17-3.png" alt="" />
需要注意的是 Xcode 只允許你在有限的選項中進(jìn)行選擇,這些選項都是你既擁有公鑰也擁有私鑰的證書。所以如果在選項中沒有出現(xiàn)你想要的那一個,那么你需要檢查的第一件事情就是你是否擁有這個證書的私鑰。在這里你需要區(qū)分開用于開發(fā)測試還是用于發(fā)布,如果你想要在機(jī)器上測試你的應(yīng)用,你需要用用于開發(fā)測試的那一對密匙來進(jìn)行簽名,如果你是要發(fā)布應(yīng)用,無論是給測試人員還是發(fā)布到 APP Store,你需要用用于發(fā)布的那一對密匙來進(jìn)行簽名。
一直以來,以上這些就是代碼簽名需要設(shè)置的全部,設(shè)置了這些就幾乎完成了。
但是在 Xcode 6 的 project settings 中出現(xiàn)了設(shè)置配置文件的選項。如果你選擇了某一個配置文件,你必須選擇這個配置文件的證書中所包含的公鑰所對應(yīng)的那個密匙對,或者你可以選擇讓 Xcode 自動完成正確的設(shè)置。關(guān)于這方面我們稍后再詳細(xì)說明,首先還是回到代碼簽名。
一個已簽名的可執(zhí)行文件的簽名包含在 Mach-O 二進(jìn)制文件格式中;對于例如腳本這樣的非 Mach-O 可執(zhí)行文件,就存放在該文件系統(tǒng)的的擴(kuò)展屬性中。這種做法使得在 OS X 和 iOS 上的任何可執(zhí)行二進(jìn)制文件都可以被設(shè)置簽名:不論是動態(tài)庫,命令行工具,還是 .app 后綴的程序包。這也意味著設(shè)置簽名的過程實(shí)際上會改動可執(zhí)行文件的文件內(nèi)容,將簽名數(shù)據(jù)寫入二進(jìn)制文件中。
如果你擁有一個證書和它的私鑰,那么用 codesign
來設(shè)置簽名非常簡單,我們現(xiàn)在嘗試用下面列出的這個證書來為 Example.app
設(shè)置簽名:
$ codesign -s 'iPhone Developer: Thomas Kollbach (7TPNXN7G6K)' Example.app
如果你想為某一個 app 程序包重新設(shè)置簽名,那么這個工具就很有用了。為了重新設(shè)置簽名,你必須帶上 -f
參數(shù),有了這個參數(shù),codesign
會用你選擇的簽名替換掉已經(jīng)存在的那一個:
$ codesign -f -s 'iPhone Developer: Thomas Kollbach (7TPNXN7G6K)' Example.app
codesign
還可以為你提供有關(guān)一個可執(zhí)行文件簽名狀態(tài)的信息,這些信息在出現(xiàn)不明錯誤時會提供巨大的幫助。舉例來說,$ codesign -vv -d Example.app
會列出一些有關(guān) Example.app
的簽名信息:
Executable=/Users/toto/Library/Developer/Xcode/DerivedData/Example-cfsbhbvmswdivqhekxfykvkpngkg/Build/Products/Debug-iphoneos/Example.app/Example
Identifier=ch.kollba.example
Format=bundle with Mach-O thin (arm64)
CodeDirectory v=20200 size=26663 flags=0x0(none) hashes=1324+5 location=embedded
Signature size=4336
Authority=iPhone Developer: Thomas Kollbach (7TPNXN7G6K)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=29.09.2014 22:29:07
Info.plist entries=33
TeamIdentifier=DZM8538E3E
Sealed Resources version=2 rules=4 files=120
Internal requirements count=1 size=184
你需要查看的第一件事是以 Authority
開頭的那三行。這三行告訴你到底是哪一個證書為這個 app 設(shè)置了簽名。在這里當(dāng)然是我的證書,iPhone Developer: Thomas Kollbach (7TPNXN7G6K)
。我的這個證書則是被證書 Apple Worldwide Developer Relations Certification Authority
設(shè)置了簽名的,依此類推這個證書則是被證書 Apple Root CA
設(shè)置了簽名。
在 Format
中也包含了一些關(guān)于代碼的信息:Example.app
并不單單是一個可執(zhí)行文件,它是一個程序包,其中包含了一個 arm64
二進(jìn)制文件。從 Executable
中的路徑信息你可以看出,這是一個以測試為目的的打包,所以是一個 Mach-O thin
的二進(jìn)制文件。
在一堆診斷信息中還包含了兩個非常有趣的條目。 Identifier
是我在 Xcode 中設(shè)置的 bundle identifier。 TeamIdentifier
用于標(biāo)識我的工作組(系統(tǒng)會用這個來判斷應(yīng)用是否是由同一個開發(fā)者發(fā)布)。此外用于發(fā)布應(yīng)用的證書中也包含這種標(biāo)識,這種標(biāo)識在區(qū)分同一名稱下的不同證書時非常有用。
現(xiàn)在這個二進(jìn)制文件已經(jīng)用證書設(shè)置好簽名。就像中世紀(jì)人用蠟來封印信封一樣,簽名就這樣封印了這個應(yīng)用。下面我們來檢查一下封印是否完好:
$ codesign --verify Example.app
$
就像大多數(shù) UNIX 工具一樣,沒有任何輸出代表簽名是完好的。那么我下面破壞這個封印,只要修改一下這個二進(jìn)制文件:
$ echo 'lol' >> Example.app/Example
$ codesign --verify Example.app
Example.app: main executable failed strict validation
修改已經(jīng)簽名的應(yīng)用會破壞封印,從命令行輸出我們可以看到代碼簽名正如我們所預(yù)期一樣起到了作用。
對于命令行工具和腳本來說,只是一個可執(zhí)行文件被設(shè)置簽名,但是 iOS 和 OS X 的應(yīng)用和框架則是包含了它們所需要的資源在其中的。這些資源包括圖片和不同的語言文件,資源中也包括很重要的應(yīng)用組成部分例如 XIB/NIB 文件,存檔文件(archives),甚至是證書文件。所以為一個程序包設(shè)置簽名時,這個包中的所有資源文件也都會被設(shè)置簽名。
為了達(dá)到為所有文件設(shè)置簽名的目的,簽名的過程中會在程序包中新建一個叫做 _CodeSignatue/CodeResources
的文件,這個文件中存儲了被簽名的程序包中所有文件的簽名。你可以自己去查看這個簽名列表文件,它僅僅是一個 plist 格式文件。
這個列表文件中不光包含了文件和它們的簽名的列表,還包含了一系列規(guī)則,這些規(guī)則決定了哪些資源文件應(yīng)當(dāng)被設(shè)置簽名。伴隨 OS X 10.10 DP 5 和 10.9.5 版本的發(fā)布,蘋果改變了代碼簽名的格式,也改變了有關(guān)資源的規(guī)則。如果你使用10.9.5或者更高版本的 codesign
工具,在 CodeResources
文件中會有4個不同區(qū)域,其中的 rules
和 files
是為老版本準(zhǔn)備的,而 files2
和 rules2
是為新的第二版的代碼簽名準(zhǔn)備的。最主要的區(qū)別是在新版本中你無法再將某些資源文件排除在代碼簽名之外,在過去你是可以的,只要在被設(shè)置簽名的程序包中添加一個名為 ResourceRules.plist
的文件,這個文件會規(guī)定哪些資源文件在檢查代碼簽名是否完好時應(yīng)該被忽略。但是在新版本的代碼簽名中,這種做法不再有效。所有的代碼文件和資源文件都必須設(shè)置簽名,不再可以有例外。在新版本的代碼簽名規(guī)定中,一個程序包中的可執(zhí)行程序包,例如擴(kuò)展 (extension),是一個獨(dú)立的需要設(shè)置簽名的個體,在檢查簽名是否完整時應(yīng)當(dāng)被單獨(dú)對待。
到目前為止,我們都假設(shè)所有的證書起到的作用都是一樣的,并且假設(shè)如果我們有了一個有效的證書代碼簽名也就相應(yīng)的有效。然而這當(dāng)然不是唯一的規(guī)則。操作系統(tǒng)有許多標(biāo)準(zhǔn)來檢測你的代碼是否允許運(yùn)行。
這些標(biāo)準(zhǔn)并不是一成不變的。舉例來說,在 OS X 上一個應(yīng)用是否允許被開啟是由 Gatekeeper 的選項決定的,你可以在系統(tǒng)設(shè)置的安全選項中改變選項。在 Gatekeeper 選項中選擇 “受信任的開發(fā)者或者來自 Mac App Store” 會要求被打開的應(yīng)用必須被證書簽名,可以是 Mac App Store 開發(fā)者的應(yīng)用發(fā)布證書也可以是開發(fā)者 ID 證書。這些選項是由一個系統(tǒng)工具 spctl
來管理的,它管理著系統(tǒng)的所有安全評估策略。
在 iOS 上規(guī)則是不一樣的,無論是用戶還是開發(fā)者都不能改變應(yīng)用開啟策略,你必須有一個開發(fā)者帳號或者應(yīng)用發(fā)布證書才能讓應(yīng)用運(yùn)行在 iOS 系統(tǒng)上。
即使你可以讓應(yīng)用運(yùn)行起來,在 iOS 上你的應(yīng)用能做什么依然是受限制的。這些限制是沙盒管理的。沙盒和代碼簽名機(jī)制是不同的,這很重要。代碼簽名保證了這個應(yīng)用里所包含的內(nèi)容正如它所說的那樣不多不少,而沙盒則是限制了應(yīng)用訪問系統(tǒng)的資源。這兩種技術(shù)是相互合作來發(fā)揮作用的,它們都能阻止你的應(yīng)用運(yùn)行,也都能在 Xcode 中引起奇怪的問題。但是在日常開發(fā)過程中,沙盒可能會更經(jīng)常引起問題。沙盒機(jī)制在什么時候會引起問題呢,大多數(shù)情況下都是由于一個叫做授權(quán)的機(jī)制決定的。
授權(quán)機(jī)制決定了哪些系統(tǒng)資源在什么情況下允許被一個應(yīng)用使用。簡單的說它就是一個沙盒的配置列表,上面列出了哪些行為被允許,哪些會被拒絕。
很可能你已經(jīng)猜到授權(quán)機(jī)制也是按照 plist 文件格式來列出的。Xcode 會將這個文件作為 --entitlements
參數(shù)的內(nèi)容傳給 codesign
,這個文件內(nèi)部格式如下:
<?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>application-identifier</key>
<string>7TPNXN7G6K.ch.kollba.example</string>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.team-identifier</key>
<string>7TPNXN7G6K</string>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>7TPNXN7G6K.ch.kollba.example</string>
</array>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>7TPNXN7G6K.ch.kollba.example</string>
<key>com.apple.security.application-groups</key>
<array>
<string>group.ch.kollba.example</string>
</array>
<key>get-task-allow</key>
<true/>
</dict>
</plist>
在 Xcode 的 Capabilities 選項卡下選擇一些選項之后,Xcode 就會生成這樣一段 XML。 Xcode 會自動生成一個 .entitlements
文件,然后在需要的時候往里面添加條目。當(dāng)構(gòu)建整個應(yīng)用時,這個文件也會提交給 codesign
作為應(yīng)用所需要擁有哪些授權(quán)的參考。這些授權(quán)信息必須都在開發(fā)者中心的 App ID 中啟用,并且包含在配置文件中,稍后我們會詳細(xì)討論這一點(diǎn)。在構(gòu)建應(yīng)用時需要使用的授權(quán)文件可以在 Xcode build setting 中的 code signing entitlements 中設(shè)置。
在這個應(yīng)用中我啟用了 iCloud 鍵值對存儲 (key-value storage) (com.apple.developer.ubiquity-kvstore-identifier
) ,以及 iCloud 文檔存儲 (com.apple.developer.ubiquity-container-identifiers
)。另外我還將應(yīng)用添加進(jìn)了一個 App Group (比如說為了與擴(kuò)展 (extensions) 共享數(shù)據(jù),com.apple.security.application-groups
), 最后開啟了推送功能 (aps-environment
)。這是一個開發(fā)版本,我會有將它連接到調(diào)試器的需求,這就需要將 get-task-allow
設(shè)為 true
。另外,app id,也就是 bundle id 加上開發(fā)者 id,也被單獨(dú)列出來了。
當(dāng)然你并不能隨心所欲的取得授權(quán),你的應(yīng)用能否得到某一項授權(quán)是有特定的規(guī)定的。舉例來說,當(dāng) get-task-allow
被設(shè)定為 ture
時,應(yīng)用只能在用于開發(fā)的證書簽名下運(yùn)行。你被允許使用的推送環(huán)境 (aps-environment) 也存在類似的限制。
根據(jù)操作系統(tǒng)版本的不同我們可選的授權(quán)項目是不一樣的,所以很難有一份列表可以詳盡地列出所有條目。至少在文檔 Adding Capabilities 中提到的所有功能都是需要經(jīng)過授權(quán)的。
授權(quán)信息會被包含在應(yīng)用的簽名信息中。如果你在這方面遇到了問題,可以嘗試查看簽名信息中具體包含了什么授權(quán)信息:$ codesign -d --entitlements - Example.app
會列出一個和前面的很像的 XML 格式的屬性列表。你可以將這個文件的內(nèi)容添加進(jìn)一個腳本,每次構(gòu)建應(yīng)用時用腳本檢查是否包含了推送服務(wù)的授權(quán)信息,以此確保推送服務(wù)工作正常。在這里推送服務(wù)只是一個例子,你使用的服務(wù)越多,這樣的時候都添加推送通知的授權(quán),以保證可以注冊推送通知。在新版本的 Xcode 6 之后,授權(quán)信息列表會以 Example.app.xcent
這樣的名字的文件形式包含在應(yīng)用包中。在我看來,這么做是為了在出現(xiàn)配置錯誤時提供更加有用的錯誤信息。
在整個代碼簽名和沙盒機(jī)制中有一個組成部分將簽名,授權(quán)和沙盒聯(lián)系了起來,那就是配置文件 (provisioning profiles)。
每一個 iOS 開發(fā)者可能都花費(fèi)過相當(dāng)?shù)臅r間研究如何設(shè)置配置文件,這個環(huán)節(jié)也正是會經(jīng)常出問題的地方。
一個配置文件中存放了系統(tǒng)用于判斷你的應(yīng)用是否允許運(yùn)行的信息,這就意味著如果你的配置文件有問題,修復(fù)起來會相當(dāng)煩人。
一個配置文件是一組信息的集合,這組信息決定了某一個應(yīng)用是否能夠在某一個特定的設(shè)備上運(yùn)行。配置文件可以用于讓應(yīng)用在你的開發(fā)設(shè)備上可以被運(yùn)行和調(diào)試,也可以用于內(nèi)部測試 (ad-hoc) 或者企業(yè)級應(yīng)用的發(fā)布。Xcode 會將你在 project setting 中選擇的配置文件打包進(jìn)應(yīng)用。前面提到了,選擇配置文件是 Xcode 6 才提供的功能,在 Xcode 5 或更早版本中,配置文件是 Xcode 根據(jù)你選擇的簽名證書來選擇的。事實(shí)上同一個證書可以擁有多個不同的配置文件,因此讓 Xcode 自行選擇可能存在一些不確定性,最好的方式是你自主去選擇,在 Xcode 6 中終于提供了這個功能。
http://wiki.jikexueyuan.com/project/objc/images/17-4.png" alt="" />
我們下面來仔細(xì)研究一下配置文件。如果你要在自己的機(jī)器上找到配置文件,在這個目錄下 ~/Library/MobileDevice/Provisioning Profiles
。Xcode 將從開發(fā)者中心下載的全部配置文件都放在了這里。
不要驚訝,配置文件并不是一個 plist 文件,它是一個根據(jù)密碼訊息語法 (Cryptographic Message Syntax) 加密的文件(下文中會簡稱 CMS,但不要用這個簡寫 Google,這不是一個很好的關(guān)鍵字)。如果你處理過 S/MIME 郵件或者證書你會對這種加密比較熟悉,詳細(xì)信息可以查看互聯(lián)網(wǎng)工程任務(wù)組 (IETF) 制定的 RFC 3852。
采用 CMS 格式進(jìn)行加密使得配置文件可以被設(shè)置簽名,所以在蘋果給你這個文件之后文件就不能被改變了。配置文件的簽名和應(yīng)用的簽名不是一回事,它是由蘋果直接在開發(fā)者中心 (developer portal) 中設(shè)置好了的。
某些版本的 OpenSSL 可以讀取這種格式,但是 OS X 自帶那個版本并不行。幸運(yùn)的是命令行工具 security
也可以解碼這個 CMS 格式,那么我們就用 security
來看看一個 .mobileprovision
文件內(nèi)部是什么樣子:
$ security cms -D -i example.mobileprovision
這個命令會輸出簽名信息中的內(nèi)容,如果你親自試一下,接下來你會得到一個 XML 格式的 plist 文件內(nèi)容輸出。
這個列表中的內(nèi)容是 iOS 用于判斷你的應(yīng)用是否能運(yùn)行在某個設(shè)備上真正需要的配置信息,每一個配置文件都有它自己的 UUID
。Xcode 會用這個 UUID
來作為標(biāo)識,記錄你在 build settings 中選擇了哪一個配置文件。
首先來看 DeveloperCertificates
這項,這一項是一個列表,包含了可以為使用這個配置文件的應(yīng)用簽名的所有證書。如果你用了一個不在這個列表中的證書進(jìn)行簽名,無論這個證書是否有效,這個應(yīng)用都無法運(yùn)行。所有的證書都是基于 Base64 編碼符合 PEM (Privacy Enhanced Mail, RFC 1848) 格式的。要查看一個證書的詳細(xì)內(nèi)容,將編碼過的文件內(nèi)容復(fù)制粘貼到一個文件中去,像下面這樣:
-----BEGIN CERTIFICATE-----
MIIFnjCCBIagAwIBAgIIE/IgVItTuH4wDQYJKoZIhvcNAQEFBQAwgZYxCzA…
-----END CERTIFICATE-----`
然后讓 OpenSSL 來處理 openssl x509 -text -in file.pem
。
回到配置文件中繼續(xù)往下看,你可能會注意到在 Entitlements
一項中包含了你的應(yīng)用的所有授權(quán)信息,鍵值就和之前在授權(quán)那節(jié)看到的一模一樣。
這些授權(quán)信息是你在開發(fā)者中心下載配置文件時在 App ID 中設(shè)置的,理想的情況下,這個文件應(yīng)該和 Xcode 為應(yīng)用設(shè)置簽名時使用的那一個同步,但這種同步并不能得到保證。這個文件的不一致是比較難發(fā)現(xiàn)的問題之一。
舉例來說,如果你在 Xcode 中添加了 iCloud 鍵值對存儲授權(quán) (com.apple.developer.ubiquity-kvstore-identifier
),但是沒有更新,重新設(shè)置并下載新的配置文件,舊的配置文件規(guī)定你的應(yīng)用并沒有這一項授權(quán)。那么如果你的應(yīng)用使用了這個功能,iOS 就會拒絕你的應(yīng)用運(yùn)行。這也是當(dāng)你在開發(fā)者中心編輯了應(yīng)用的授權(quán),對應(yīng)的配置文件會被標(biāo)記為無效的原因。
如果你打開的是一個用于開發(fā)測試的證書,你會看到一項 ProvisionedDevices
,在這一項里包含了所有可以用于測試的設(shè)備列表。因?yàn)榕渲梦募枰惶O果簽名,所以每次你添加了新的設(shè)備進(jìn)去就要重新下載新的配置文件。
代碼簽名和配置文件這一套大概是一個 iOS 開發(fā)者必須處理的僅次于編碼的最復(fù)雜的問題之一。與在 Mac 或 PC 上直接的編譯運(yùn)行你的代碼不同,處理這些問題會是非常不同的經(jīng)歷。
雖然了解每一個部分是怎么運(yùn)作的很有幫助,但是要控制好所有這些設(shè)置和工具其實(shí)是一件很消耗時間的事情,特別是在一個開發(fā)團(tuán)隊中,到處發(fā)送證書和配置文件顯然很不方便。雖然蘋果在最近幾次發(fā)布的 Xcode 中都嘗試改善,但是我不是很確定每一項改動都起到了好的作用。處理代碼簽名是每個開發(fā)者必過的大坑。
雖然處理代碼簽名對于開發(fā)者來說非常繁瑣,但不可否認(rèn)正是它使得 iOS 對于用戶來說是一個非常安全的操作系統(tǒng)。如果你注意安全相關(guān)的新聞,每一次出現(xiàn)號稱能在 iOS 上運(yùn)行的木馬或者惡意軟件,例如不怎么出名的 FinFisher,仔細(xì)看看詳細(xì)說明,都會寫明 “需要越獄”。說實(shí)話我還沒見過面向 iOS 的不需要越獄的病毒或者木馬。
所以為代碼簽名和配置文件進(jìn)行的這些麻煩設(shè)置并不是徒勞無功。