第三步:iOS系統把發來的消息傳遞給相應的應用程序,並且按照設定彈出Push通知
要能夠完整實現一條消息推送,需要我們在App ID中打開Push Notifications,需要我們準備好Provisioning Profile和SSL證書,並且一定要注意Development和Distribution環境是需要分開的。最後,把SSL證書導入到AVOS Cloud平臺,就可以嘗試遠程消息推送了。具體的操作流程可以參考我們的使用指南: iOS推送證書設置指南(https://cn.avoscloud.com/docs/ios_push_cert.html )。
知道了誰要推送,或者說要推送給哪個App之後,APNs還需要知道推到哪臺設備上,這就是設備標識的作用。獲取設備標識的流程如下:
第二步:App獲得一個DeviceToken
第三步:App將DeviceToken保存起來,這裏就是通過
[AVInstallation saveInBackground]
將DeviceToken保存到AVOS Cloud第四步:當某些特定事件發生,開發者委託AVOS Cloud來發送推送消息,這時候AVOS Cloud的推送服務器就會給APNs發送一則推送消息,APNs最後消息送到用戶設備。
推送相關的幾個概念
消息類型
一條消息推送過來,可以有如下幾種表現形式:
在應用icon上提示一個新收到的消息數(即badge)
播放一段聲音
開發者可以在每次推送的時候設置,在推送達到用戶設備時開發者也可以選擇不同的提示方式。
本地消息通知
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]; returnYES; }
如果註冊成功,APNs會返回給你設備的device 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]; } }