人力有時(shí)而窮,記憶力終究還是擋不住時(shí)間消磨,期間遇到各種奇葩問題,也是只有親身經(jīng)歷才能理解。所以現(xiàn)在記下來,防止以后走彎路。
事先準(zhǔn)備:
1).首先你得有一個(gè)付費(fèi)的開發(fā)者賬號
2).Mac、iPhone設(shè)備得準(zhǔn)備好
開始進(jìn)入正題
第一步:先準(zhǔn)備好CSR,CSR又叫.certSigningRequest文件,用于請求證書和描述文件,所以這也叫請求文件。生成方法如下:
1.打開鑰匙串
點(diǎn)擊如圖所示的“從證書頒發(fā)機(jī)構(gòu)請求證書……”

2.跳出證書助理,用戶電子郵件地址可隨意填,但最好填你自己郵箱,請求選擇“存儲(chǔ)到磁盤”

3.點(diǎn)擊繼續(xù)后得到CertificateSigningRequest.certSigningRequest文件
第二步:登錄developer.apple.com登錄你的開發(fā)者賬號

1.如上圖所示,先生成APPID既bundleID,點(diǎn)擊加號然后生成bundleID,這里沒什么難點(diǎn),主要需要注意的是bundleID命名的規(guī)范性

2.現(xiàn)在生成推送證書,如上圖,一般需要生成開發(fā)證書和APPStore用的證書,development對應(yīng)開發(fā)證書,production對應(yīng)APPStore證書

點(diǎn)擊右上角加號,如果是development則選擇如上圖所示的Apple?Push Notification service SSL (Sandbox),點(diǎn)擊繼續(xù),選擇我們剛剛生成的App ID也就是bundle ID

接著上傳我們生成好的CertificateSigningRequest.certSigningRequest文件,然后點(diǎn)擊生成證書,最后一步的時(shí)候記得下載證書到桌面,后面會(huì)用到到這里tui'son推送證書就生成了,接下來我們生成描述文件provision
3.描述文件生成也大同小異,沒什么難點(diǎn)development就選擇development,AppStore就選Appstore,也是上傳CSR得到描述文件provision,然后download到桌面?zhèn)溆谩?/p>
第三步:我們回到桌面,安裝推送證書,這里有一個(gè)坑,最好我們別直接雙擊安裝,否則有可能出現(xiàn)沒有專用秘鑰的情況,如下圖中第一個(gè)證書,發(fā)現(xiàn)了嗎?它是沒有展開箭頭的,意味著它沒有專用密鑰。這樣是不行的。

在這里我弄了進(jìn)一個(gè)上午,反復(fù)刪除證書和provision然后重新安裝,甚至重新生成bundle ID和provision以及推送證書全部重來一遍,都無效,網(wǎng)上搜索來的方法幾乎都試過,還是無果。突然我看到某個(gè)論壇有人說了句,直接把證書拖到登錄里,一試,果然可以了!真是大坑!

如上圖,已經(jīng)有下拉箭頭了,說明有專用密鑰了。你可能會(huì)問,為什么我千方百計(jì)要把專用密鑰弄出來呢?直接安裝證書,然后選好對應(yīng)provision和bundleID不就好了嗎?程序也可以正常運(yùn)行啊。是的,沒錯(cuò),是可以運(yùn)行,但是推送證書所需要的p12文件你就倒不出來了!推送需要證書和專用密鑰的p12文件!p12文件!P12文件!
接下來我們就可以倒出p12文件了,右鍵證書選擇導(dǎo)出


終于看到了我夢寐以求的p12文件,淚奔
好的,把它放到桌面上,同理,也別忘記了把對應(yīng)的專用密鑰導(dǎo)出來,如下圖

現(xiàn)在我們就得到了development的推送證書和專用密鑰的.p12文件,接下來我們需要把它們合成為一個(gè).pem文件,這個(gè)才是服務(wù)器做APNs推送需要用到的文件。
第四步:生成.pem文件
到此為止,我們已經(jīng)有了兩個(gè).p12文件,把他們放到同一個(gè)文件夾(aaa)下,需要把兩個(gè).p12文件轉(zhuǎn)換成.pem文件。
a.先打開終端,切換到文件夾aaa下執(zhí)行
[cpp]view plaincopy
openssl?pkcs12?-clcerts?-nokeys?-out?cert.pem?-in?cert.p12
在執(zhí)行的時(shí)候,將會(huì)讓輸入密碼,輸入剛才設(shè)置的密碼即可生成一個(gè)cert.pem文件。
b.再執(zhí)行:
[cpp]view plaincopy
openssl?pkcs12?-nocerts?-out?key.pem?-in?key.p12
此時(shí)要注意在終端中的提示,第一次輸入的密碼是生成證書時(shí)候的密碼,第二次第三次輸入密碼是設(shè)置key.pem的新密碼。
c.如果需要對key不進(jìn)行加密,執(zhí)行下邊語句
[cpp]view plaincopy
openssl?rsa?-in?key.pem?-out?key.unencrypted.pem
d.然后就可以合并兩個(gè).pem文件,這個(gè)ck.pem就是服務(wù)端需要的證書了。
[cpp]view plaincopy
cat?cert.pem?key.unencrypted.pem?>?ck.pem
此時(shí),把生成的ck.pem給服務(wù)器端的人員即可。
apns-dev-cert.p12和apns-dev-key.p12
第一個(gè)是推送證書的p12第二個(gè)是專用密鑰的p12

這就是我們最終需要的.pem文件,把這文件給服務(wù)器就好了,剩下的是服務(wù)器端的事情。
等服務(wù)器安裝好證書及調(diào)試后,我們需要測試下推送到底能不能用,所以,我們提供pem文件的同時(shí)得提供bundleID和devicetoken。等等,devicetoken?這是什么東東?好的,接下來我們再講講這個(gè)坑。
通過神奇的百度,我找到了如下資料:
先簡單介紹下push的機(jī)制
客戶端通過
(void)registerForRemoteNotificationTypes:(UIRemoteNotificationType)types
這個(gè)函數(shù)向APNs(Apple Push Service)注冊push,types可標(biāo)明接收的push的類型,聲音,數(shù)字等。
(void)application:(UIApplication
*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData
*)deviceToken;
當(dāng)app成功注冊通知后,會(huì)調(diào)用這個(gè)函數(shù),并把deviceToken返回給應(yīng)用。
然后我們的程序就會(huì)把返回的這個(gè)deviceToken以及設(shè)備的udid及軟件版本(淘寶for iPhone還是淘寶for iPad)及系統(tǒng)版本,用戶名等發(fā)送到我們的服務(wù)器(下圖中的provider)上,然后存儲(chǔ)在數(shù)據(jù)庫里。整個(gè)獲取device token的過程可參見下圖所示:

在需要發(fā)送push時(shí),我們的服務(wù)端就會(huì)取出要發(fā)送的設(shè)備的device token,然后以下圖所示的結(jié)構(gòu),組成符合特定結(jié)構(gòu)的字符串,然后將其發(fā)送到的APNs

APNs可以根據(jù)與APNs建立連接的Provider所使用的證書判斷是要哪個(gè)app請求發(fā)送的notification,繼而把這個(gè)notification發(fā)送到的設(shè)備上。
下圖為一個(gè)簡單的從Provider到Device發(fā)送push的過程:

device
token到底是什么呢?不同的app的device
token相同么?一個(gè)設(shè)備會(huì)產(chǎn)生多個(gè)device token么?一個(gè)的device token可能對應(yīng)多個(gè)UDID么?
結(jié)論:device token是對APNs來說,設(shè)備的標(biāo)識符,與app無關(guān),所以同一臺(tái)設(shè)備上,不同的app獲得的device token是一樣的;一個(gè)設(shè)備可能會(huì)產(chǎn)生多個(gè)device token,一個(gè)device
token也可能對應(yīng)多個(gè)UDID,下面進(jìn)行解釋。
device
token是什么?
文檔中如下描述的:

對于APS來說,token是設(shè)備的標(biāo)識符。device token不同于UIDevice的uniqueIdentifier(即UDID),因?yàn)槌鲇诎踩碗[私原因,當(dāng)設(shè)備被擦除后,token必須變化。
所以也就是說,一般情況下,token是不變的,但是在設(shè)備被擦除后,token會(huì)變的。
今天無心說在我們的服務(wù)器上的數(shù)據(jù)庫里,存在同一個(gè)UDID對應(yīng)有多個(gè)token的情況,之前是沒有考慮到設(shè)備擦除的情況,所以就懷疑是不是同一個(gè)設(shè)備上同時(shí)裝了taobao4iphone和taobao4ipad,而token是與app關(guān)聯(lián)的,所以產(chǎn)生的這種情況,于是就找了楊匡的ipad來做測試,結(jié)果發(fā)現(xiàn)taobao4iphone和taobao4ipad收到的token是相同的,所以token應(yīng)該是與app無關(guān)的,而是針對設(shè)備的(文檔上也是如此描述的),是設(shè)備的標(biāo)識,那除了設(shè)備被擦除的情況外,設(shè)備的device token應(yīng)該是相同的,可是楊匡說之前崇厚給他查出來的他的iPad的token和我log出來的device token是不同的,后來就想到了,push是有兩套的,development和product,即調(diào)試和release,在這兩種情況下,服務(wù)端使用的push證書是不一樣的,而程序使用的證書也不一樣,那同一個(gè)設(shè)備在development和distribution情況下收到的device token是否一樣呢,于是就做了實(shí)驗(yàn),實(shí)際結(jié)果如下
實(shí)驗(yàn)設(shè)備:iPad 1

可以看出,同一個(gè)設(shè)備在development和distribution情況下,收到的device token是不同的,而token是與app無關(guān)的。
綜合文檔及上述實(shí)驗(yàn)結(jié)果可以得到以下結(jié)果:
同一個(gè)udid對應(yīng)有不同的device token的情況暫時(shí)有如下兩種:
設(shè)備擦除過,token變化過,老的新的都存儲(chǔ)在數(shù)據(jù)庫里
設(shè)備同時(shí)裝過development和distribution的程序
不知道還有沒有其它原因造成的同一個(gè)設(shè)備有不同的device token的情況,大家如果有什么相關(guān)的經(jīng)驗(yàn),可以補(bǔ)充一下。
Ok,balabala一堆講完了,我們總結(jié)了下,devicetoken類似于令牌,但是又不同于UUID唯一標(biāo)識符,devicetoken會(huì)變化,但是我們只要知道它也是Apple設(shè)備的標(biāo)識符就好了,配合bundleID這樣才能給設(shè)備準(zhǔn)確地推送,OK科普完畢,開始獲取devicetoken
//獲取DeviceToken成功
- (void)application:(UIApplication*)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSLog(@"DeviceToken: {%@}",deviceToken);
//這里進(jìn)行的操作,是將Device Token發(fā)送到服務(wù)端
UIAlertView* alert = [[UIAlertViewalloc]initWithTitle:nilmessage:[NSStringstringWithFormat:@"DeviceToken:%@",deviceToken]delegate:selfcancelButtonTitle:nilotherButtonTitles:@"確定",nil];
[alertshow];
}
從上面這個(gè)方法里,我們就能得到devicetoken,打印出來就OK了,但我們還有一個(gè)問題,APPStore版本和development用的是同樣的bundleID所以devicetoken是一致的,但是如果是inhouse版本怎么辦?其實(shí)也很簡單,那就是,我們把上面那個(gè)方法里得到的devicetoken傳遞到某個(gè)頁面,然后用label或者alertview,或者其他可視的控件展示出來就好了,然后抄下來就OK啦!
OK,推送搞定!
接著我們選擇對應(yīng)的證書provision 和 bundleID就可以愉快地開發(fā)啦!