前言
這幾天最大的新聞我想就是巴黎恐怖襲擊
了,誒,博主每年跨年都那么虔誠地許下“希望世界和平”的愿望袁余,想不到每年都無法實(shí)現(xiàn),維護(hù)世界和平這么難咱揍,博主真是有心無力啊颖榜,其實(shí)蕓蕓眾生的我們能做的大概就是不要闖紅燈、不搶小妹妹的甜筒煤裙、拉完屎記得沖水掩完、打飯不逃票、不在澡堂小便硼砰、不挖人家墻角……其實(shí)就是維護(hù)世界和平了且蓬。
然而黑客組織Anonymous向ISIS宣戰(zhàn)了!
圖0
威武题翰!
好吧回歸這次文章主題恶阴,就列舉一些iOS應(yīng)用發(fā)布中個(gè)人覺得還蠻容易忽略的一些細(xì)節(jié)。
Bundle identifier
Xcode中 Target -> General
中的bundle identifier
;
info.plist
中的Bundle identifier
;
證書中心{:target="_blank"} 的Identifiers
中App IDs
新建App時(shí)的Explicit App ID
;
以及iTunes Connect
中App信息的套裝ID
必須保持一致1稀冯事!
在info.plist或者Xcode里的各種設(shè)置中,有很多$(XXX)
這樣的像腳本一樣的東西血公,所以補(bǔ)充一點(diǎn)Xcode中的環(huán)境變量{:target="_blank"}
Certificates證書
蘋果的證書體系一直都是iOS初學(xué)者無盡的夢魘昵仅,什么開發(fā)證書、發(fā)布證書累魔、推送證書摔笤,什么ad hoc、內(nèi)測分發(fā)薛夜、真機(jī)調(diào)試……我想每一個(gè)iOS初學(xué)剛開始接觸Apple的證書體系的時(shí)候內(nèi)心是絕壁崩潰并且被心中的草泥馬踐踏的體無完膚的……籍茧。
其實(shí)蘋果的證書其實(shí)沒那么玄乎,很多朋友弄不懂或者過了一段時(shí)間又不知道怎么弄了梯澜,本質(zhì)的原因是因?yàn)閷?a target="_blank" rel="nofollow">非對稱加密(公開密鑰加密){:target="_blank"}的不理解導(dǎo)致的寞冯,所以為了完全的駕馭蘋果的證書渴析,這些基礎(chǔ)的知識就是坑你的坎,必須跨過去的吮龄。
網(wǎng)上有各種解釋證書中心里面每一種證書作用是什么俭茧、怎么創(chuàng)建、怎么使用的漓帚,但是這也只能授人以魚母债,所以博主不會(huì)介紹每一種證書是干嘛的,因?yàn)槟憧辞澳甓嗔艘粋€(gè)Pass Type ID Certificate
尝抖,去年又有了WatchKit Services Certificate
毡们,今年又來一個(gè)Apple Pay Certificate
……根本就解釋這些證書不完嘛~,所以理解這些證書的統(tǒng)一規(guī)律才是王道昧辽!所謂
萬變不離其宗
很多資料都把證書分成兩種衙熔,分為開發(fā)證書(development)、以及發(fā)布證書(distribution)搅荞。但是博主認(rèn)為這樣分類不是很不科學(xué)的红氯,博主的理解的分類是這樣的
圖1
-
根證書
是與開發(fā)者或者企業(yè)對應(yīng)的,只要是被根證書
簽名的App都可以理解為是這個(gè)證書對應(yīng)的開發(fā)者開發(fā)的咕痛。所以一個(gè)根證書
可以簽名多個(gè)App痢甘。
-
其他證書
呢是與具體的App對應(yīng)的,一個(gè)App的推送證書是無法給另一個(gè)App使用的茉贡,所以一個(gè)其他證書
只能為一個(gè)App簽名塞栅,更確切的說是這個(gè)App需要使用某一項(xiàng)Apple的服務(wù)而去產(chǎn)生這個(gè)其他證書
。
所以其實(shí)蘋果每年都添加的證書屬于其他證書
块仆,這些其他證書并不是非必須的构蹬,而是使用了蘋果的某一項(xiàng)服務(wù)時(shí)才需要提供的憑證王暗。而根證書
是必須的悔据,它簽名的APP是屬于這個(gè)證書的所有者的。
圖2
圖中我的這個(gè)賬號默認(rèn)會(huì)有兩個(gè)不同用途的根證書
俗壹,有兩個(gè)App科汗,分別為App1、APP2绷雏,以及它們對應(yīng)的兩種用途的推送證書(屬于其他證書
)头滔。
假如我現(xiàn)在需要真機(jī)調(diào)試App1的推送,那么我只要下載開發(fā)根證書
以及App1的開發(fā)推送證書
然后雙擊打開導(dǎo)入鑰匙串涎显,然后創(chuàng)建相應(yīng)profile即可真機(jī)調(diào)試了坤检;
假如現(xiàn)在我要發(fā)布APP2,那么我只要下載發(fā)布根證書
以及APP2的發(fā)布推送證書
期吓,然后創(chuàng)建相應(yīng)地profile即可打包上傳App Strore了早歇。(這里因?yàn)榘l(fā)布的特殊性,所以發(fā)布的電腦必須是創(chuàng)建這個(gè)發(fā)布根證書
的電腦)。
profile(描述文件)下文還有篇幅介紹箭跳。
我TM都繞暈了晨另,確實(shí)有點(diǎn)麻煩有點(diǎn)復(fù)雜,果然iOS開發(fā)門檻就是高啊谱姓,但是哥就喜歡借尿。
App IDs
在相應(yīng)地App的edit中可以添加多套APNs推送證書(其他的證書也類似的)
圖3
在這里聲明一下,其他證書
其他證書生成的時(shí)候屉来,使用的certSigningRequest
文件可以和產(chǎn)生根證書
的certSigningRequest
的不一致路翻,也就是說產(chǎn)生其他證書
時(shí)不一定需要產(chǎn)生根證書
的電腦,所以這里也坑了無數(shù)的人調(diào)試推送茄靠,這個(gè)在下文推送的那些事詳細(xì)填坑帚桩。
Provisioning Profiles描述文件
圖4
我想這個(gè)界面一彈出來的時(shí)候,蛋蛋憂傷迎面撲來嘹黔。然后怒點(diǎn) Fix issue
账嚎,然后你們團(tuán)隊(duì)負(fù)責(zé)管理證書的基友突然發(fā)現(xiàn)證書中心多了好多好亂的證書以及描述文件,然后他爆了一句:what the huck儡蔓!刪掉了帶有Xcode *
的證書以及描述文件郭蕉,然后自己又暴力的點(diǎn)了一發(fā)Fix issue
,然后你突然調(diào)試不了了喂江,再暴擊Fix issue
鍵召锈,最后整個(gè)團(tuán)隊(duì)都只有通過Fix issue
來真機(jī)調(diào)試了……。
所以慎點(diǎn)Fix issue
获询,如果點(diǎn)擊這個(gè)選項(xiàng)涨岁,聰明的(蠢哭的)Xcode就會(huì)自己管理描述文件,然后各種莫名其妙的帶有Xcode *
的證書以及描述文件……
其實(shí)只要堅(jiān)信一點(diǎn)吉嚣,證書梢薪、設(shè)備ID、AppID尝哆、描述文件都弄對了就絕逼不會(huì)出問題的秉撇!
描述文件工作原理
圖5
- 其實(shí)描述文件工作的原理就是在APP打包或者真機(jī)調(diào)試的時(shí)候,讓Xcode去檢查描述文件里面的BundleID與這個(gè)APP的BundleID是否對應(yīng)秋泄。
- 對應(yīng)的話就會(huì)去
keyChain
查找有沒有相應(yīng)地證書(所以證書要下載好琐馆,并且導(dǎo)入keyChain
) - 如果有證書存在的話就會(huì)檢查證書的類型,如果是開發(fā)證書恒序,則會(huì)檢查調(diào)試的設(shè)備是否加入了描述文件里面的信任設(shè)備ID列表瘦麸,如果設(shè)備沒有在描述文件的列表中,則無法調(diào)試歧胁;如果證書類型是發(fā)布證書則不會(huì)檢查設(shè)備ID列表滋饲。
額外地彤敛,如果公司新增了測試機(jī),并且在證書中心的Devices
中添加了新測試機(jī)的ID了赌,這樣描述文件也要相應(yīng)地更新墨榄,然后重新下載,下載完之后可以先刪除舊的描述文件(博主直接覆蓋的方式貌似描述文件沒有更新啊)勿她,你們可以自己做實(shí)驗(yàn)咯袄秩,描述文件的路勁/Users/XXX/Library/MobileDevice/Provisioning\ Profiles
XXX
你的用戶名。
不要覆蓋逢并!記得先刪除之剧,可以免除很多問題。
推送的那些事
如果說億萬級用戶的微信推送服務(wù)并不是企鵝自己定制的而都是由蘋果APNs推送的話砍聊,那蘋果的推送就真的牛逼了背稼,但是有時(shí)候測試推送,經(jīng)常APNs要死不活的玻蝌,推了半天才到蟹肘,有一次在APNs沙箱環(huán)境怒推1000多條,然后這條隊(duì)列持續(xù)了半個(gè)月才推完~~俯树。所以微信帘腹、扣扣肯定是定制的推送,有錢就是討厭许饿,那么任性阳欲。
但是蘋果推送的開發(fā)是比較簡單地,如果沒有高級推送需求基本就不用寫代碼了陋率,只要配置好證書一切OK球化。
現(xiàn)在常用的后臺server中,一般將推送證書以及推送證書的私鑰導(dǎo)出p12交給后臺人員即可瓦糟。
PHP有點(diǎn)調(diào)皮筒愚,還需要轉(zhuǎn)換成pem
生成PHP需要的Pem證書
準(zhǔn)備:
- 蘋果服務(wù)器證書端設(shè)置正確!打包證書狸页、描述文件正確O悄堋!
- 下載推送證書(cer格式)芍耘,導(dǎo)入keyChain,保證私鑰存在熄阻,不存在去找創(chuàng)建這個(gè)證書的電腦要一份過來斋竞。
- 從鑰匙庫導(dǎo)出的
根證書(推送證書)私鑰(p12格式)
第三步根證書的私鑰這里是一個(gè)坑!因?yàn)橐粋€(gè)App的推送證書的創(chuàng)建可以和根證書創(chuàng)建的電腦不同秃殉,也就是keyChain產(chǎn)生的certSigningRequest
不一樣坝初,所以私鑰也是不一樣的浸剩,在這里生成Pem時(shí),注意要使用推送證書的私鑰鳄袍!
操作過程:
-
把推送證書(.cer)轉(zhuǎn)換為.pem文件绢要,執(zhí)行命令:
openssl x509 -in 推送證書.cer -inform der -out 推送證書.pem
-
把推送證書導(dǎo)出的私鑰(.p12)文件轉(zhuǎn)化為.pem文件:
openssl pkcs12 -nocerts -out 推送證書私鑰.pem -in 推送證書私鑰.p12
-
對生成的這兩個(gè)pem文件再生成一個(gè)pem文件,來把證書和私鑰整合到一個(gè)文件里:
cat 推送證書.pem 推送證書私鑰.pem >PHPPush.pem
然后把這個(gè)PHPPush.pem給后臺基友們拗小,就可以下班啦重罪。
當(dāng)然測試推送也比較麻煩,需要模擬真實(shí)的推送環(huán)境哀九,一般需要后臺提供幫助剿配,但是遇到一些后臺同事,他們有強(qiáng)烈地信仰著鄙視鏈的話阅束,很鄙視iOS呼胚,心里早就稱呼你“死前段”多年了,還那么多事……
所以關(guān)于調(diào)試推送息裸,博主教你自己推自己蝇更!不麻煩別人。
只要拷貝這段代碼
<?php
// devicetoken
$deviceToken = '你的deviceToken';
// 私鑰密碼呼盆,生成pem的時(shí)候輸入的
$passphrase = '123456';
// 定制推送內(nèi)容簿寂,有一點(diǎn)的格式要求,詳情Apple文檔
$message = array(
'body'=>'你收到一個(gè)新訂單'
);
$body['aps'] = array(
'alert' => $message,
'sound' => 'default',
'badge' => 100,
);
$body['type']=3;
$body['msg_type']=4;
$body['title']='新訂單提醒';
$body['msg']='你收到一個(gè)新消息';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'push.pem');//記得把生成的push.pem放在和這個(gè)php文件同一個(gè)目錄
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client(
//這里需要特別注意宿亡,一個(gè)是開發(fā)推送的沙箱環(huán)境常遂,一個(gè)是發(fā)布推送的正式環(huán)境,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);
?>
將上面的代碼復(fù)制挽荠,保存成push.php
然后根據(jù)上面“生成PHP需要的Pem證書”的步驟生成push.pem
兩個(gè)文件放在同一目錄
執(zhí)行下面的命令
DavidDay$ php push.php
結(jié)果為
Connected to APNS
Message successfully delivered
是不是就推送成功了呢克胳?呵呵噠
打包、分發(fā)及內(nèi)測
關(guān)于打包是有很多姿勢的圈匆,每個(gè)人都有各自的喜好漠另,大部分規(guī)矩的做法都是使用Xcode的一條龍服務(wù)的:
選擇相應(yīng)地描述文件、證書
選擇ARM架構(gòu)機(jī)型(模擬器是Intel架構(gòu)的跃赚,真機(jī)是ARM架構(gòu)的笆搓,不能通用)
product -> archive
-
然后就可以選擇導(dǎo)出ipa在第三方平臺分發(fā)測試或者上傳App Stroe審核了
?
這樣的做法比較保險(xiǎn),因?yàn)?code>archive 只會(huì)編譯出真機(jī)的二進(jìn)制碼纬傲,所以不用擔(dān)心導(dǎo)出的ipa真機(jī)裝不起满败。
另一種姿勢是使用xcodebuild
工具,純Shell編譯叹括,比較不好處理錯(cuò)誤算墨,但是逼格滿滿啊,想詳細(xì)了解這種姿勢的可以看看官方文檔{:target="_blank"} 汁雷,或者參考這位同學(xué)的分享{:target="_blank"}
當(dāng)然嘛净嘀,博主作為拖拖派的忠實(shí)擁躉报咳,博主打包ipa的時(shí)候是這樣的:
圖6
![](http://daiweilai.github.io/img/post/2015-11-17-pic6.gif)
隨時(shí)build隨時(shí)轉(zhuǎn)ipa。
分發(fā)內(nèi)測一般都會(huì)使用第三方的平臺挖藏,fir{:target="_blank"}暑刃、蒲公英{:target="_blank"} 都很好呀~
關(guān)于提交審核這里,一般archive過去了膜眠,證書正確都沒問題的岩臣,當(dāng)然還是要檢查項(xiàng)目是否調(diào)用了私有API,之前用reveal {:target="_blank"} 柴底,提交應(yīng)用的時(shí)候忘了移除婿脸,千不該萬不該的還是用了Xcode的upload工具,也不報(bào)錯(cuò)柄驻,在iTunesConnect中構(gòu)建版本也出現(xiàn)了狐树,只是狀態(tài)“正在處理”,一般這個(gè)狀態(tài)持續(xù)10分鐘~2個(gè)小時(shí)就會(huì)通過了鸿脓,然后博主自信關(guān)機(jī)下班抑钟,想不到第二天構(gòu)建版本還是“正在處理”,然后猜想是不是iTunes出問題了又怒傳了N個(gè)包野哭,依然是“正在處理”在塔,后來準(zhǔn)備發(fā)郵件,打開郵箱拨黔,尼瑪蛔溃!
圖7
原來調(diào)用了私有接口,忘記移除reveal了~篱蝇,回顧起來這里有三個(gè)大坑贺待,
- Xcode的上傳工具很辣雞!零截!很多錯(cuò)誤都無法掃描出來麸塞,所以切記 使用
Application Loader
,速度快涧衙,錯(cuò)誤報(bào)告也精準(zhǔn)哪工。 - iTunesConnect的錯(cuò)誤狀態(tài)幾乎沒有,一般只有兩個(gè)狀態(tài) “正在處理”弧哎、“成功”雁比,所以如果超過兩個(gè)小時(shí)仍然是“正在處理”,那么極有可能包出問題了傻铣!
- 記住關(guān)注郵件章贞!
打包項(xiàng)目證書選擇必須正確 (Xcode7以下 選擇項(xiàng)目編譯target為Iphone Device 不要連接手機(jī) 否則會(huì) ,Xcode7中不需要拔出真機(jī)非洲,因?yàn)槎嗔艘粋€(gè)build only device
的選項(xiàng))
編譯target選錯(cuò)了 報(bào)錯(cuò)
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 ")
總結(jié)
突然想起我哥說的一句話
有時(shí)候有些女人就像飯?zhí)蔑埐搜枷蓿m然難吃,但是去晚了也會(huì)沒有的两踏!
珍惜身邊的人败京。
感覺這個(gè)總結(jié)什么鬼?有點(diǎn)傷感梦染,嗯赡麦,iOS應(yīng)用的發(fā)布,每個(gè)從業(yè)者都應(yīng)該能夠熟練的對發(fā)布進(jìn)行操作和意外處理的帕识。
沒錢結(jié)婚泛粹。