前言
這幾天最大的新聞我想就是巴黎恐怖襲擊
了,誒,博主每年跨年都那么虔誠地許下“希望世界和平”的愿望,想不到每年都無法實現,維護世界和平這么難,博主真是有心無力啊,其實蕓蕓眾生的我們能做的大概就是不要闖紅燈、不搶小妹妹的甜筒、拉完屎記得沖水、打飯不逃票、不在澡堂小便、不挖人家墻角……其實就是維護世界和平了。
然而黑客組織Anonymous向ISIS宣戰了!
圖0
威武!
好吧回歸這次文章主題,就列舉一些iOS應用發布中個人覺得還蠻容易忽略的一些細節。
Bundle identifier
Xcode中 Target -> General
中的bundle identifier
;
info.plist
中的Bundle identifier
;
證書中心{:target="_blank"} 的Identifiers
中App IDs
新建App時的Explicit App ID
;
以及iTunes Connect
中App信息的套裝ID
必須保持一致!!
在info.plist或者Xcode里的各種設置中,有很多$(XXX)
這樣的像腳本一樣的東西,所以補充一點Xcode中的環境變量{:target="_blank"}
Certificates證書
蘋果的證書體系一直都是iOS初學者無盡的夢魘,什么開發證書、發布證書、推送證書,什么ad hoc、內測分發、真機調試……我想每一個iOS初學剛開始接觸Apple的證書體系的時候內心是絕壁崩潰并且被心中的草泥馬踐踏的體無完膚的……。
其實蘋果的證書其實沒那么玄乎,很多朋友弄不懂或者過了一段時間又不知道怎么弄了,本質的原因是因為對非對稱加密(公開密鑰加密){:target="_blank"}的不理解導致的,所以為了完全的駕馭蘋果的證書,這些基礎的知識就是坑你的坎,必須跨過去的。
網上有各種解釋證書中心里面每一種證書作用是什么、怎么創建、怎么使用的,但是這也只能授人以魚,所以博主不會介紹每一種證書是干嘛的,因為你看前年多了一個Pass Type ID Certificate
,去年又有了WatchKit Services Certificate
,今年又來一個Apple Pay Certificate
……根本就解釋這些證書不完嘛~,所以理解這些證書的統一規律才是王道!所謂
萬變不離其宗
很多資料都把證書分成兩種,分為開發證書(development)、以及發布證書(distribution)。但是博主認為這樣分類不是很不科學的,博主的理解的分類是這樣的
圖1
-
根證書
是與開發者或者企業對應的,只要是被根證書
簽名的App都可以理解為是這個證書對應的開發者開發的。所以一個根證書
可以簽名多個App。
-
其他證書
呢是與具體的App對應的,一個App的推送證書是無法給另一個App使用的,所以一個其他證書
只能為一個App簽名,更確切的說是這個App需要使用某一項Apple的服務而去產生這個其他證書
。
所以其實蘋果每年都添加的證書屬于其他證書
,這些其他證書并不是非必須的,而是使用了蘋果的某一項服務時才需要提供的憑證。而根證書
是必須的,它簽名的APP是屬于這個證書的所有者的。
圖2
圖中我的這個賬號默認會有兩個不同用途的根證書
,有兩個App,分別為App1、APP2,以及它們對應的兩種用途的推送證書(屬于其他證書
)。
假如我現在需要真機調試App1的推送,那么我只要下載開發根證書
以及App1的開發推送證書
然后雙擊打開導入鑰匙串,然后創建相應profile即可真機調試了;
假如現在我要發布APP2,那么我只要下載發布根證書
以及APP2的發布推送證書
,然后創建相應地profile即可打包上傳App Strore了。(這里因為發布的特殊性,所以發布的電腦必須是創建這個發布根證書
的電腦)。
profile(描述文件)下文還有篇幅介紹。
我TM都繞暈了,確實有點麻煩有點復雜,果然iOS開發門檻就是高啊,但是哥就喜歡。
App IDs
在相應地App的edit中可以添加多套APNs推送證書(其他的證書也類似的)
圖3
在這里聲明一下,其他證書
其他證書生成的時候,使用的certSigningRequest
文件可以和產生根證書
的certSigningRequest
的不一致,也就是說產生其他證書
時不一定需要產生根證書
的電腦,所以這里也坑了無數的人調試推送,這個在下文推送的那些事詳細填坑。
Provisioning Profiles描述文件
圖4
我想這個界面一彈出來的時候,蛋蛋憂傷迎面撲來。然后怒點 Fix issue
,然后你們團隊負責管理證書的基友突然發現證書中心多了好多好亂的證書以及描述文件,然后他爆了一句:what the huck!刪掉了帶有Xcode *
的證書以及描述文件,然后自己又暴力的點了一發Fix issue
,然后你突然調試不了了,再暴擊Fix issue
鍵,最后整個團隊都只有通過Fix issue
來真機調試了……。
所以慎點Fix issue
,如果點擊這個選項,聰明的(蠢哭的)Xcode就會自己管理描述文件,然后各種莫名其妙的帶有Xcode *
的證書以及描述文件……
其實只要堅信一點,證書、設備ID、AppID、描述文件都弄對了就絕逼不會出問題的!
描述文件工作原理
圖5
- 其實描述文件工作的原理就是在APP打包或者真機調試的時候,讓Xcode去檢查描述文件里面的BundleID與這個APP的BundleID是否對應。
- 對應的話就會去
keyChain
查找有沒有相應地證書(所以證書要下載好,并且導入keyChain
) - 如果有證書存在的話就會檢查證書的類型,如果是開發證書,則會檢查調試的設備是否加入了描述文件里面的信任設備ID列表,如果設備沒有在描述文件的列表中,則無法調試;如果證書類型是發布證書則不會檢查設備ID列表。
額外地,如果公司新增了測試機,并且在證書中心的Devices
中添加了新測試機的ID,這樣描述文件也要相應地更新,然后重新下載,下載完之后可以先刪除舊的描述文件(博主直接覆蓋的方式貌似描述文件沒有更新啊),你們可以自己做實驗咯,描述文件的路勁/Users/XXX/Library/MobileDevice/Provisioning\ Profiles
XXX
你的用戶名。
不要覆蓋!記得先刪除,可以免除很多問題。
推送的那些事
如果說億萬級用戶的微信推送服務并不是企鵝自己定制的而都是由蘋果APNs推送的話,那蘋果的推送就真的牛逼了,但是有時候測試推送,經常APNs要死不活的,推了半天才到,有一次在APNs沙箱環境怒推1000多條,然后這條隊列持續了半個月才推完~~。所以微信、扣扣肯定是定制的推送,有錢就是討厭,那么任性。
但是蘋果推送的開發是比較簡單地,如果沒有高級推送需求基本就不用寫代碼了,只要配置好證書一切OK。
現在常用的后臺server中,一般將推送證書以及推送證書的私鑰導出p12交給后臺人員即可。
PHP有點調皮,還需要轉換成pem
生成PHP需要的Pem證書
準備:
- 蘋果服務器證書端設置正確!打包證書、描述文件正確!!
- 下載推送證書(cer格式),導入keyChain,保證私鑰存在,不存在去找創建這個證書的電腦要一份過來。
- 從鑰匙庫導出的
根證書(推送證書)私鑰(p12格式)
第三步根證書的私鑰這里是一個坑!因為一個App的推送證書的創建可以和根證書創建的電腦不同,也就是keyChain產生的certSigningRequest
不一樣,所以私鑰也是不一樣的,在這里生成Pem時,注意要使用推送證書的私鑰!
操作過程:
-
把推送證書(.cer)轉換為.pem文件,執行命令:
openssl x509 -in 推送證書.cer -inform der -out 推送證書.pem
-
把推送證書導出的私鑰(.p12)文件轉化為.pem文件:
openssl pkcs12 -nocerts -out 推送證書私鑰.pem -in 推送證書私鑰.p12
-
對生成的這兩個pem文件再生成一個pem文件,來把證書和私鑰整合到一個文件里:
cat 推送證書.pem 推送證書私鑰.pem >PHPPush.pem
然后把這個PHPPush.pem給后臺基友們,就可以下班啦。
當然測試推送也比較麻煩,需要模擬真實的推送環境,一般需要后臺提供幫助,但是遇到一些后臺同事,他們有強烈地信仰著鄙視鏈的話,很鄙視iOS,心里早就稱呼你“死前段”多年了,還那么多事……
所以關于調試推送,博主教你自己推自己!不麻煩別人。
只要拷貝這段代碼
<?php
// devicetoken
$deviceToken = '你的deviceToken';
// 私鑰密碼,生成pem的時候輸入的
$passphrase = '123456';
// 定制推送內容,有一點的格式要求,詳情Apple文檔
$message = array(
'body'=>'你收到一個新訂單'
);
$body['aps'] = array(
'alert' => $message,
'sound' => 'default',
'badge' => 100,
);
$body['type']=3;
$body['msg_type']=4;
$body['title']='新訂單提醒';
$body['msg']='你收到一個新消息';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'push.pem');//記得把生成的push.pem放在和這個php文件同一個目錄
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client(
//這里需要特別注意,一個是開發推送的沙箱環境,一個是發布推送的正式環境,deviceToken是不通用的
'ssl://gateway.sandbox.push.apple.com:2195', $err,
//'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . PHP_EOL);
echo 'Connected to APNS' . PHP_EOL;
$payload = json_encode($body);
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
$result = fwrite($fp, $msg, strlen($msg));
if (!$result)
echo 'Message not delivered' . PHP_EOL;
else
echo 'Message successfully delivered' . PHP_EOL;
fclose($fp);
?>
將上面的代碼復制,保存成push.php
然后根據上面“生成PHP需要的Pem證書”的步驟生成push.pem
兩個文件放在同一目錄
執行下面的命令
DavidDay$ php push.php
結果為
Connected to APNS
Message successfully delivered
是不是就推送成功了呢?呵呵噠
打包、分發及內測
關于打包是有很多姿勢的,每個人都有各自的喜好,大部分規矩的做法都是使用Xcode的一條龍服務的:
選擇相應地描述文件、證書
選擇ARM架構機型(模擬器是Intel架構的,真機是ARM架構的,不能通用)
product -> archive
-
然后就可以選擇導出ipa在第三方平臺分發測試或者上傳App Stroe審核了
?
這樣的做法比較保險,因為archive
只會編譯出真機的二進制碼,所以不用擔心導出的ipa真機裝不起。
另一種姿勢是使用xcodebuild
工具,純Shell編譯,比較不好處理錯誤,但是逼格滿滿啊,想詳細了解這種姿勢的可以看看官方文檔{:target="_blank"} ,或者參考這位同學的分享{:target="_blank"}
當然嘛,博主作為拖拖派的忠實擁躉,博主打包ipa的時候是這樣的:
圖6

隨時build隨時轉ipa。
分發內測一般都會使用第三方的平臺,fir{:target="_blank"}、蒲公英{:target="_blank"} 都很好呀~
關于提交審核這里,一般archive過去了,證書正確都沒問題的,當然還是要檢查項目是否調用了私有API,之前用reveal {:target="_blank"} ,提交應用的時候忘了移除,千不該萬不該的還是用了Xcode的upload工具,也不報錯,在iTunesConnect中構建版本也出現了,只是狀態“正在處理”,一般這個狀態持續10分鐘~2個小時就會通過了,然后博主自信關機下班,想不到第二天構建版本還是“正在處理”,然后猜想是不是iTunes出問題了又怒傳了N個包,依然是“正在處理”,后來準備發郵件,打開郵箱,尼瑪!
圖7
原來調用了私有接口,忘記移除reveal了~,回顧起來這里有三個大坑,
- Xcode的上傳工具很辣雞!!很多錯誤都無法掃描出來,所以切記 使用
Application Loader
,速度快,錯誤報告也精準。 - iTunesConnect的錯誤狀態幾乎沒有,一般只有兩個狀態 “正在處理”、“成功”,所以如果超過兩個小時仍然是“正在處理”,那么極有可能包出問題了!
- 記住關注郵件!
打包項目證書選擇必須正確 (Xcode7以下 選擇項目編譯target為Iphone Device 不要連接手機 否則會 ,Xcode7中不需要拔出真機,因為多了一個build only device
的選項)
編譯target選錯了 報錯
ITMS-90530 "Invalid MinimumOSVersion. Apps that only support 64-bit devices must specify a deplyment target of 8.0 or later"
IMTS-90208 "Invalid Bundle. The bundle xxx.app does not support the minimum OS version specified in the Info.plist"
IMTS-90502 "Invalid Bundle. Apps that only contain the arm64 slice must also have'arm64' in the list of UIRequiredDeviceCapabilities in Info.plist ")
總結
突然想起我哥說的一句話
有時候有些女人就像飯堂飯菜,雖然難吃,但是去晚了也會沒有的!
珍惜身邊的人。
感覺這個總結什么鬼?有點傷感,嗯,iOS應用的發布,每個從業者都應該能夠熟練的對發布進行操作和意外處理的。
沒錢結婚。