iOS 遠程推送的實現

iOS的推送能夠用下圖簡單的歸納:php

這裏 Provider 是指某個應用的Developer,固然若是開發者使用AVOS Cloud的服務,把發送消息的請求委託給咱們,那麼這裏的Provider就是AVOS Cloud的推送服務程序了。上圖能夠分爲三步:
 
第一步:AVOS Cloud推送服務程序把要發送的消息、目的設備的惟一標識打包,發給APNs。
第二步:APNs在自身的已註冊Push服務的應用列表中,查找有相應標識的設備,並把消息發送到設備。
第三步:iOS系統把發來的消息傳遞給相應的應用程序,而且按照設定彈出Push通知
 
爲了實現消息推送,有兩點很是重要:
 
1. App的推送證書
 
要可以完整實現一條消息推送,須要咱們在App ID中打開Push Notifications,須要咱們準備好Provisioning Profile和SSL證書,而且必定要注意Development和Distribution環境是須要分開的。最後,把SSL證書導入到AVOS Cloud平臺,就能夠嘗試遠程消息推送了。具體的操做流程以下:

(1). 登陸 iPhone Developer Connection Portal 連接) 而後點擊 App IDs
(2). 建立一個 Apple ID ,如:com.chenjungang.apnstest  注意:通配符 ID 不能用於推送通知服務
(3). 點擊 Apple ID 旁的「Configure」,根據「嚮導」 的步驟生成一個簽名上傳,而後下載生成的許可證。
(4). 雙擊 .cer 文件將你的 aps_development.cer 導入 Keychain 中。
(5). 在 Mac 上打開「鑰匙串訪問」,而後在「登陸」中選擇 "密鑰"分類,找到咱們建立的證書,而後右擊「Apple Development IOS Push Services: com.tadpole.TestAPNs」 > 導出 「Apple Development IOS Push Services: com.chenjungang.apnstest」。保存爲 cert.p12 文件。
(6). 經過終端命令將這個 cert.p12 文件轉換爲 PEM 格式,打開終端, cd 進入證書所在目錄,執行以下命令:(Java 直接給 .p12 文件,Phppem 文件)node

openssl pkcs12 -in cert.p12 -out apple_push_notification_production.pem -nodes -clcerts

執行完上面命令會在當前目錄下生成一個名爲apple_push_notification_production.pem文件,這個文件就是咱們須要獲得php鏈接APNS 的文件,將apple_push_notification_production.pem和push.php放入同一目錄上傳到服務器,push.php的代碼以下:json

 

 1 <?php 
 2 $deviceToken = 'ad853c20 3a9b874e 00d0cde2 44a73752 999bb250 9fa36129 0525d5d0 a6ba3e4c';
 3 
 4 // Put your private key's passphrase here:
 5 $passphrase = '123456';
 6 
 7 // Put your alert message here:
 8 $message = 'This is some push message!';
 9 $ctx = stream_context_create();
10 stream_context_set_option($ctx, 'ssl', 'local_cert', 'apple_push_notification_production.pem');
11 stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
12 
13 // Open a connection to the APNS server
14 //這個爲正式的發佈地址
15  //$fp = stream_socket_client(「ssl://gateway.push.apple.com:2195「, $err, $errstr, 60, //STREAM_CLIENT_CONNECT, $ctx);
16 //這個是沙盒測試地址,發佈到appstore後記得修改哦
17 $fp = stream_socket_client(
18 'ssl://gateway.sandbox.push.apple.com:2195', $err,
19 $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
20 if (!$fp)
21 exit("Failed to connect: $err $errstr" . PHP_EOL);
22 echo 'Connected to APNS' . PHP_EOL;
23 
24 // Create the payload body
25 $body['aps'] = array(
26 'alert' => $message,
27 'sound' => 'default'
28 );
29 
30 // Encode the payload as JSON
31 $payload = json_encode($body);
32 
33 // Build the binary notification
34 $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
35 
36 // Send it to the server
37 $result = fwrite($fp, $msg, strlen($msg));
38 
39 if (!$result)
40 echo 'Message not delivered' . PHP_EOL;
41 else
42 echo 'Message successfully delivered' . PHP_EOL;
43 
44 // Close the connection to the server
45 fclose($fp);
46 
47 ?>
PHP

 

2. 設備標識DeviceToken
 
知道了誰要推送,或者說要推送給哪一個App以後,APNs還須要知道推到哪臺設備上,這就是設備標識的做用。獲取設備標識的流程以下:
 
 
第一步:App打開推送開關,用戶要確認TA但願得到該App的推送消息
第二步:App得到一個DeviceToken
第三步:App將DeviceToken保存起來,這裏就是經過[AVInstallation saveInBackground]將DeviceToken保存到AVOS Cloud
第四步:當某些特定事件發生,開發者委託AVOS Cloud來發送推送消息,這時候AVOS Cloud的推送服務器就會給APNs發送一則推送消息,APNs最後消息送到用戶設備
 
推送相關的幾個概念
消息類型
一條消息推送過來,能夠有以下幾種表現形式:
1. 顯示一個alert或者banner,展示具體內容
2. 在應用icon上提示一個新到消息數
3. 播放一段聲音
 
開發者能夠在每次推送的時候設置,在推送達到用戶設備時開發者也能夠選擇不一樣的提示方式。
 
本地消息通知
iOS上有兩種消息通知,一種是本地消息(Local Notification),一種是遠程消息(Push Notification,也叫Remote Notification),設計這兩種通知的目的都是爲了提醒用戶,如今有些什麼新鮮的事情發生了,吸引用戶從新打開應用。
 
本地消息何時有用呢?譬如你正在作一個To-do的工具類應用,對於用戶加入的每個事項,都會有一個完成的時間點,用戶能夠要求這個To-do應用在事項過時以前的某一個時間點提醒一下TA。爲了達到這一目的,App就能夠調度一個本地通知,在時間點到了以後發出一個Alert消息或者其餘提示。
咱們在處理推送消息的時候,也能夠綜合運用這兩種方式。
 
代碼裏面如何實現推送
首先,咱們要獲取DeviceToken。
App須要每次啓動的時候都去註冊遠程通知——經過調用UIApplication的registerForRemoteNotificationTypes:方法,傳遞給它你但願支持的消息類型參數便可,例如:
 
 1 #define IS_IOS8_AND_UP ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)
 2 
 3 -(void)settingPushMessage:(UIApplication*)application
 4 {
 5     
 6     if (IS_IOS8_AND_UP) {
 7         [application registerForRemoteNotifications];
 8         UIUserNotificationType types = UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert;
 9         [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:types categories:nil]];
10     }else{
11         //消息推送支持的類型
12         UIRemoteNotificationType types =
13         (UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound);
14         //註冊消息推送
15         [[UIApplication sharedApplication]registerForRemoteNotificationTypes:types];
16     }
17     
18 }
19 
20 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
21 {
22     //獲取token
23     NSString* token = [NSString stringWithFormat:@"%@",deviceToken];
24     token = [token stringByReplacingOccurrencesOfString:@"<" withString:@""];
25     token = [token stringByReplacingOccurrencesOfString:@">" withString:@""];
26     [[NSUserDefaults standardUserDefaults] setObject:token forKey:@"APVNToken"];
27     
28     NSLog(@"token====%@",token);
29 }
30 - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
31 {
32     //這裏是獲取token失敗
33     NSString *error_str = [NSString stringWithFormat: @"%@", error];
34     NSLog(@"Failed to get token, error:%@", error_str.description);
35 }
36 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
37 {
38     //在此處理接收到的消息。
39     NSLog(@"Receive remote notification : %@",userInfo);
40 }
View Code
 
請注意:註冊流程須要在app每次啓動時調用,這並不不會帶來額外的負擔,由於iOS操做系統在第一次得到了有效的device token以後,會本地緩存起來,之後app再調用registerForRemoteNotificationTypes:的時候會馬上返回,並不會再進行網絡請求。另外,app層面不該該對device token進行緩存,由於device token也有可能變化——若是用戶重裝了操做系統,那麼APNs再次給出的device token就會和以前的不同,又或者是,用戶restore了原來的backup到新的設備上,那麼原來的device token也會失效。
 
其次,咱們要處理收到消息以後的回調
咱們能夠設想一下消息通知的幾種使用場景:
1,在app沒有被啓動的時候,接收到了消息通知。這時候操做系統會按照默認的方式來展示一個alert消息,在app icon上標記一個數字,甚至播放一段聲音。
 
2,用戶看到消息以後,點擊了一下action按鈕或者點擊了應用圖標。若是action按鈕被點擊了,系統會經過調用application:didFinishLaunchingWithOptions:這個代理方法來啓動應用,而且會把notification的payload數據傳遞進去。若是應用圖標被點擊了,系統也同樣會調用application:didFinishLaunchingWithOptions:這個代理方法來啓動應用,惟一不一樣的是這時候啓動參數裏面不會有任何notification的信息。
 
3,若是遠程消息發送過來的時候,app正在運行,這時候會發生什麼呢?
 
app代理的application:didReceiveRemoteNotification:方法會被調用,同時遠程消息中的payload數據會做爲參數傳遞進去。
 
常見問題FAQ
1. 我能推送長消息嗎? 
不能,APNs限制了每一個notification的payload最大長度是256字節,超長的消息是不能發送的。
 
2. 推送怎麼加聲音提醒? 
消息推送是能夠指定聲音的。譬如你能夠對正面的反饋使用歡快的聲音,對負面的反饋使用低沉一點的聲音,均可以達到別出心裁讓人眼前一亮的目的。
 
你須要先放一些aiff、wav或者caf音頻文件到app的資源文件中,而後在推送的時候指定不一樣的音頻文件名就能夠了。
 
3. 推送的Badge是怎麼回事? 
推送並不必定會致使應用圖標上紅色數字增長,是否顯示這一數字,顯示成多少,都取決於開發者本身。
 
在發送推送消息的時候,咱們能夠選擇是否遞增這一數字;若是不選擇這一項,那麼消息推送並不會致使應用圖標上紅色數字的出現。
 
好,如今問題來了,這個數字若是搞出來了,怎麼讓它消失掉呢?
 
其實咱們只須要在任什麼時候候設置 UIApplication.applicationIconBadgeNumber 屬性爲0,就可讓這個數字消失掉。
 
通常咱們會選擇在應用啓動的時候(application:didFinishLaunchingWithOptions:方法中),或者乾脆一點,在應用每次被切換到前臺的時候(applicationWillEnterForeground:方法中),調用這一行代碼,便可馬上清除掉Badge數字了。
 
4. AVOS Cloud平臺發出去的通知格式到底是什麼樣子的
對於每一條推送消息,都包含一個payload,一般是組成了一個JSON的Dictionary,這其中必不可少的是aps屬性,它對應的value也是一個Dictionary,包含下面一些內容:
1)alert消息(文本或Dictionary)
2)應用圖標上的紅色數字
3)播放的聲音文件名
 
在由推送激活的app打開事件中,application:didFinishLaunchingWithOptions:的options參數就是這個大的Dictionary對象。
 
1 { 
2     aps =     { 
3         alert = "hello, everyone"; 
4         badge = 2; 
5         sound = default; 
6     }; 
7 } 

 

這裏要注意的時alert部分,它的值能夠是一個String(文本消息),也能夠是一個JSON的Dictionary。當它是文本消息的時候,系統就會把這些文字顯示到一個alertview中;若是它也是由一個JSON Dictionary組成的話,其格式以下:
* body
* action-loc-key
* loc-key
* loc-args
* launch-image
 
body部分就是alertView中將要展示出來的文本消息,loc-屬性主要是用來實現本地化消息,launch-image只是app主bundle裏的一個圖片文件的名稱,通常來講咱們不指定這一屬性。
 
5. 如何顯示本地化的消息
有兩種辦法能夠實現推送消息的本地化:
1)在推送的payload中使用loc-key和loc-args來指定進行本地化,這樣Provider方只須要按照統一的格式來發送便可,消息的解析和組裝則由客戶端來完成。
2)若是推送的payload裏面不包含loc-key/loc-args信息,那麼Provider方就須要本身作本地化處理,而後給不一樣的device發送不一樣的消息,爲了作到這一點,還須要app在上傳device token的時候也把用戶的語言設置信息傳回來。
目前,由於AVOS Cloud主要就是瞄準中國大陸市場和海外中文用戶,因此咱們在推送上還不提供多語言支持。
 
6. 應用該怎麼響應推送消息 
上面說的處理流程,只能簡單展現一下遠程消息,激活用戶讓他們從新回到app中來。可是有時候,咱們但願帶給用戶更好的使用體驗,譬如若是咱們告訴用戶:張三剛剛評論了你的照片。這時候用戶若是點擊action按鈕進入app,咱們是展現具體的評論頁面爲好,仍是展現一般的啓動頁面而後讓用戶本身去找張三的評論好?我想負責任的開發者都會選擇前者。
 
要作到靈活響應不一樣類型的通知消息,咱們須要在通知的payload中增長更多信息,而不能僅僅只有alert出來的文字信息。對於AVOS Cloud消息推送平臺來說,就須要開發者使用更高級功能的JSON格式。譬如咱們發送這樣的json字符串{"action":{"type":4},"alert":"hello, everyone」} 最終在app內會收到這樣的UserInfo Dictionary:
 
1 { 
2     action =     { 
3         type = 4; 
4     }; 
5     aps =     { 
6         alert = "hello, everyone"; 
7         badge = 4; 
8     }; 
9 } 

 

「hello, everyone」會顯示到alertView中,可是整個Dictionary會經過launchOptions傳遞給application: didFinishLaunchingWithOptions: 方法,這樣咱們在程序裏面就能夠對不一樣的消息實現不一樣的跳轉了。
相關文章
相關標籤/搜索