1、消息推送原理:php
在實現消息推送以前先說起幾個於推送相關概念,以下圖1-1:ios
一、Provider:就是爲指定IOS設備應用程序提供Push的服務器,(若是IOS設備的應用程序是客戶端的話,那麼Provider能夠理解爲服務端[消息的發起者]);json
二、APNS:Apple Push Notification Service[蘋果消息推送服務器];緩存
三、iPhone:用來接收APNS下發下來的消息;服務器
四、Client App:IOS設備上的應用程序,用來接收iphone傳遞APNS下發的消息到制定的一個客戶端 app[消息的最終響應者];網絡
上圖能夠分爲三個階段:app
階段一:Provider[服務端]把要發送的消息,目的IOS設備標識打包,發送給APNS;iphone
階段二:APNS在自身的已註冊Push服務的IOS設備列表中,查找有相應標識的IOS設備,並將消息發送到IOS設備;ide
階段三:IOS設備把發送的消息傳遞給對應的應用程序,而且按照設定彈出Push通知。工具
具體過程,以下圖1-2:
一、[Client App]註冊消息推送;
二、[Client App]跟[APNS Service]要deviceToken, Client App接收deviceToken;
三、[Client App]將deviceToken發送給[Provider]Push服務端程序;
四、當Push服務端程序知足發送消息條件了,[Provider]向[APNS Service]發送消息;
五、[APNS Service]將消息發送給[Client App].
2、消息推送實現:
一、生成*.certSigningRequest文件,步驟以下:
[MacBook-應用程序-實用工具-鑰匙串訪問-證書助手-從證書機構求證書-證書信息(用戶電子郵箱地址{填寫您的郵箱,如:your@email.com},經常使用名稱{任意,如:PushDemo},請求是:{單選,選擇‘存儲到磁盤’})-繼續-保存],這時會在您指定的地方生成你指定的文件,默認爲CertificateSigningRequest.certSigningRequest文件,這裏命名爲:PushDemo.certSigningRequest.在此*.certSigningRequest已經生成,具體操做步驟如圖所示。
若是生成成功,則會在[鑰匙串訪問|登陸|密鑰]欄目中列出與*.certSigningRequest關聯的密鑰,這裏是PushDemo,如圖所示:
二、新建一個App ID(在蘋果開發者帳號中配置)
(1) 登陸iOS Dev Center,登陸成功後,點擊(iOS Provisioning Portal對應連接),如圖所示:
(2) 建立New App ID[App IDsàManageàNew App ID]( Description{填寫您對此App ID 的描述,如:iShop},Bundle Seed ID(App ID Prefix){選擇綁定App ID前綴,如:默認選擇Generate New},Bundle Identifier(App ID Suffix){填寫綁定App ID後綴,如:com.yourcorp.iShop}),以下圖所示:
這樣就會生成下面這條記錄,如圖所示:
(3) 配置上一步中生成的App ID,讓其支持消息推送[點擊2-6中的Configureà選中Enable for Apple Push Notification serviceà點擊Configure],如圖所示:
(4) Generate a Certificate Signing Request(生成部署請求認證)[點擊2-7中的2ConfigureàContinueà步驟1生成的*certSigningRequest文件(這裏是iShop. certSigningRequest)-Generate-生成完成後將其下載下來,命名爲:aps_developer.cer],雙擊aps_developer.cer證書{將證書與密鑰關聯,並將證書導入到MacBook中},以下圖所示:
(5) 建立Development Provisioning Profiles[開發許可配置文件](Provisioning| Development|New Profile),具體操做流程以下圖所示:
點擊圖中Submit,生成Development Provisioning Profiles[開發許可配置文件],這裏是:iShopDevprofile.mobileprovision以下圖所示:
下載此開發許可證書(用於聯機調試)。
總結,到如今爲止,咱們已經生成:A:*.certSigningRequest文件(在步驟(4)中使用,用於生成證書B)、B:aps_developer_identity.cer證書(在Provider[Push服務器]服務端應用使用)、C:*..mobileprovision開發許可配置文件(在Client App客戶端應用聯機調試使用)。
三、新建一個項目
1. 建立一個"single view application" project,爲省事,你設置的"Company Identifier" + "Production「必須和step 5建立的App ID的"bundle identifier"一致。
2. 在AppDelegate.m file的"didFinishLaunchingWithOptions" method裏,添加下列代碼 (用於爲app register push notification feature):
// Let the device know we want to receive push notifications
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
3. 在AppDelegate.m file裏添加下列2個methods (用來handle register remote notification with device token和register error的events)
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
NSLog(@"My token is: %@", deviceToken);
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(@"Failed to get token, error: %@", error);
}
4. 運行該app in real device (simulator doesn't support push notification)。這時你會在device上看到一個popup window (該窗口只會出現一次,重裝app不會再出現),提示你該app會send push notification給你,若是贊成則clickOK,不一樣意則click "Now allow」。若是選擇了OK,那麼在"Setting > Notifications「裏會有你的app在list裏。並且這時你的Xcode output console會顯示你的device token。
5: export "PushDemo" private key to a ".p12" file(該文件會在後面生成apns provider的.p12 or .pem file時用到)
1). right click "PushDemo「 private key and select "Export ..."PushDemo
2). Save the private key as 「PushDemoKey.p12」 file, click Save button
3). 這時會讓你輸入2次用於加密該.p12 file的密碼,例如用"123321",接着會要求你輸入一次your mac account password
6: 在5中生成的「PushDemoKey.p12」 file和step 6生成的"aps_development.cer" file是用於APNS provider side的源文件,APNS Provider side進行push message時要用到的"cert + key" file就是經過這2個file來生成。該Step就是用來生成for APNS provider side (php version)要用到這個"cert + key" pem file.
1) open Terminal, go to Desktop (假設這2個file都在desktop裏)
2) 執行下列命令來生成和apns cer file對應的pem file "PushDemoCert.pem"
openssl x509 -in aps_development.cer -inform der -out PushDemoCert.pem
3) 執行下列命令來生成和private key .p12 file對應的pem file "PushDemoKey.pem" (注意:執行過程會要求你輸入"PushDemoKey.p12"建立時設置的密碼,以及設置"PushDemoKey.pem」的密碼)
openssl pkcs12 -nocerts -out PushDemoKey.pem -in PushDemoKey.p12
4) 執行下列命令把step 11.2生成的cert pem file和step 11.3生成的key pem file合成爲一個pem file "PushDemoCK.pem"
cat PushDemoCert.pem PushDemoKey.pem > PushDemoCK.pem
7: 在5生成的「PushDemoKey.p12」 file和step 6生成的"aps_development.cer" file是用於APNS provider side的源文件,該step是簡單測試這2個file是否有效
1) open Terminal, go to Desktop (假設這2個file都在desktop裏)
2) 執行下列命令來測試是否可以connect apple提供的不經加密(即不需使用任何證書!)的APNS server
telnet gateway.sandbox.push.apple.com 2195
若是你看到下列輸出,則表示你的電腦能夠connect APNS. 若是出現error,那麼check你的firewall是否容許outgoing connections on port 2195。
Trying 17.172.233.65...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.
Press Ctrl+C to close the connection.
3) 執行下列命令來測試是否可以connect apple提供的經加密(需使用2) and 3)生成的2個pem file!)的APNS "sandbox「 server for development.
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushDemoCert.pem -key PushDemoKey.pem
執行過程當中會要你輸入PushDemoKey.pem生成時設置的密碼。若是connect server成功,就會等待你輸入字串,你能夠輸入任意字串,而後回車,就會disconnect server。若是鏈接不成功,則openssl會顯示錯誤信息。
注意:實際上有2個APNS servers: the 「sandbox」 server (用於testing) the live server(用於production mode)。咱們這裏測試的是sandbox server。live apns server的操做相似。
8: 建立provider server side (php version)
1). Download SimplePush PHP code to your mac machine and then unzip it.
2). 去掉SimplePush folder裏的pk.pem (它沒用),把step 11.4生成的"PushDemoCK.pem" copy toSimplePush folder
3). 修改simplepush.php file下面幾行:
// Put your device token here (without spaces):
//device token來自Step 10的第4點,在output console獲取,注意:要去掉先後的尖括號,和中間的全部空格
$deviceToken = '43fcc3cff12965bc45bf842bf9166fa60e8240c575d0aeb0bf395fb7ff86b465';
// Put your private key's passphrase here:
//該值是 3)生成PushDemoKey.pem時設置的密碼
$passphrase = '123456';
// Put your alert message here:
$message = 'My first push notification!';
//.....stream_context_set_option($ctx, 'ssl', 'local_cert', 'PushDemoCK.pem');
4). 在terminal window裏,go to the simplepush folder,而後執行下列命令,你的iPhone應該會收到一條push message。
php simplepush.php
注意:若是你的app在iphone裏是正在運行,並且app是在front end時,當它收到push message時是不會出如今iPhone頂部的notification area的!
參考文章:http://mmz06.blog.163.com/blog/static/121416962011111710934946/
http://user.qzone.qq.com/75869071/infocenter%23!app=2&via=QZ.HashRefresh&pos=1351564081#!app=2&via=QZ.HashRefresh&pos=1351564081
APNS的推送機制
與Android上咱們本身實現的推送服務不同,Apple對設備的控制很是嚴格,消息推送的流程必需要通過APNs:
這裏 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平臺,就能夠嘗試遠程消息推送了。具體的操做流程能夠參考咱們的使用指南:iOS推送證書設置指南。
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:方法,傳遞給它你但願支持的消息類型參數便可,例如:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // do some initiale working ... [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound]; return YES; }
若是註冊成功,APNs會返回給你設備的token,iOS系統會把它傳遞給app delegate代理——application:didRegisterForRemoteNotificationsWithDeviceToken:方法,你應該在這個方法裏面把token保存到AVOS Cloud後臺,例如:
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSLog(@"Receive DeviceToken: %@", deviceToken); AVInstallation *currentInstallation = [AVInstallation currentInstallation]; [currentInstallation setDeviceTokenFromData:deviceToken]; [currentInstallation saveInBackground]; }
若是註冊失敗,application:didFailToRegisterForRemoteNotificationsWithError:方法會被調用,經過NSError參數你能夠看到具體的出錯信息,例如:
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"註冊失敗,沒法獲取設備ID, 具體錯誤: %@", error); }
請注意:註冊流程須要在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的信息。
示例代碼以下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // do initializing works ... if (launchOptions) { // do something else ... [AVAnalytics trackAppOpenedWithLaunchOptions:launchOptions]; } [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound]; return YES; }
3,若是遠程消息發送過來的時候,app正在運行,這時候會發生什麼呢?
app代理的application:didReceiveRemoteNotification:方法會被調用,同時遠程消息中的payload數據會做爲參數傳遞進去。
示例代碼以下:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { if (application.applicationState == UIApplicationStateActive) { // 轉換成一個本地通知,顯示到通知欄,你也能夠直接顯示出一個alertView,只是那樣稍顯aggressive:) UILocalNotification *localNotification = [[UILocalNotification alloc] init]; localNotification.userInfo = userInfo; localNotification.soundName = UILocalNotificationDefaultSoundName; localNotification.alertBody = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"]; localNotification.fireDate = [NSDate date]; [[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; } else { [AVAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo]; } }
常見問題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對象。
{ aps = { alert = "hello, everyone"; badge = 2; sound = default; }; }
這裏要注意的時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:
{ action = { type = 4; }; aps = { alert = "hello, everyone"; badge = 4; }; }
「hello, everyone」會顯示到alertView中,可是整個Dictionary會經過launchOptions傳遞給application: didFinishLaunchingWithOptions: 方法,這樣咱們在程序裏面就能夠對不一樣的消息實現不一樣的跳轉了。