本文從屬於筆者的iOS入門與最佳實踐系列文章,最近又被AppStore提交審覈搞的要死要死的,因此在本文略作總結。html
AppStore的證書與綁定機制對於筆者感受仍是蠻複雜的,不過流程多走即使可能就會清晰不少。首先須要明白的是,在蘋果的證書體系中,Certificates與Identifiers是相互獨立的,筆者以前常常有個疑問就是最先提交某個APP審覈的開發者的P12丟失了,那後續從新申請的證書還能夠用於提交後續版本嗎?答案確定是能夠的。通常來講,某個Certificates+Identifiers會獲得一個MobileProvision文件,而該文件就是在進行本地開發、打包上傳時所必須的。
iOS有兩種證書和描述文件:git
證書類型 | 使用場景 |
---|---|
開發(Development)證書和描述文件 | 用於開發測試 |
發佈(Distribution)證書和描述文件 | 用於提交Appstore |
在蘋果官方的開發者計劃(Apple Developer Member Center)層面,App ID 即 Product ID,用於標識一個或者一組 App。github
在 Mac/iOS 開發語境中,bundle(捆綁) 是指一個內部結構按照標準規則組織的特殊目錄。在 Mac OS 應用程序目錄下的某個 *.app 上可右鍵顯示包內容(Contents),其本質上就是可執行二進制文件(MacOS/)及其資源(Resources/)的打包組合。所以,在 Xcode 中配置的 Bundle Identifier 必須和 App ID 是一致的(Explicit)或匹配的(Wildcard)。安全
App ID 字符串一般以反域名(reverse-domain-name)格式的 Company Identifier(Company ID)做爲前綴(Prefix/Seed),通常不超過 255 個 ASCII 字符。服務器
App ID 全名會被追加 Application Identifier Prefix(通常爲 TeamID.),分爲兩類:網絡
Explicit App ID:惟一的 App ID,用於惟一標識一個應用程序。例如「com.apple.garageband」這個 App ID,用於標識 Bundle Identifier 爲「com.apple.garageband」的 App。app
Wildcard App ID:含有通配符的 App ID,用於標識一組應用程序。例如「」(其實是 Application Identifier Prefix)表示全部應用程序;而「com.apple.」能夠表示 Bundle Identifier 以「com.apple.」開頭(蘋果公司)的全部應用程序。dom
用戶可在 Developer Member Center 網站上註冊(Register)或刪除(Delete)已註冊的 App IDs。App ID 被配置到【XcodeTarget|Info|Bundle Identifier】下;對於 Wildcard App ID,只要 bundle identifier 包含其做爲 Prefix/Seed 便可。
iOS 證書是用來證實 iOS App 內容(bundle with executable and resources)的合法性和完整性的數字證書。對於想安裝到真機或發佈到 AppStore 的應用程序(App),只有通過簽名驗證(Signature Validated)才能確保來源可信,而且保證 App 內容是完整、未經篡改的。
iOS 證書分爲兩類:Development 和 Production(Distribution)。
Development 證書用來開發和調試應用程序:A development certificate identifies you, as a team member, in a development provisioning profile that allows apps signed by you to launch on devices.
Production 主要用來分發應用程序(根據證書種類有不一樣做用):A *distribution certificate identifies your team or organization in a distribution provisioning profile and allows you to *submit your app to the store. Only a team agent or an admin can create a distribution certificate.
普通我的開發帳號最多可註冊 iOS Development/Distribution 證書各2個,用戶可在網站上刪除(Revoke)已註冊的 Certificate。Apple 證書頒發機構 WWDRCA(Apple Worldwide Developer Relations Certification Authority) 將使用其 private key 對 CSR 中的 public key 和一些身份信息進行加密簽名生成數字證書(ios_development.cer)並記錄在案(Apple Member Center)。
而P12文件,正是用於在多臺設備間共享證書。在 Keychain Access|Certificates 中選中欲導出的 certificate 或其下 private key,右鍵 Export 或者經過菜單 File|Export Items 導出 Certificates.p12——PKCS12 file holds the private key and certificate。其 他 Mac 機器上雙擊 Certificates.p12(若有密碼需輸入密碼)便可安裝該共享證書。有了共享證書以後,在開發者網站上將欲調試的 iOS 設備註冊到該開發者帳號名下,並下載對應證書受權了 iOS 調試設備的 Provisioning Profile 文件,方可在 iOS 真機設備上開發調試。
Provisioning Profile 文件包含了上述的全部內容:證書、App ID 和 設備 ID。
一個 Provisioning Profile 對應一個 Explicit App ID 或 Wildcard App ID(一組相同 Prefix/Seed 的 App IDs)。在網站上手動建立一個 Provisioning Profile 時,須要依次指定 App ID(單選)、證書(Certificates,可多選)和設備(Devices,可多選)。用戶可在網站上刪除(Delete)已註冊的 Provisioning Profiles。Provisioning Profile 決定 Xcode 用哪一個證書(公鑰)/私鑰組合(Key Pair/Signing Identity)來簽署應用程序(Signing Product),並將在應用程序打包時嵌入到 .ipa 包裏。安裝應用程序時,Provisioning Profile 文件被拷貝到 iOS 設備中,運行該 iOS App 的設備經過它來認證安裝的程序。若是要打包到真機上運行一個APP,通常要經歷如下三步:
首先,須要指明它的 App ID,而且驗證 Bundle ID 是否與其一致;
其次,須要證書對應的私鑰來進行簽名,用於標識這個 APP 是合法、安全、完整的;
而後,若是是真機調試,須要確認這臺設備是否受權運行該 APP。
Provisioning Profile 把這些信息所有打包在一塊兒,方便咱們在調試和發佈程序打包時使用。這樣,只要在不一樣的狀況下選擇不一樣的 Provisioning Profile 文件就能夠了。Provisioning Profile 也分爲 Development 和 Distribution 兩類,有效期同 Certificate 同樣。Distribution 版本的 ProvisioningProfile 主要用於提交 App Store 審覈,其中不指定開發測試的Devices(0,unlimited)。App ID 爲 Wildcard App ID(*)。App Store 審覈經過上架後,容許全部 iOS 設備(Deployment Target)上安裝運行該App。Xcode 將所有供應配置文件(包括用戶手動下載安裝的和 Xcode 自動建立的 Team Provisioning Profile)放在目錄 ~/Library/MobileDevice/Provisioning Profiles 下。
所謂「免證書」真機調試,並非真的不須要證書,Xcode真機調試原有的證書配置體系仍在——All iOS, tvOS, and watchOS appsmust be code signed and provisioned to launch on a device. 因此,上文囉嗦幾千字仍是有點用的。
自 Xcode7 開始,原來基於付費開發者帳號及自助生成證書及配置文件的繁瑣過程被蘋果簡化,Xcode將針對任何普通帳號自動爲聯調真機生成所需相關的證書及配置文件。當你打算向 App Store 提交發布應用,才須要付費。
第一步:進入 Xcode Preferences|Accounts,添加本身的 Apple ID 帳號。
第二步:Build Settings|Code Signing 下的 Provisioning Profile 選擇 Automatic,Code Signing Identity 選擇 Automatic 下的iOS Developer。
第三步:General 配置 Bundle identifier,Team 下拉選擇蘋果Member Center自動爲你的帳號生成的Personal Team ID。
本身的帳號在調試公司或其餘第三方APP代碼時,若填寫 Bundle identifier 爲他人帳號註冊的 APP ID(例如蘋果相機應用 com.apple.camera),會報錯:
No provisioning profiles with a valid signing identity (i.e. certificate and private key pair) matching the bundle identifier 「com.apple.camera」 were found.
即便編譯經過了,可能運行時APP自身與服務器校驗也可能會報簽名錯誤,腫麼辦???
Her skill:此時,能夠在他人原有App ID基礎上添加後綴(例如com.apple.camera.extension),配置成應用的衍生插件(至關於置於同一 App Group 下)就能夠快樂的玩耍了。
若是啓動APP時,Xcode報錯「process launch failed: Security」或iPhone報錯【不受信任的開發者】,此時須要到iPhone通用配置中的描述文件(最新系統中可能叫設備管理)中,在描述文件(開發商應用)中選擇對應的描述文件(你的Apple ID)點擊 信任 或 驗證 便可。
筆者以前作過體育社交類產品,提交的時候被拒了,緣由是沒有添加內容舉報的功能。
自2016年6月1日起,蘋果要求全部提交App Store的iOS應用必須支持IPv6-only環境,背景也是衆所周知的,IPv4地址已基本分配完畢,同時IPv6比IPv4也更加高效,向IPv6過渡是大勢所趨。
首先須要明確一點,在App Store審覈APP的IPv6-only的環境下也是能夠正常訪問IPv4的服務的,只是首先由DNS64將解析出來的IPv4地址轉成兼容的IPv6地址,而後訪問IPv4服務時經過NAT64網關對IPv4和IPv6進行NAT,並不須要客戶有實際的IPv6服務。以下圖所示:
客戶端在向DNS64請求一個域名的IPv6地址時,DNS64會向域名的受權DNS請求IPv6地址,若是存在IPv6地址,則直接給客戶端返回IPv6地址,若是不存在IPv6地址,則向受權請求IPv4地址,並將返回的IPv4地址轉換爲兼容的IPv6地址。
以Google DNS64爲例說明轉換規則,分別請求dnspod.cn的A記錄(IPv4地址)和AAAA記錄(IPv6地址):
從解析結果能夠看出IPv4地址對應的IPv6地址,後32位的3b25:7465實際上就是IPv4地址的16進製表示59=0x3b,37=0x25,116=0x74,101=0x65,明白該規則後也能夠本身進行IPv4向兼容的IPv6地址的轉換,如119.29.29.29的兼容IPv6地址爲64:ff9b::771d:1d1d,其中::表示爲全0。
DNS64解析流程以下圖所示:
用Mac作一個熱點,而後用iPhone鏈接這個Wi-Fi,在「System Preferences」界面選中「Sharing」的同時,要按住「Option」鍵。
以後在「Sharing」界面中,咱們會看到和以前不同的地方,就是紅框所標的地方,多了一個叫「Create NAT64 Network」的選框,選中它。
下圖展現的藍色部分的這些API都是不存在兼容性問題的,而咱們平時本身用的包括那些第三方的網絡庫大部分都是用的這些API。
大部分狀況下,咱們用高級的API徹底可以實現咱們的需求,並且高級API封裝的很便於使用,不少底層的像適配IPv6的工做都已經幫咱們作好了。而用底層API會有大量的工做要咱們本身來作,更容易產生bug。但你若是確實須要用底層的POSIX socket API, 請參照這個RFC4038: Application Aspects of IPv6 Transition的指導。
好比下面這個API,nodename這個參數不要傳IP地址,而應該用域名
這個方法在著名的第三方Reachability中是用到的,咱們經常使用的第三方網絡庫AFNetworking就用了這個。因此用到的同窗得好好查一下了。
inet_addr() inet_aton() inet_lnaof() inet_makeaddr() inet_netof() inet_network() inet_ntoa() inet_ntoa_r() bindresvport() getipv4sourcefilter() setipv4sourcefilter()
以及以下的一些數據類型: