最近在研究iOS的推送問題,遇到了一些問題,最終整理了一下。放在這裏和你們分享php
APNS的推送機制ios
首先咱們看一下蘋果官方給出的對ios推送機制的解釋。以下圖數據庫
Provider就是咱們本身程序的後臺服務器,APNS是Apple Push Notification Service的縮寫,也就是蘋果的推送服務器。apache
上圖能夠分爲三個階段:windows
第一階段:應用程序的服務器端把要發送的消息、目的iPhone的標識打包,發給APNS。 安全
第二階段:APNS在自身的已註冊Push服務的iPhone列表中,查找有相應標識的iPhone,並把消息發送到iPhone。 服務器
第三階段:iPhone把發來的消息傳遞給相應的應用程序,而且按照設定彈出Push通知。app
APNS推送通知的詳細工做流程iphone
下面這張圖是說明APNS推送通知的詳細工做流程:ide
根據圖片咱們能夠歸納一下:
一、應用程序註冊APNS消息推送。
二、iOS從APNS Server獲取devicetoken,應用程序接收device token。
三、應用程序將device token發送給程序的PUSH服務端程序。
四、服務端程序向APNS服務發送消息。
五、APNS服務將消息發送給iPhone應用程序。
準備工做
首先要有一臺蘋果的設備,模擬器是不支持推送的,因此你須要一臺iphone,ipod touch或者ipad。
咱們的客戶端與蘋果服務器之間和咱們本身的服務器與蘋果服務器之間都須要證書來進行連接。下面咱們來開始進入證書的製做過程。
一 CSR文件
首先咱們要有生成一個Certificate Signing Request(也就是CSR)的請求文件。
在應用程序裏的使用工具中找到鑰匙串訪問。
選擇從證書頒發機構請求證書
填上你的郵箱和經常使用名,經常使用名要記一下,一會會用到。而後選擇保存到磁盤,繼續
保存位置在桌面,點擊存儲。
到這裏點擊完成後咱們會在桌面上看到一個CertificateSigningRequest.certSigningRequest的請求文件,也就是咱們說的CSR文件。在咱們生成CSR文件的同時,會在鑰匙串訪問中生成一對祕鑰,名稱爲剛纔咱們填寫的經常使用名
二 下載開發證書和發佈證書
(這裏我爲了你們能看清楚,已經把以前的證書事先吊銷了)
到https://developer.apple.com/devcenter/ios/index.action登陸後,在右側的ios Developer Program裏點擊iOS Provisioning Portal。
進入下一級頁面後在左側選擇Certificates
點擊紅色的部分生成一個開發證書
點擊選擇文件,選擇剛纔咱們生成到桌面的CSR請求文件。
注意,若是你在後面測試的時候出現了問題,請檢查一下這裏,這裏的CSR請求文件必須是咱們剛纔生成的那個
選擇完成後點擊Submit提交
提交完成後返回頁面。頁面會是這樣的,而後咱們刷新一下頁面
刷新後會出現一個下載按鈕,咱們點擊下載。如今咱們的開發證書已經配置並下載好了,發佈證書的配置過程和開發證書是一致的,再也不贅述。下載完後雙擊,會跳到鑰匙串訪問裏。這就是咱們以後要進行測的證書
三 配置AppID,配置並下載SSL證書
點擊左側的App IDs,找到咱們要作推送功能的程序的id(若是沒有的話要先New一個。注意,這裏的App ID必須不能是通配的,通配的不能夠作推送)。點擊Configure
進入後默認推送功能是關閉的,咱們須要把推送功能打開
選中打開後,點擊右邊灰色的Configure按鈕
這裏的文件一樣的,仍是選擇咱們生成在桌面上的CSR請求文件
而後點擊繼續
出現了咱們須要的SSL證書,咱們點擊下載後點擊Done完成。
Status狀態變成了綠色可用了。這裏右邊的下載和上一步的下載是同樣的,若是在上一步中下載了證書,便無需再次下載。此時咱們有了一個名字叫aps_development.cer的SSL證書,一樣,咱們把他放在桌面。雙擊後會跳到鑰匙串訪問,出現咱們的SSL推送證書
一樣的,發佈的SSL證書的步驟也是同樣的。
四 下載Provisioning證書
在左側選擇Provisioning
配置好後點擊提交(注意App ID要與咱們剛的程序對應)
以後變回出現下載按鈕,咱們點擊下載。下載後雙擊,並將咱們的設備上的描述文件更新一下(最好把以前的所有刪除,而後再安裝,防止出錯)。
五 從鑰匙串訪問中導出祕鑰
打開鑰匙串訪問,找到咱們的專用祕鑰(專用祕鑰的名稱就是咱們在最開始生成CSR請求的時候填寫的經常使用名)
右鍵選擇導出
導出的文件名咱們叫作Push
在這裏須要輸入一個密碼來對文件進行加密。這裏咱們選擇abcabc,固然你也能夠本身選擇是什麼,可是這個密碼必需要銘記,切記!
而後輸入你電腦的密碼,點擊容許。
這樣咱們就在桌面上生成了一個Push.p12文件。
到此爲止,咱們在桌面上一共生成了三個文件。一個是CSR請求文件,一個是aps_development .cer的SSL證書文件,還有一個剛纔生成的Push.p12祕鑰文件。
如今咱們的準備工做已經作完了。要開始對生成的文件進行處理了。緣由上面已經解釋過,由於咱們的服務連接蘋果服務器也是須要證書的,可是咱們直接生成的證書windows系統(咱們通常的服務器都是win系統的)是不識別的,因此咱們須要生成一個後綴爲pem的帶證書帶祕鑰的文件。
六 處理證書
下面咱們打開終端(位置:應用程序à實用工具à終端)。
cd到桌面,咱們那三個文件所在的位置
一、把.cer的SSL證書轉換爲.pem文件,執行命令:
openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem
在桌面上會生成一個PushChatCert.pem文件
二、把私鑰Push.p12文件轉化爲.pem文件:
openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12
這裏須要咱們輸入密碼,這個密碼也就是咱們導出p12文件時的密碼,也就是咱們上面設置的abcabc。而後,須要咱們對生成的pem文件設置一個密語,這裏咱們推薦仍是用上面這個abcabc,防止混亂(固然你也能夠設置成別的更有意義的密語),這裏的密語是要告訴咱們服務器的。這樣,桌面上又會生成一個PushChatKey.pem文件
三、對生成的這兩個pem文件再生成一個pem文件,來把證書和私鑰整合到一個文件裏:
cat PushChatCert.pem PushChatKey.pem > ck.pem
生成ck.pem文件
這樣,咱們的文件就製做完了。下面進入測試階段
爲了測試證書是否工做,執行下面的命令:
telnet gateway.sandbox.push.apple.com 2195
它將嘗試發送一個規則的,不加密的鏈接到APNS服務。若是你看到上面的反饋,那說明你的MAC可以到達APNS。按下Ctrl+C關閉鏈接。若是獲得一個錯誤信息,那麼你須要確保你的防火牆容許2195端口。通常這裏都不會出現什麼問題。
下面咱們要使用咱們生成的SSL證書和私鑰來設置一個安全的連接去連接蘋果服務器:
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem
執行完這一句命令後須要咱們輸入密語
Enter pass phrase for PushChatKey.pem:
咱們輸入abcabc按回車
你會看到一個完整的輸出,讓你明白OpenSSL在後臺作什麼。若是連接是成功的,你能夠隨便輸入一個字符,按下回車,服務器就會斷開連接,若是創建鏈接時有問題,OpenSSL會給你返回一個錯誤信息。
當你在最後的時候你看到這樣說明你已經成功了:
CONNECTED(00000003)
depth=1 /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa isincorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust CertificationAuthority - L1C
verify error:num=20:unable to get local issuercertificate
verify return:0
---
Certificate chain
0s:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=iTMSEngineering/CN=gateway.sandbox.push.apple.com
i:/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated byreference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
1s:/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated byreference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
i:/O=Entrust.net/OU=www.entrust.net/CPS_2048incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.netCertification Authority (2048)
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFGzCCBAOgAwIBAgIETBz90jANBgkqhkiG9w0BAQUFADCBsTELMAkGA1UEBhMC
……省略……
fMGbLqkGn8YogdPqe5T1
-----END CERTIFICATE-----
subject=/C=US/ST=California/L=Cupertino/O=AppleInc./OU=iTMS Engineering/CN=gateway.sandbox.push.apple.com
issuer=/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa isincorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust CertificationAuthority - L1C
---
No client certificate CA names sent
---
SSL handshake has read 2731 bytes and written 2165 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : AES256-SHA
Session-ID:
Session-ID-ctx:
Master-Key:C7A47EED5E1F5……省略……369D4
Key-Arg : None
Start Time:1361862882
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
在這裏提醒一下,也許你會看到像我這樣的提示:verify error:num=20:unable to get local issuercertificate
verify return:0
實際上是沒問題的。
七 項目測試
創建咱們的推送的項目(注意BundleIdentifier必須和咱們推送應用的App id一致)
在AppDelegate裏didFinishLaunchingWithOptions函數裏寫
- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
……
//推送的形式:標記,聲音,提示
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
return YES;
}
- (void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {
NSLog(@"regisger success:%@",pToken);
//註冊成功,將deviceToken保存到應用服務器數據庫中
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
// 處理推送消息
NSLog(@"userinfo:%@",userInfo);
NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
}
- (void)application:(UIApplication *)applicationdidFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Registfail%@",error);
}
咱們運行程序的時候會有提示,說咱們的程序要發送推送通知
下面咱們把php服務器代碼和生成的ck.pem文件放在統一文件夾下面(這裏咱們仍是統一放在桌面上)。
用Xcode打開(其餘工具也能夠)php服務器端的代碼,把deviceToken改爲咱們如今要進行測試的iphone的deviceToken(得到方法:首先運行咱們的程序,程序啓動後打印的日誌文件裏能夠看到。感謝 邊玩勺子把兒去 同窗的提醒),密語改爲咱們以前設置的abcabc。而後保存。
而後在終端運行命令(若是剛纔你關閉了終端的話,最好ls一下,看看當前是否是在桌面),執行命令:
php pushMe.php
而後回車(pushMe爲服務器文件名稱)
若是出現這樣的提示說明成功了,而後在iphone上,咱們期待已久的推送消息終於來了。
如下是推送的幾種效果:
常見問題:
一、在用證書和祕鑰連接服務器時出現提示:
Error opening client certificate private key filePushChatKey.pem
20839:error:02001002:system library:fopen:No such file ordirectory:/SourceCache/OpenSSL098/OpenSSL098-44/src/crypto/bio/bss_file.c:356:fopen('PushChatKey.pem','r')
20839:error:20074002:BIO routines:FILE_CTRL:systemlib:/SourceCache/OpenSSL098/OpenSSL098-44/src/crypto/bio/bss_file.c:358:
unable to load client certificate private key file
解決:
文件路徑不對。cd到生成的pem文件路徑下再進行連接
二、前期測試沒有問題,將ck.pem給服務器,經過服務器進行推送時推送不成功,提示連接APNS失敗。
解決:一,看一下證書的名稱,密語是否正確;二,路徑是否正確;而後檢查一下庫,OpenSSL和libssl;此外apache還要開啓OpenSSL權限,確保能夠訪問pem
三、APNS地址
測試地址gateway.sandbox.push.apple.com:2195
發佈地址 gateway.push.apple.com:2195
測試的地址用的是沙盒,發佈地址是不一樣的。發佈軟件的時候記得改過來
四、要注意順序問題,必定要按照這個順序來:
生成鑰匙串請求 -->配置下載開發證書--> 配置App ID ,配置、下載SSL證書-->Provisioning證書