細說 iOS 消息推送
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的推送server就會給APNs發送一則推送消息,APNs最後消息送到用戶設備
推送相關的幾個概念
消息類型
一條消息推送過來,能夠有例如以下幾種表現形式:
開發人員能夠在每次推送的時候設置。在推送達到用戶設備時開發人員也能夠選擇不同的提示方式。
本地消息通知
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,用戶看到消息之後。點擊了一下actionbutton或者點擊了應用圖標
假設actionbutton被點擊了,系統會通過調用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
我能推送長消息嗎
不能,APNs限制了每一個notification的payload最大長度是256字節,超長的消息是不能發送的。
推送怎麽加聲音提醒
消息推送是能夠指定聲音的。譬如你能夠對正面的反饋使用歡快的聲音,對負面的反饋使用低沈一點的聲音,都能夠達到別出心裁讓人眼前一亮的目的。
你須要先放一些aiff、wav或者caf音頻文件到app的資源文件裏。然後在推送的時候指定不同的音頻文件名稱就能夠了。
推送的Badge是怎麽回事
推送並不一定會導致應用圖標上紅色數字添加,是否顯示這一數字,顯示成多少。都取決於開發人員自己。
在發送推送消息的時候,我們能夠選擇是否遞增這一數字;假設不選擇這一項。那麽消息推送並不會導致應用圖標上紅色數字的出現。
好。如今問題來了。這個數字假設搞出來了,怎麽讓它消失掉呢?
事實上我們僅僅須要在不論什麽時候設置 UIApplication.applicationIconBadgeNumber 屬性為0,就能夠讓這個數字消失掉。
一般我們會選擇在應用啟動的時候(application:didFinishLaunchingWithOptions:方法中)。或者幹脆一點,在應用每次被切換到前臺的時候(applicationWillEnterForeground:方法中),調用這一行代碼。就可以立馬清除掉Badge數字了。
AVOS Cloud平臺發出去的通知格式到底是什麽樣子的
對於每一條推送消息。都包括一個payload,一般是組成了一個JSON的Dictionary,這當中不可缺少的是aps屬性,它相應的value也是一個Dictionary,包括以下一些內容:
在由推送激活的app打開事件中,
application:didFinishLaunchingWithOptions:
的options參數就是這個大的Dictionary對象。
{
aps = {
alert = "hello, everyone";
badge = 2;
sound = default;
};
}
這裏要註意的時alert部分。它的值能夠是一個String(文本消息),也能夠是一個JSON的Dictionary。當它是文本消息的時候,系統就會把這些文字顯示到一個alertview中;假設它也是由一個JSON Dictionary組成的話。其格式例如以下:
body部分就是alertView中將要展現出來的文本消息,loc-屬性主要是用來實現本地化消息,launch-image僅僅是app主bundle裏的一個圖片文件的名稱。一般來說我們不指定這一屬性。
怎樣顯示本地化的消息
有兩種辦法能夠實現推送消息的本地化:
1,在推送的payload中使用loc-key和loc-args來指定進行本地化,這樣Provider方僅僅須要依照統一的格式來發送就可以。消息的解析和組裝則由client來完畢。
2。假設推送的payload裏面不包括loc-key/loc-args信息。那麽Provider方就須要自己做本地化處理,然後給不同的device發送不同的消息。為了做到這一點,還須要app在上傳device token的時候也把用戶的語言設置信息傳回來。
眼下,由於AVOS Cloud主要就是瞄準中國大陸市場和海外中文用戶。所以我們在推送上還不提供多語言支持。
應用該怎麽響應推送消息
上面說的處理流程。僅僅能簡單展示一下遠程消息,激活用戶讓他們又一次回到app中來。可是有時候。我們希望帶給用戶更好的使用體驗。譬如假設我們告訴用戶:張三剛剛評論了你的照片。這時候用戶假設點擊actionbutton進入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: 方法,這樣我們在程序裏面就能夠對不同的消息實現不同的跳轉了。
http://blog.csdn.net/kylinbl/article/details/6729369
細說 iOS 消息推送