本人第一次寫博客,寫的不好的地方大家請見諒。
本文主要參考了http://blog.csdn.net/showhilllee/article/details/8631734,感謝showhilllee詳細的講解。因為在做的過程中有些自己的理解和變化,所以自己再寫一遍關於推送的詳細博客。
本文分為四部分介紹:
一、解釋APNS遠程推送
二、配置推送的證書
三、導出自己服務器可用的證書
四、代碼實現設備注冊推送、獲取推送消息
好了,現在開始正式講解推送。
一、首先上一個老圖,蘋果很早就給大家的,推送流程圖。
雖然ios更新很多版本,但是推送的這個流程從沒有變過。推送的機制是:設備應用中首次打開向APNS(蘋果推送服務器)注冊推送,並獲取設備令牌deviceToken->應用內將deviceToken發送到自己的推送服務器或第三方推送服務器進行保存->自己的服務器或第三方推送服務器將消息和deviceToken捆綁發送到APNS->APNS發送消息到設備,設備顯示推送消息。
deviceToken類似UUID,在應用第一次請求deviceToken后,如果應用沒有刪除重新安裝deviceToken是不會變的,應用刪除后再重新安裝,再注冊遠程推送后deviceToken會變化。所以每次應用打開都應該去注冊推送並請求deviceToken,第一次會有系統提示是否推送,選擇推送后,會收到回調函數中deviceToken,第一次會有些延遲,以后再開應用請求deviceToken就秒回了。
蘋果的APNS服務器就是專門做推送的,分為測試地址和正式地址,所有蘋果的推送消息都要經過APNS推送發到設備,無論測試還是正式。其實推送的原理就是設備將獲得的deviceToken發送給自己的服務器保存,自己的服務器選擇保存的deviceToken和要推送的消息打包發給APNS,APNS自動推送到指定的設備上。第三方推送在蘋果推送這方面只是在自己的服務器和APNS中間加了一步,自己的服務器將消息和設備標識發給第三方服務器,第三方推送再將設備表示找到deviceToken,將消息發送到APNS。
二、配置推送的證書
1.打開本地鑰匙串,左上角鑰匙串訪問-》證書助理-》從證書頒發機構請求證書
用戶電子郵件地址一般就填開發者賬號郵箱,選擇存儲到磁盤,保存在桌面,名字不用改。
2、(1)打開瀏覽器,登錄apple developer,選擇頂部導航欄Account,登錄
進入界面后,選擇Certificates-Development 點擊右上角加號
選擇Development的第二個選項,蘋果開發服務證書Apple Push Notification service SSL(APNs),點擊continue
這里需要選擇一個App ID,我們先不講從哪生成,假設已經有了一個了,點擊下一步continue
點擊choose file 選擇本機生成的
點擊continue,下載生成的aps_development.cer文件,並保存在桌面新建一個push的文件夾。
(2)下面說下App ID新建,點擊Identifiers->App IDs->右上角加號
進入此界面后,name就設為你項目的名字吧(隨意),Bundle ID要與項目中Bundle ID一致,選擇Explicit AppID是為了唯一證書,Wildcard App ID是團隊證書,做推送不用Wildcard App ID,要選擇Explicit AppID。
在此頁面下面勾上Push Notifications
點擊continues后在此界面點擊register就好了
接下來就是在(1)部分中填寫App ID的步驟了。
(3)下載.mobileprovision文件 點擊Provisioning Profiles-》All-》右上角加號。
因為是開發環境,所以選擇Development的ios app,發布環境就選擇Distribution。接下來選擇AppID,Cer,Devices,也就是“哪個應用,哪個證書,哪個設備”的邏輯。
Profile Name可以隨便起。下載.mobileprovision文件並放在剛才新建的push文件夾。
好了,至此,證書都配置好了。
三、配置.p12文件和windows服務器所需的.pem文件
.p12文件是服務器推送需要的驗證證書,如果用第三方推送則需要這個文件,先講怎么生成這個文件
1、首先雙擊安裝上一節生成的.cer和.mobileprovision文件,安裝。
打開鑰匙串,找到剛安裝的.cer證書,點擊-》右鍵-》導出"*****",彈出這個窗口
名字隨便起,為防止意外不要用中文了,保存到剛才新建的push文件夾,點擊存儲后彈出這個窗口
這是.p12文件需要設置一個訪問密碼,輸入密碼,簡單點就123456了,驗證這再輸入一遍剛才輸入的123456,點擊好。
如果用第三方推送那導出.p12文件就夠了。
2、如果自己搭建推送服務器還是windows的就需要.pem文件了,下面我們將.cer文件和剛生成的.p12文件分別轉換成.pem文件。
打開終端,敲入cd 並把push文件夾的路徑輸入,回車,進入push文件夾
可以敲完cd空格后,在finder中找到push文件夾,按住畫圈的push那藍色的文件夾圖標拖入終端,直接顯示路徑。
(1)進入push文件夾后輸入指令:openssl x509 -in aps_development.cer -inform der -out PushChatCert1.pem
這個指令的意思是將下載的aps_development.cer證書文件生成名叫PushChatCert1的.pem文件,這個.pem文件名隨便起,但你要標示出這個是.cer文件轉換生成的。
(2)再輸入指令:openssl pkcs12 -nocerts -out PushChatKey.pem -in SharePush.p12,輸入p12密碼並設置pem密碼,為了方便設置成一樣的。 這個指令是將.p12文件生成.pem文件,PusheChatKey.pem的名字隨便起,同上,也要知道這個是.p12文件生成的。
輸入完指令后需要輸入.p12的密碼,回車后需要設置這個.pem文件的密碼,為了方便設置和.p12文件一樣的密碼123456
(3)將剛才生成的兩個.pem文件合成一個.pem文件,指令:cat PushChatCert1.pem PushChatKey.pem > ck.pem
合成新的.pem文件名叫ck,這個隨便起,自己記住就行。
(4)接下來測試一下這兩個文件連接蘋果測試推送服務器
輸入測試連接指令:telnet gateway.sandbox.push.apple.com 2195。control+c斷連接
輸入測試通知指令:通知openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert1.pem -key PushChatKey.pem 。輸入任何字符切斷連接
ok,至此環境和證書都配置好了。下面開始敲代碼。
四、打開xcode,新建一個項目,這個就不說了,打開Appdelegate.m文件
(1)在
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions函數中輸入下面代碼來想APNs注冊推送,第一行代碼的意思是當應用打開后將應用圖標右上角消息數置空。
后面判斷設備系統版本的原因是自iOS8.0后推送通知的函數發生了變化。
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; if ([[[UIDevice currentDevice] systemVersion] floatValue]>=8.0) { [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]]; [[UIApplication sharedApplication] registerForRemoteNotifications]; }else{ [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeAlert]; }
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{ //這里處理deviceToken,將獲取的deviceToken保存自己的服務器或者與別的信息一起捆綁 }
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ // NSLog(@"userinfo:%@",userInfo); // NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]); NSString *message = [NSString stringWithFormat:@" 新消息:%@",[[userInfo objectForKey:@"aps"]objectForKey:@"alert"]]; }
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err { NSString *str = [NSString stringWithFormat: @"Error: %@", err]; NSLog(@"獲取令牌失敗: %@",str); }
didRegisterForRemoteNotificationsWithDeviceToken這個函數的作用是注冊成功后返回devicetoken。
didReceiveRemoteNotification這個函數的作用是獲取到推送消息回調的,參數userInfo是消息體,類型是字典型,通過[[userInfo objectForKey:@"aps"]objectForKey:@"alert"]可取到具體的消息內容。
didFailToRegisterForRemoteNotificationsWithError這個函數的作用是如果注冊推送失敗了回調,你可以做一些處理。
這樣項目中也寫好了推送的代碼,下面簡單寫了一個php文件,當服務器給蘋果推送發一條推送,devicetoken就用剛才項目執行后收到的devicetoken。
五、php代碼
<?php // ??????????deviceToken??????????????? $deviceToken = '這里寫獲取到的devicetoken'; // Put your private key's passphrase here: $passphrase = '這里寫之前設置的pem文件的密碼'; // Put your alert message here: $message = '推送測試:hellow world!'; //////////////////////////////////////////////////////////////////////////////// $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'local_cert', '這里寫之前把兩個pem文件合成的一個pem文件名'); stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase); // Open a connection to the APNS server //?????????? //$fp = stream_socket_client(?ssl://gateway.push.apple.com:2195?, $err, $errstr, 60, //STREAM_CLIENT_CONNECT, $ctx); //?????????????appstore?????? $fp = stream_socket_client( 'ssl://gateway.sandbox.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; // Create the payload body $body['aps'] = array( 'alert' => $message, 'badge' => 1, 'sound' => 'default' ); // Encode the payload as JSON $payload = json_encode($body); // Build the binary notification $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload; // Send it to the server $result = fwrite($fp, $msg, strlen($msg)); if (!$result) echo 'Message not delivered' . PHP_EOL; else echo 'Message successfully delivered' . PHP_EOL; // Close the connection to the server fclose($fp); ?>
保存php文件在之前說的push文件夾,名字就叫push.php。
打開終端,進入push文件夾,輸入指令:php push.php,回車執行。
好了,終於寫完了,第一次寫博客太費勁了,之前保存草稿后再打開草稿沒有圖片了,圖還得重新截,還有寫了一半就瀏覽器'死了',還是重新寫。。。額,就想了個辦法,先把所有圖截好,再寫博客,這樣還好。總之寫完了,寫的不好的地方大家輕噴啊~