三個模塊:
//代碼簽名授權 Code Signing Entitlements //代碼簽名身份 Code Signing Identity //描述文件/配置文件 Provisioning Profile
1.點擊這裡—-蘋果官網code sign guide
2.代碼簽名 (code signing) 和配置文件 (provisioning),是做iOS開發繞不過的坎,報錯的時候也是很不容易解決的,終究其原因,就是對蘋果為iOS開發設置的一整套安全機制理解不到位導致的,平時大家都集中時間處理開發中遇到的需求問題,在這裡投入的時間不夠,到時出現錯誤時,不曉得從哪裡下手
3.蘋果的很多東西都是閉源的,代碼簽名就是一個難以理解的神秘黑盒,我們無法直接看到代碼簽名的運作過程,它們隱藏在 iOS 系統內部和 SDK 之中.想要理解code sign的運作,就不得不了解證書和秘鑰了
作為一個 iOS 開發者,在你開發使用的機器上應該已經有一個證書,一個公鑰,以及一個私鑰。這些是代碼簽名機制的核心
打開–鑰匙串—我的證書
$ codesign -s 'iPhone Developer: [email protected] (4KPK36MFV)' Example.app如果你想為某一個 app 程序包重新設置簽名,那麼這個工具就很有用了。為了重新設置簽名,你必須帶上 -f 參數,有了這個參數,codesign 會用你選擇的簽名替換掉已經存在的那一個:
$ codesign -f -s 'iPhone Developer: [email protected] (4KPK36MFV)' Example.app
codesign 還可以為你提供有關一個可執行文件簽名狀態的信息,這些信息在出現不明錯誤時會提供巨大的幫助。舉例來說,$ codesign -vv -d Example.app 會列出一些有關 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: [email protected] (4KPK36MFV) '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 設置了簽名。在這裡當然是我的證書,iPhone Developer: [email protected] (4KPK36MFV)。我的這個證書則是被證書 Apple Worldwide Developer Relations Certification Authority 設置了簽名的,依此類推這個證書則是被證書 Apple Root CA 設置了簽名。
在 Format 中也包含了一些關於代碼的信息:Example.app 並不單單是一個可執行文件,它是一個程序包,其中包含了一個 arm64 二進制文件。從 Executable 中的路徑信息你可以看出,這是一個以測試為目的的打包,所以是一個 Mach-O thin 的二進制文件。
在一堆診斷信息中還包含了兩個非常有趣的條目。 Identifier 是我在 Xcode 中設置的 bundle identifier。 TeamIdentifier 用於標識我的工作組(系統會用這個來判斷應用是否是由同一個開發者發布)。此外用於發布應用的證書中也包含這種標識,這種標識在區分同一名稱下的不同證書時非常有用。
下面我們來檢查一下封印是否完好:
$ codesign --verify Example.app
原理理解:
即使你可以讓應用運行起來,在 iOS 上你的應用能做什麼依然是受限制的。這些限制是沙盒管理的。
沙盒和代碼簽名機制是不同的。代碼簽名保證了這個應用裡所包含的內容正如它所說的那樣不多不少,而沙盒則是限制了應用訪問系統的資源。
這兩種技術是相互合作來發揮作用的,它們都能阻止你的應用運行,也都能在 Xcode 中引起奇怪的問題。但是在日常開發過程中,沙盒可能會更經常引起問題。沙盒機制在什麼時候會引起問題呢,大多數情況下都是由於一個叫做授權的機制決定的。
授權機制決定了哪些系統資源在什麼情況下允許被一個應用使用。簡單的說它就是一個沙盒的配置列表,上面列出了哪些行為被允許,哪些會被拒絕。
很可能你已經猜到授權機制也是按照 plist 文件格式來列出的。Xcode 會將這個文件作為 –entitlements 參數的內容傳給 codesign ,這個文件內部格式如下:
application-identifier 7TPNXN7G6K.ch.kollba.example aps-environment development com.apple.developer.team-identifier 7TPNXN7G6K com.apple.developer.ubiquity-container-identifiers 7TPNXN7G6K.ch.kollba.example com.apple.developer.ubiquity-kvstore-identifier 7TPNXN7G6K.ch.kollba.example com.apple.security.application-groups group.ch.kollba.example get-task-allow
在 Xcode 的 Capabilities 選項卡下選擇一些選項之後,Xcode 就會生成這樣一段 XML。 Xcode 會自動生成一個 .entitlements 文件,然後在需要的時候往裡面添加條目。
當構建整個應用時,這個文件也會提交給 codesign 作為應用所需要擁有哪些授權的參考。這些授權信息必須都在開發者中心的 App ID 中啟用,並且包含在配置文件中。在構建應用時需要使用的授權文件可以在 Xcode build setting 中的 code signing entitlements 中設置。
$ codesign -d --entitlements - Example.app
會列出一個和前面的很像的 XML 格式的屬性列表。你可以將這個文件的內容添加進一個腳本,每次構建應用時用腳本檢查是否包含了推送服務的授權信息,以此確保推送服務工作正常。在這裡推送服務只是一個例子,你使用的服務越多,這樣的時候都添加推送通知的授權,以保證可以注冊推送通知。Xcode 6 之後,授權信息列表會以 Example.app.xcent 這樣的名字的文件形式包含在應用包中。
在整個代碼簽名和沙盒機制中有一個組成部分將簽名,授權和沙盒聯系了起來,那就是配置文件 (provisioning profiles)。
每一個 iOS 開發者可能都花費過相當的時間研究如何設置配置文件,這個環節也正是會經常出問題的地方。
一個配置文件中存放了系統用於判斷你的應用是否允許運行的信息,這就意味著如果你的配置文件有問題,修復起來會相當煩人。
一個配置文件是一組信息的集合,這組信息決定了某一個應用是否能夠在某一個特定的設備上運行。配置文件可以用於讓應用在你的開發設備上可以被運行和調試,也可以用於內部測試 (ad-hoc) 或者企業級應用的發布。Xcode 會將你在 project setting 中選擇的配置文件打包進應用。
我們下面來仔細研究一下配置文件。如果你要在自己的機器上找到配置文件,在這個目錄下 ~/Library/MobileDevice/Provisioning Profiles。Xcode 將從開發者中心下載的全部配置文件都放在了這裡。
配置文件並不是一個 plist 文件,它是一個根據密碼訊息語法 (Cryptographic Message Syntax) 加密的文件
采用 CMS 格式進行加密使得配置文件可以被設置簽名,所以在蘋果給你這個文件之後文件就不能被改變了。配置文件的簽名和應用的簽名不是一回事,它是由蘋果直接在開發者中心 (developer portal) 中設置好了的。
某些版本的 OpenSSL 可以讀取這種格式,但是 OS X 自帶那個版本並不行。幸運的是命令行工具 security 也可以解碼這個 CMS 格式,那麼我們就用 security 來看看一個 .mobileprovision 文件內部是什麼樣子:
$ security cms -D -i example.mobileprovision
這個命令會輸出簽名信息中的內容,接下來你會得到一個 XML 格式的 plist 文件內容輸出。
這個列表中的內容是 iOS 用於判斷你的應用是否能運行在某個設備上真正需要的配置信息,每一個配置文件都有它自己的 UUID 。Xcode 會用這個 UUID 來作為標識,記錄你在 build settings 中選擇了哪一個配置文件。
首先來看 DeveloperCertificates 這項,這一項是一個列表,包含了可以為使用這個配置文件的應用簽名的所有證書。如果你用了一個不在這個列表中的證書進行簽名,無論這個證書是否有效,這個應用都無法運行。所有的證書都是基於 Base64 編碼符合 PEM (Privacy Enhanced Mail, RFC 1848) 格式的。要查看一個證書的詳細內容,將編碼過的文件內容復制粘貼到一個文件中去,像下面這樣:
-----BEGIN CERTIFICATE----- MIIFnjCCBIagAwIBAgIIE/IgVItTuH4wDQYJKoZIhvcNAQEFBQAwgZYxCzA… -----END CERTIFICATE-----
可能會注意到在 Entitlements 一項中包含了你的應用的所有授權信息,這些授權信息是你在開發者中心下載配置文件時在 App ID 中設置的,理想的情況下,這個文件應該和 Xcode 為應用設置簽名時使用的那一個同步,但這種同步並不能得到保證。這個文件的不一致是比較難發現的問題之一。
舉例來說,如果你在 Xcode 中添加了 iCloud 鍵值對存儲授權 (com.apple.developer.ubiquity-kvstore-identifier),但是沒有更新,重新設置並下載新的配置文件,舊的配置文件規定你的應用並沒有這一項授權。那麼如果你的應用使用了這個功能,iOS 就會拒絕你的應用運行。這也是當你在開發者中心編輯了應用的授權,對應的配置文件會被標記為無效的原因。
如果你打開的是一個用於開發測試的證書,你會看到一項 ProvisionedDevices,在這一項裡包含了所有可以用於測試的設備列表。因為配置文件需要被蘋果簽名,所以每次你添加了新的設備進去就要重新下載新的配置文件。
代碼簽名和配置文件這一套大概是一個 iOS 開發者必須處理的僅次於編碼的最復雜的問題之一。
雖然了解每一個部分是怎麼運作的很有幫助,但是要控制好所有這些設置和工具其實是一件很消耗時間的事情,特別是在一個開發團隊中,到處發送證書和配置文件顯然很不方便。雖然蘋果在最近幾次發布的 Xcode 中都嘗試改善,但是我不是很確定每一項改動都起到了好的作用。處理代碼簽名是每個開發者必過的大坑。
雖然處理代碼簽名對於開發者來說非常繁瑣,但不可否認正是它使得 iOS 對於用戶來說是一個非常安全的操作系統。所以為代碼簽名和配置文件進行的這些麻煩設置並不是徒勞無功。