iOS遠程推送,從機制到實現,盡量詳細


   本人第一次寫博客,寫的不好的地方大家請見諒。

   本文主要參考了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,回車執行。

 

好了,終於寫完了,第一次寫博客太費勁了,之前保存草稿后再打開草稿沒有圖片了,圖還得重新截,還有寫了一半就瀏覽器'死了',還是重新寫。。。額,就想了個辦法,先把所有圖截好,再寫博客,這樣還好。總之寫完了,寫的不好的地方大家輕噴啊~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM