在iOS10上,蘋果將原來散落在UIKit中各處的用戶通知相關(guān)的代碼進行重構(gòu),剝離,打造了一個全新的通知框架-UserNotifications。筆者最近在開發(fā)公司通知相關(guān)的需求,跟著WWDC2016的視頻和官方文檔,學(xué)習(xí)了一下新框架。同時,在學(xué)習(xí)過程中,和老框架對應(yīng)Api進行對比,有了個人的感受和看法。
首先,對于通知框架,其框架功能包括以下四類
- 申請權(quán)限/注冊配置
- 發(fā)送本地通知
- 展示和響應(yīng)本地/遠(yuǎn)程通知
- App Extension
在UserNotifications框架中,最核心的類是UNUserNotificationCenter,這個類的是這三項功能的管理類,通過注入到currentNotificationCenter進行對消息的管理。而在之前,大部分操作的管理者UIApplication的單例。
1.申請權(quán)限/注冊配置
在新框架中,將申請權(quán)限和注冊配置拆分為兩個Api,使得職責(zé)更加分明。先看舊框架的實現(xiàn)。
UIUserNotificationType types = ...//通知可顯示的樣式
UIUserNotificationSettings *settting = [UIUserNotificationSettings settingsForTypes:types categories:nil]; //將樣式和Category一起生成配置
[[UIApplication sharedApplication] registerUserNotificationSettings:settting];//用這個配置注冊
Category的概念,是一個通知的種類。對同種類的通知,可以規(guī)定對應(yīng)的一組按鈕操作,同時,iOS10以上的Rich Notification(可以展示圖片,自定義視圖)的區(qū)分讀也是通過category來區(qū)分。
而在老的通知框架中,上面第二行代碼中可以看到,category和展示樣式一同綁定起來用于申請權(quán)限。實際上,Category的概念用于區(qū)分接收消息的種類,也就是其實這個概念屬于接收消息后進行自定義處理的使用者,也就是App內(nèi)部開發(fā)。而對于申請權(quán)限,其實最終是向App外部的交互,也就是App用戶關(guān)心的。而新框架進行拆分后,就更加自由和職責(zé)區(qū)分了。
UserNotifications中請求權(quán)限的用法
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:... completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
//...如果被授權(quán)了
}
}];
同時,增加一個callback將授權(quán)后的狀態(tài)返回,就像分散型網(wǎng)絡(luò)請求一般。
對于遠(yuǎn)程通知,還需要一個獲取用戶token的操作,并使用這個token進行APNs推送。但是奇怪的是,對于申請token這個操作,新框架中卻沒有對應(yīng)的Api,沿用舊的Api。
[[UIApplication sharedApplication] registerForRemoteNotifications];
//AppDelegate
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
....
}
獲取操作被放在AppDelegate的回調(diào)中,如果按照新框架的設(shè)計,應(yīng)該會被設(shè)計成一個帶callBack的Api。所以筆者猜測沿用舊設(shè)計的原因是,在以后,獲取token的操作不一定由發(fā)起請求后產(chǎn)生,也許可能會有多種情況下產(chǎn)生獲取操作,也可能token會過期可以進行更新,重置操作。所以delegate的集中式管理更加擁有拓展性,當(dāng)然也有可能這個Api忘記遷移哈哈。
配置Category并注冊
對于Category的作用,上文已經(jīng)有介紹,而Category中目前主要的功能,是對應(yīng)一組按鈕操作。
Category的使用分四步
- 創(chuàng)建Category,設(shè)置identifer,配置一組按鈕(可無)
- 將Category注冊到UIApplication(舊)/UNNotificationCenter(新)中
- 發(fā)送本地或遠(yuǎn)程消息時需要按鈕或自定義視圖時帶上對應(yīng)的categoryIdentifer
- 收到消息進行響應(yīng)時通過消息中攜帶的categoryIdentifer進行分類,可以指定不同的操作
舊框架中按鈕動作對象UIUserNotificationAction和新的UNNotificationAction差異性不大,主要關(guān)心的是
- 按鈕上顯示的文字
- 按鈕的identifer,用于區(qū)分按鈕
- 是否需要跳轉(zhuǎn)到前臺,喚起主App
而差異性在于
- 舊框架分為可變對象和不可變對象,新框架只有不可變對象加上實例化方法
- 新框架中,對于可輸入操作的按鈕,拆分成一個子類,可以使輸入操作自定義性和拓展性更強
新建一個按鈕也很簡單
UNNotificationAction *callDriverAction = [UNNotificationAction actionWithIdentifier:@"xxx" title:@"呼叫司機" options:UNNotificationActionOptionForeground];
options中可以選擇是否需要解鎖后才能操作、按鈕顏色是否為紅色(代表操作有破壞性)、是否打開App。
然后將整組按鈕加入UNNotificationCategory(新)或UIUserNotificationCategory(舊)中。
這兩個對象差異性在于
- 舊框架分為可變對象和不可變對象,新框架只有不可變對象加上實例化方法
- 舊框架按鈕有兩種使用環(huán)境,所以需要設(shè)置UIUserNotificationActionContext
- 新框架支持配置按鈕的響應(yīng)是否發(fā)送到UNNotificationCenter的Delegate或CarPlay中
- 新框架支持Intent框架(SiriKit使用到)
UIUserNotificationActionContext
- UIUserNotificationActionContextDefault-對應(yīng)iOS10以下的的“提醒”樣式,是一個彈框
- UIUserNotificationActionContextMinimal-對應(yīng)iOS10以下的“橫幅”樣式,最多支持兩個按鈕橫向并排,多于兩個按鈕會取前兩個
為什么這個在新的框架中被去掉了呢?
- iOS10上,提醒樣式不再是一個彈框,而是和“橫幅”統(tǒng)一,只是不會主動往上收起
- iOS10上,橫幅的按鈕不再是橫向并排,而是豎著排放,也不會限制個數(shù)
之后調(diào)用setNotificationCategories方法注冊即可
[[UNUserNotificationCenter currentNotificationCenter]setNotificationCategories:[NSSet setWithObject:self.category]];
在運行app時,原來的set里的categories并不會清空,所以需要將整個Set傳進去作為參數(shù),這樣會把原來的set完整替換成新的set。每次調(diào)用時,整個set替換原來的set。
同時,對于通知設(shè)置和Category設(shè)置,拆分了兩個Api去獲取當(dāng)前的設(shè)置。
- (void)getNotificationCategoriesWithCompletionHandler:(void(^)(NSSet<UNNotificationCategory *> *categories))completionHandler;
- (void)getNotificationSettingsWithCompletionHandler:(void(^)(UNNotificationSettings *settings))completionHandler;
而對于按鈕的操作響應(yīng),將在第三部分響應(yīng)通知中介紹。
2.發(fā)送本地通知
在iOS10以前,本地通知的類用的是UILocalNotification。而在UserNotifications框架中,將本地通知和遠(yuǎn)程通知統(tǒng)一起來,然后將通知拆分成request=content(內(nèi)容)+trigger(觸發(fā)器)的模式,十分像網(wǎng)絡(luò)請求的思路。這樣設(shè)計的好處是對于遠(yuǎn)程通知和本地通知對于響應(yīng)的處理得到統(tǒng)一,同時也不會像以前一樣,將本地特有的功能隨意堆砌在本地通知類中,而是通過差異化配置類去進行注入。
UNNotificationContent
新的通知內(nèi)容類,有可變子類。同時有以下新功能
- 支持一個UNNotificationAttachment(附件)數(shù)組,附件用一個identifer+文件路徑構(gòu)成,可攜帶視頻/圖片等,而這些內(nèi)容也為iOS10的RichNotification自定義視圖提供了素材
- 支持Title+Subtitle,Apns對應(yīng)字段也同步支持
- 通知聲音有了特定類UNNotificationSound進行管理,以后拓展性,自由度更好了
- threadIdentifer(主要用于Extesion Content中,在最后一節(jié)App Extension中會介紹)
UNNotificationTrigger
而之前散落成一個個不同類型的觸發(fā)相關(guān)屬性,也被匯總成了UNNotification的子類。有以下幾個類
- UNPushNotificationTrigger-這個類代表這條消息是由APNs推送過來的,也就是這個trigger是否是這個類是區(qū)分本地通知和遠(yuǎn)程通知的標(biāo)志,對于做多系統(tǒng)b版本兼容時,很有幫助
- UNTimeIntervalNotificationTrigger-根據(jù)相隔時間觸發(fā),就和計時器一樣,注意timeInterval要大于0,且希望repeats的話,需要timeInterval大于60
- UNCalendarNotificationTrigger-根據(jù)日歷時間觸發(fā)
- UNLocationNotificationTrigger-根據(jù)定位在某個位置觸發(fā)
UNNotificationRequest
request除了包含content和trigger外,還有一個非常主要的屬性,那就是identifer。
有了Identifer,可以實現(xiàn)通知的更新和移除。
把通知分成待展示(已投遞,但未觸發(fā)或未展示)和已經(jīng)展示過進入用戶通知中心的兩種。遠(yuǎn)程通知在后臺收到會立即展示。也就是一共有四種情況
- 更新未展示的通知(本地&遠(yuǎn)程前臺)
- 更新已展示的通知(本地&遠(yuǎn)程)
- 取消未展示的通知(本地)
- 取消已展示的通知(本地)
而標(biāo)識同一通知的標(biāo)志,就是通知的identifer。
而發(fā)送/更新通知用的是同一個Api,就是將request添加到UNNotificationCenter里,同時也有一個callback回調(diào)狀態(tài)
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:[UNNotificationRequest requestWithIdentifier:sameIdentifer content:content trigger:trigger] withCompletionHandler:^(NSError * _Nullable error) {
...
}];
而取消或移除未展示和已展示的通知,分開了兩組Api方便根據(jù)情況選擇,同時也有g(shù)et方法獲取當(dāng)前已展示/未展示的隊列里的所有通知,而且和添加/更新不同,移除只需要一個identifer,且可以同時傳入一組identifer,一次性移除多個
- (void)getPendingNotificationRequestsWithCompletionHandler:(void(^)(NSArray<UNNotificationRequest *> *requests))completionHandler;//獲取未展示通知
- (void)removePendingNotificationRequestsWithIdentifiers:(NSArray<NSString *> *)identifiers;//取消未展示通知
- (void)removeAllPendingNotificationRequests;//取消所有未展示通知隊列里的通知
- (void)getDeliveredNotificationsWithCompletionHandler:(void(^)(NSArray<UNNotification *> *notifications))completionHandler;//獲取已展示通知
- (void)removeDeliveredNotificationsWithIdentifiers:(NSArray<NSString *> *)identifiers;//從通知中心中移除已展示通知
- (void)removeAllDeliveredNotifications;//移除所有通知中心里的通知
3.展示和響應(yīng)
在舊框架里面,這部分Api是最為混亂的部分。一共有1..2.....7個delegate......而且之中有的還有取代關(guān)系,也就是有其中一個另一個不執(zhí)行......
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;//前臺收到遠(yuǎn)程通知
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;//前臺收到本地通知
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void(^)())completionHandler;//iOS9之前本地通知點擊按鈕后
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler;//iOS9遠(yuǎn)程通知點擊按鈕后
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler;//iOS9之前遠(yuǎn)程通知點擊按鈕后
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler;//iOS9本地通知點擊按鈕
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;//iOS7以上收到遠(yuǎn)程通知調(diào)用(未被廢棄)
這么亂,讓我重新分類。
- 收到通知
- 點擊通知本身
- 點擊通知的自定義按鈕
收到通知
在觸發(fā)本地通知時,App并不會被喚醒,所以本地只有前臺時才有回調(diào)。
- 本地+前臺-
didReceiveLocalNotification
- 遠(yuǎn)程+前臺-
didReceiveRemoteNotification
和didReceiveRemoteNotification:fetchCompletionHandler
若有后面則只執(zhí)行后面那個 - 遠(yuǎn)程+后臺-喚醒并執(zhí)行
didReceiveRemoteNotification:fetchCompletionHandler
點擊通知本身
本地+App存活-
didReceiveLocalNotification
本地+App未存活-
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
,其中l(wèi)anchOptions中UIApplicationLaunchOptionsLocalNotificationKey為UILocalNotification對象遠(yuǎn)程+App存活-
didReceiveRemoteNotification
和didReceiveRemoteNotification:fetchCompletionHandler
若有后面則只執(zhí)行后面那個-
遠(yuǎn)程+App未存活-
didReceiveRemoteNotification:fetchCompletionHandler
有則執(zhí)行,無則-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
,其中l(wèi)anchOptions中UIApplicationLaunchOptionsRemoteNotificationKey為通知的userInfo
點擊自定義按鈕
- iOS9
handleActionWithIdentifier
,有responseInfo后綴的優(yōu)先調(diào),無則調(diào)用無后綴的 - iOS8調(diào)用無后綴的
整理完感覺就是,亂,還涉及到lauchOptions等無關(guān)api,api之間還會覆蓋,還有一些不是收到和響應(yīng)都會調(diào)。
而新框架單純拆分為收到消息+點擊事件響應(yīng),且不再在Api層面區(qū)分遠(yuǎn)程與本地通知,使對待通知的路徑變得統(tǒng)一。
通知的收到
在前臺的時候,收到不管是本地還是遠(yuǎn)程通知都會被新的delegate接管。以前的通知框架,在前臺收到通知時,默認(rèn)是不展示(沒有橫幅等)的。而新delegate可以在前臺收到通知后,展示前,做一些處理,包括以什么形式展示,已經(jīng)做一些自定義操作。而這個Delegate只有App在前臺才會執(zhí)行。因為在后臺App收到通知時,通知不會喚醒App(不是喚起),而App可能是被殺死的,所以這個Delegate沒有被賦值,所以統(tǒng)一只在App在前臺時才執(zhí)行。而將新的Api對應(yīng)舊的Api轉(zhuǎn)換起來的話,就是下面的代碼。
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
BOOL isRemote = NO;
if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
isRemote = YES;
}
UILocalNotification *localNotification;//從新的轉(zhuǎn)換為舊的本地通知
if (!isRemote && [[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveLocalNotification:)]) {
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveLocalNotification:localNotification];
}
else if (isRemote) {
if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]) {
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveRemoteNotification:notification.request.content.userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
}
else if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:)]){
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveRemoteNotification:notification.request.content.userInfo];
}
}
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionAlert);//決定前臺展示形式
}
而CompletionHandler里傳入希望通知支持的類型(橫幅、紅點、聲音),在自定義操作完成后執(zhí)行這個block就可。當(dāng)然可以在這里為不同消息定制不同的支持類型。
點擊通知或按鈕的操作響應(yīng)
新框架中,點擊操作和收到通知的Api的響應(yīng)終于被區(qū)分開了。而且點擊操作也包含點擊通知本身,以及有了點清除關(guān)閉通知的事件響應(yīng)。拆分點擊和收到的Api是很好的,因為點擊通知和按鈕時,實際上會將app喚起到前臺,一般這時候需要進行頁面跳轉(zhuǎn),界面狀態(tài)恢復(fù)等等,這些在收到通知時是沒有必要的。
新的Api和就的轉(zhuǎn)換的話就是下面這樣
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler{
BOOL isRemote = NO;
if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
isRemote = YES;
}
UILocalNotification *localNotification;//從新的轉(zhuǎn)換為舊的本地通知
if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier] || [response.actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) {
if (!isRemote && [[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveLocalNotification:)]) {
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveLocalNotification:localNotification];
}
else if (isRemote) {
if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:fetchCompletionHandler:)]) {
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveRemoteNotification:response.notification.request.content.userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
}
else if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:didReceiveRemoteNotification:)]){
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] didReceiveRemoteNotification:response.notification.request.content.userInfo];
}
}
}
else{
if (!isRemote) {
if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:)]) {
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] handleActionWithIdentifier:response.actionIdentifier forLocalNotification:localNotification withResponseInfo:@{} completionHandler:^{}];
}
else if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:handleActionWithIdentifier:forLocalNotification:completionHandler:)]){
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] handleActionWithIdentifier:response.actionIdentifier forLocalNotification:localNotification completionHandler:^{}];
}
}
else{
if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:handleActionWithIdentifier:forRemoteNotification:withResponseInfo:completionHandler:)]) {
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] handleActionWithIdentifier:response.actionIdentifier forRemoteNotification:response.notification.request.content.userInfo withResponseInfo:@{} completionHandler:^{}];
}
else if ([[UIApplication sharedApplication].delegate respondsToSelector:@selector(application:handleActionWithIdentifier:forRemoteNotification:completionHandler:)]){
[[UIApplication sharedApplication].delegate application:[UIApplication sharedApplication] handleActionWithIdentifier:response.actionIdentifier forRemoteNotification:response.notification.request.content.userInfo completionHandler:^{}];
}
}
}
}
completionHandler();
}
當(dāng)實現(xiàn)了新框架這兩個Delegate后,舊框架的6個Delegate將不會被執(zhí)行,所以除非App只支持iOS10,盡量按上面的代碼進行兼容。
**注意-(void)application:(UIApplication )application didReceiveRemoteNotification:(NSDictionary )userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;這個方法并未隨著舊框架被廢棄,還是正常使用。
4.App Extension
關(guān)于新通知框架的Extension,有以下兩個
NotificationService Extension
這個Extension允許我們在遠(yuǎn)程通知收到前做一些修改。因為之前App內(nèi)UNNotificaionCenter的Delegte并不能在App不存活情況下執(zhí)行,所以有了這個Extension來提供這樣的功能。新建NotificationService的target后,發(fā)現(xiàn)系統(tǒng)會自動生成了UNNotificationServiceExtension的子類。其中重寫方法的模板,系統(tǒng)也生成好了。
@interface NotificationService ()
@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
self.contentHandler(self.bestAttemptContent);
}
- (void)serviceExtensionTimeWillExpire {
self.contentHandler(self.bestAttemptContent);
}
@end
第一個方法在收到遠(yuǎn)程通知時,可以攔截通知并修改通知內(nèi)容。先用一個block保存當(dāng)時的上下文,再修改完后再調(diào)用block再修改完新的通知內(nèi)容回調(diào)回去。
第二個方法是在修改通知時機將要結(jié)束時調(diào)用,這時候會強制執(zhí)行block了。
在推送 payload 中增加一個 mutable-content
值為 1 來啟用這個Extension,暫時還不支持本地通知。
NotificationContent Extension
這個就是實現(xiàn)Rich Notification的拓展。新建這個Target后,可以發(fā)現(xiàn)自動生成了一個ViewController并遵循了UserNotificationsUI框架的UNNotificationContentExtension協(xié)議。又是一個新框架,看來之后在通知視圖上的功能將會變得更強大。
- (void)didReceiveNotification:(UNNotification *)notification {
//收到通知后的操作
}
- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption option))completion{
//收到通知響應(yīng),如按鈕,可以這個方法里攔截,并自定義操作,再決定是否將按鈕放行至主app
}
這個協(xié)議里面只有上面兩個方法。第一個方法用于在展開Rich視圖時觸發(fā),進行根據(jù)數(shù)據(jù)去改變視圖。就如平時收到網(wǎng)絡(luò)請求后根據(jù)網(wǎng)絡(luò)請求返回的響應(yīng)改變視圖元素。當(dāng)打開RIch視圖后,這個方法還有兩個時機會觸發(fā)。
- Request的Identifer一致,相當(dāng)于更新整個通知,同時視圖也重新加載
- 還記得之前說的Content的threadIdentifer么,這個相同時,這個方法也會重新調(diào)用,也就是這個是用來標(biāo)識同一個流程的的通知,當(dāng)然,通知還是兩條,只是視圖從通知A狀態(tài)到通知B狀態(tài)了
而第二個方法,實在通知響應(yīng)時,比如按鈕響應(yīng)時,先在這個Extension里攔截,可以進行響應(yīng)修改,視圖改變等操作,然后通過CompletionHandler的UNNotificationContentExtensionResponseOption來選擇放行這些響應(yīng)。其中UNNotificationContentExtensionResponseOptionDismissAndForwardAction才可以將響應(yīng)放行到主app里UNNotificationCenter的delegate方法中。
同時這個Extension也有自己的Storyboard和Info.plist。
DefaultContenHidden代表是否在Rich狀態(tài)下還顯示原來的body文字
Category代表此類categoryIdentifer會觸發(fā)這個ViewController,可以是一個Array,多個同時支持這個ViewController。
SizeRatio代表高/寬比,其中寬固定為屏幕寬度,也就是用這個來調(diào)整視圖的高度。
iOS11New
都是一些小改動,增加一些細(xì)分化Api等,可以在蘋果官方文檔找到。
https://developer.apple.com/documentation/usernotifications?changes=latest_major&language=objc
總結(jié)
iOS10新通知框架和舊框架差異性
UILocalNotification | UNNotificationRequest | Apns消息體 |
---|---|---|
無 | identifer | HTTP/2的header中的 apns-collapse-id |
無 | content.attachments(UNNotificationAttachmen) | 可在UNNotificationService中修改 |
applicationIconBadgeNumber(Integer) | content.badge | badge |
alertBody | content.body | alert的body |
category | content.categoryIdentifer | category |
alertLaunchImage | lanuchImageName(打開時啟動圖) | alert的lanch-image |
soundName(新無法轉(zhuǎn)換為舊) | UNNotificationSound-soundNamed: | sound |
無 | subtitle | alert的subtitle |
無 | threadIdentifer(特殊標(biāo)識符,自定義用) | thread-id |
alertTitle(iOS8.2以上) | title | alert的title |
userInfo | userInfo | 所有 |
fireDate | UNNotificatonTimeInterval-trigger.timeInterval | 無 |
repeatInterval>0 或 repeatCalendar不為空或regionTriggersOnce為YES | trigger.repeat | 無 |
alertAction(alert模式下action名字) | 無 | 無 |
region(觸發(fā)位置) | UNLocationNotificationTrigger-trigger.region | 無 |
timeZone | 無 | 無 |
repeatInterval(重復(fù)時間點) | UNNotificationTimeInterval/Calendar-nextTriggerDate轉(zhuǎn)換 | 無 |
reatCalendar(重復(fù)的日歷) | trigger的Class為UNNotificationPushTrigger | 無 |
regionTriggersOnce | UNLocationNotificationTrigger-trigger.repeats | 無 |
hasAction(alert下是否有動作) | 無 | 無 |
UNNotificationAction | UIUserNotificationAction |
---|---|
identifer | Identifer |
title | title |
UNNotificationActionOptions-options | activationMode+authenticationRequired+destructive共同決定 |
UNTextInputNotificationAction/UNNotification(按鈕種類) | UIUserNotificationActionBehavior-behavior(iOS9以上) |
無 | parameters |
UNTextInputNotificationAction-textInputButtonTitle | 無 |
UNTextInputNotificationAction-textInputPlaceholder | 無 |
UNNotificationCategory | UIUserNotificationCategory |
---|---|
identifer | Identifer |
actions(UNNotificationAction) | actionsForContext(UIUserNotificationAction) |
intentIdentifers(支持Siri或蘋果叫車框架的標(biāo)識符) | 無 |
options(點擊后是否消失等等) | 無 |
iOS10的通知框架,和之前比簡直煥然一新,整潔,優(yōu)雅。還有一點需要注意的是,因為原來屬于UIKit中,那么最好在主線程中操作。但由于老框架暫時還不會被廢棄,所以在接入時,要注意新老框架的兼容和覆蓋,避免出現(xiàn)不必要的Bug。
PS:此文又名《iOS10通知框架最全總結(jié)》
PPS:此文又名《iOS10通知框架,你看我就夠了》
PPPS:此文又名《iOS10通知框架,你真的懂么?》
所有源碼和Demo
如果您覺得有幫助,不妨給個star鼓勵一下,歡迎關(guān)注&交流
有任何問題歡迎評論私信或者提issue
QQ:757765420
Email:nemocdz@gmail.com
Github:Nemocdz
微博:@Nemocdz