本文根據(jù)此文稍作精簡: http://www.reibang.com/p/d18c51b3321d
作者:Poker_Facer
一、本文總結(jié)了項目iOS8-10的通知適配工作
iOS推送通知幾乎每年都在改铃在,直到iOS10的出現(xiàn),蘋果對這塊進行了重構(gòu)拇泣。本文總結(jié)了一下項目中iOS8-10的通知模塊適配工作。
二矮锈、實際開發(fā)中的適配工作
在實際開發(fā)中霉翔,iOS8-10的適配代碼如下:
- (void)setupWithOptions:(NSDictionary *)launchOptions {
// iOS8-10.0 注冊通知
if (!IS_IOS(10.0)) {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
// iOS10.0+ 開啟通知權(quán)限
else {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
UNAuthorizationOptions options = UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert;
[center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
}
// 啟動極光推送SDK
[JPUSHService setupWithOption:launchOptions
appKey:kJPUSHAppKey
channel:channel
apsForProduction:VERSION_RELEASE
advertisingIdentifier:nil];
// 極光推送日志打印開關(guān)
if (VERSION_RELEASE) {
[JPUSHService setLogOFF];
} else {
[JPUSHService setDebugMode];
}
// 注冊極光推送(內(nèi)部會調(diào)用registerForRemoteNotifications注冊APNS)
JPUSHRegisterEntity *entity = [[JPUSHRegisterEntity alloc] init];
entity.types = JPAuthorizationOptionAlert | JPAuthorizationOptionBadge | JPAuthorizationOptionSound;
[JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
}
iOS10通過UNNotificationTrigger這個類的子類來區(qū)分遠程通知和本地通知。
iOS8 通知請求權(quán)限修改愕难。即UIRemoteNotificationType由UIUserNotificationType代替早龟,并加入了UIUserNotificationSettings。
iOS9 通知加入可輸入操作猫缭。
iOS10 通知重構(gòu)葱弟,全新框架UNUserNotifications。
三猜丹、遠程通知與本地通知的觸發(fā)和調(diào)用
各版本通知中使用的類圖表:
1芝加、普通本地通知
- 程序殺死狀態(tài)。
所有版本射窒,本地通知在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法中獲取藏杖。[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]
即為我們需要的本地通知對象。沒有通知時launchOptions為空脉顿。 - 程序后臺狀態(tài)蝌麸。
iOS10以下,在點擊通知會調(diào)用- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
方法艾疟。
iOS10會調(diào)用- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler
方法来吩。 - 程序前臺狀態(tài)。
iOS10以下不會觸發(fā)通知欄蔽莱,并且還是調(diào)用- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
方法弟疆。
iOS10會立馬觸發(fā)- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
方法,并且能根據(jù)completionHandler回調(diào)配置通知的顯示樣式盗冷。點擊通知后同樣會觸發(fā)- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler
方法怠苔。
值得注意的是,程序后臺狀態(tài)下仪糖,代理方法都是在用戶點擊通知后才會執(zhí)行柑司,收到通知點擊應(yīng)用圖標(biāo)啟動是不會走代理方法的。
程序殺死狀態(tài)下啟動應(yīng)用只會觸發(fā)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法锅劝。
iOS10所有的通知帜羊,都只會觸發(fā)下面兩個方法。而區(qū)分遠程還是本地通知鸠天,就是前面提到的UNNotificationTrigger的子類讼育,當(dāng)UNNotificationRequest的trigger為UNPushNotificationTrigger時,說明此通知為遠程通知,否則為本地通知奶段。下面為代理方法:
// iOS10通知代理方法饥瓷,應(yīng)用程序在前臺的時候調(diào)用
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
UNNotificationRequest *request = notification.request;
NSDictionary *userInfo = request.content.userInfo;
if ([request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
NSLog(@"收到了一個遠程推送:%@", userInfo);
} else {
NSLog(@"收到了一個本地推送:%@", userInfo);
}
//此方法回調(diào),設(shè)置程序前臺時banner提示框的顯示選項
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);
}
// iOS10通知代理方法,通知前后臺點擊時會觸發(fā)痹籍。
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
// 只有本地通知才能獲取到這個key對應(yīng)的value
NSData *modelData = userInfo[CYLocalNotificationModelKey];
if (modelData) {
[[CYLocalNotificationMgr sharedManager] handleLocalNotificationResponse:response];
}
completionHandler();
}
遠程通知和本地通知之所以能統(tǒng)一規(guī)范呢铆,就是因為其原理類似,唯一的區(qū)別在于遠程通知需要獲取用戶的token蹲缠,通過蘋果的APNS將通知發(fā)送給對應(yīng)用戶棺克,而具體通知的內(nèi)容則由后臺配置的那個aps字典決定了。
2线定、普通遠程通知
下面是iOS8-9遠程通知相關(guān)的代理方法
/**
已經(jīng)收到遠程推送消息
@param userInfo 收到的userInfo信息
*/
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if (application.applicationState == UIApplicationStateActive) {
NSLog(@"程序運行中收到通知");
} else {
NSLog(@"程序不活躍中收到通知");
}
}
/**
后臺模式收到的遠程推送信息娜谊,需要開啟后臺模式的遠程推送,實現(xiàn)了此方法斤讥,上面的方法就失效纱皆。
*/
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
if (application.applicationState == UIApplicationStateActive) {
NSLog(@"程序運行中收到通知");
} else {
NSLog(@"程序不活躍中收到通知");
}
completionHandler(UIBackgroundFetchResultNewData);
}
遠程推送需要后臺配置title等參數(shù),也就是在本地通知中設(shè)置的那些什么alertTitle芭商,alertBody啥子的派草。基本格式如下:
{
"aps" : {
"alert" : {
"title" : "主標(biāo)題",
"subtitle" : "子標(biāo)題",
"body" : "通知內(nèi)容"
},
"badge" : 2,
"sound" : "alert.wav"
},
"custom" : "something"
}
其中aps為固定對象铛楣,后臺需要傳輸自己的參數(shù)可以自行添加與aps并列的鍵值對近迁。
- subtitle是iOS10才有的,iOS10之前加不加無所謂簸州。
- sound為提示音钳踊,默認(rèn)為default,自定義時別忘了后綴勿侯。
- custom為自擴展字段,比如iOS10中圖片和視頻的連接地址就可以放這里缴罗。
3助琐、高級遠程通知
所謂高級,無非就是iOS10以下的可操作通知面氓、iOS10中通知的增刪改兵钮,以及UNNotificationServiceExtension和UNNotificationContentExtension這兩個通知擴展了。由于是遠程通知舌界,這里僅附上測試aps格式掘譬,方便測試。
{
"aps" : {
"alert" : {
"title" : "這是title",
"subtitle" : "這是subtitle",
"body" : "這是body"
},
"mutable-content" : "1",
"category" : "myNotificationCategory"
}
}
- 此aps可以用來測試上述所有高級遠程通知呻拌。
- category中的值必須與測試可操作通知時的category值一樣葱轩。
- 測試UNNotificationContentExtension時,必須和plist文件中的UNNotificationExtensionCategory所對應(yīng)的值保持一致,編譯對應(yīng)的Scheme即可靴拱。
- 凡是需要對通知內(nèi)容做修改的都要加上mutable-content字段垃喊,UNNotificationServiceExtension中需要使用。例如下載通知中傳來的圖片或視頻袜炕,先下載后再通知本谜。
- 通知的增刪改都是根據(jù)request中的identifier進行查找和區(qū)分的。
通知其實也就這些偎窘,只是改的多乌助,顯得亂而已。理解了通知的流程與原理陌知,處理這一模塊的問題也就能得心應(yīng)手他托。