iOS10里的通知與推送

通知和推送是一種東西么?

iOS 10通知

推送

圖1為通知伤靠,圖2為推送

也許有些同學(xué)現(xiàn)在才恍然大悟,今天我們就聊聊這個(gè)通知和推送吧啼染。

什么叫通知宴合,什么叫推送?

通知是iOS操作系統(tǒng)層面上的功能迹鹅,說白了就是iPhone上的通知條卦洽,通知中心等,App來了一條通知斜棚,系統(tǒng)來了升級(jí)通知阀蒂,待辦事項(xiàng)來了一條通知该窗,這里的通知指的是iOS操作系統(tǒng)內(nèi)的一個(gè)功能,更多體現(xiàn)在UI蚤霞、交互酗失、觸發(fā)邏輯、通知方式上昧绣。

推送指的是由APNs服務(wù)器规肴、ProviderService、iOS系統(tǒng)夜畴、App構(gòu)成的通訊系統(tǒng)拖刃,是移動(dòng)互聯(lián)網(wǎng)與傳統(tǒng)的Web最明顯的區(qū)別的地方。正因?yàn)橛辛送扑吞盎妫瑢?shí)現(xiàn)了服務(wù)端能夠反向與用戶建立聯(lián)系兑牡,而不是等待用戶訪問Web服務(wù)器。這里我們著重講一下APNs與ProviderService兔簇。

APNs(Apple Push Notification service-蘋果推送通知服務(wù))

APNs官方文檔

APNs是推送的核心发绢。該服務(wù)與iOS設(shè)備建立起強(qiáng)大的持久連接通訊(和間接WatchOS,TVOS垄琐,和MacOS設(shè)備)边酒。在早期的時(shí)候,iOS通過管理AppSSL認(rèn)證的推送證書與APNs建立起長(zhǎng)連接通訊狸窘,但不是可靠的通訊墩朦。隨后,APNs使用持久連接進(jìn)行服務(wù)端推送翻擒。在長(zhǎng)期的演進(jìn)過程中氓涣,現(xiàn)在iOS10提供的APNs服務(wù)是基于HTTP/2協(xié)議棧同時(shí)使用Json Web Token(json令牌)保證通訊安全。有如下幾項(xiàng)改進(jìn):

iOS 8以后陋气,APNs推送的字節(jié)是2k劳吠,iOS8以前是256字節(jié)痒玩,iOS10現(xiàn)在是4k

iOS 9以后APNs支持HTTP/2協(xié)議棧议慰,優(yōu)化長(zhǎng)連接,具有標(biāo)準(zhǔn)的HTTP返回和管道復(fù)用技術(shù)

iOS 10以后草讶,APNs可根據(jù)推送消息的唯一標(biāo)示符查詢某條消息是否被用戶閱讀,可更新某一推送消息炉菲,而不用發(fā)重讀的多條消息

更多的詳細(xì)解釋有一篇文章叫做?《國(guó)內(nèi) 90%以上的 iOS 開發(fā)者,對(duì) APNs 的認(rèn)識(shí)都是錯(cuò)的》浇雹,大家可以深入了解昭灵。

通知

iOS操作系統(tǒng)的通知包括了App的通知烂完、系統(tǒng)的通知和官方應(yīng)用的通知,實(shí)質(zhì)上就是推送的數(shù)據(jù)在iOS操作系統(tǒng)上的表現(xiàn)和本地通知在iOS操作系統(tǒng)的表現(xiàn)嘶窄,在交互上iOS10的通知大大增強(qiáng)柄冲,可定制化UI现横,增加了更加細(xì)分的通知權(quán)限管理和更多的通知設(shè)定戒祠,例如遠(yuǎn)程通知、時(shí)間通知配阵、地理位置通知和日歷通知。

很多開發(fā)者都知道iOS10中蘋果升級(jí)推出了User Notifications FrameworkUser Notifications UI Framework兩個(gè)框架饱亮,但是千萬不要跟推送混為一談剔宪,這兩個(gè)框架升級(jí)和打包的是通知的功能增加和通知交互層面上的改進(jìn)。

推送Push只不過是iOS10通知的一種觸發(fā)器斗锭。

配合最新的推送服務(wù)使用強(qiáng)大的iOS10通知功能

重點(diǎn)介紹一下iOS10的通知新功能,用戶體驗(yàn)的提升和開發(fā)者能夠發(fā)揮的地方非常多豺撑,使得iOS更具有競(jìng)爭(zhēng)力聪轿。

iOS 10通知系統(tǒng)支持Images, GIFs, Audio and Video類型

iOS 10推出Notification Service Extension與Notification Content Extension,可以實(shí)現(xiàn)推送數(shù)據(jù)在展示前進(jìn)行下載更新音瓷、定制通知UI

iOS 10統(tǒng)一了通知類型外莲,具有時(shí)間間隔通知、地理位置通知和日歷通知

iOS里的通知擴(kuò)展

User Notifications Framework 介紹:

關(guān)系圖:

User Notifications Framework類關(guān)系圖

重點(diǎn)介紹:

UNUserNotificationCenter通知中心,用以管理通知的注冊(cè)亥曹、權(quán)限獲取和管理媳瞪、通知的刪除與更新,通過代理分發(fā)事件等兢仰。

UNNotification 通知實(shí)體把将,在UNUserNotificationCenter的代理回調(diào)事件中请垛,告知App接收到一條通知叼屠,包含一個(gè)發(fā)起通知的請(qǐng)求UNNotificationRequest

UNNotificationRequest包含通知內(nèi)容UNNotificationContent和觸發(fā)器UNNotificationTrigger

UNNotificationContent 通知內(nèi)容,通知的title荚坞,sound,badge以及相關(guān)的圖像诡挂、聲音璃俗、視頻附件UNNotificationAttachment,觸發(fā)打開App時(shí)候指定的LacnchImage等

UNNotificationResponse唱星,用戶在觸發(fā)了按鈕或者文本提交的UNNotificationAction的時(shí)候,會(huì)形成一個(gè)response哎榴,通過通知中心的代理方法回調(diào)給App進(jìn)行處理或者是交給擴(kuò)展處理叹话。

UNNotificationServiceExtension,是一個(gè)在接收到APNs服務(wù)器推送過來的數(shù)據(jù)進(jìn)行處理的服務(wù)擴(kuò)展热凹,如果App提供了服務(wù)擴(kuò)展,那么APNs下發(fā)推送后在通知顯示觸發(fā)之前碟渺,會(huì)在UNNotificationServiceExtension內(nèi)接收到苫拍,此處有大約30秒的處理時(shí)間,開發(fā)者可以進(jìn)行一些數(shù)據(jù)下載垄提、數(shù)據(jù)解密、更新等操作高蜂,然后交由而后的內(nèi)容擴(kuò)展(UNNotificationContentExtension)或者是App進(jìn)行觸發(fā)顯示

UNNotificationCategory,用以定義一組樣式類型,該分類包含了某一個(gè)通知包含的交互動(dòng)作的組合露泊,比如說UNNotificationRequest內(nèi)包含了一個(gè)Category標(biāo)示,那該通知就會(huì)以預(yù)定義好的交互按鈕或者文本框添加到通知實(shí)體上沉噩。

UNNotificationAttachment川蒙,通知內(nèi)容UNNotificationContent包含的附件昼牛,一般為圖片、視頻和音頻伶椿,雖然iOS10的通知數(shù)據(jù)容量為4k,但依舊很少尝蠕,在添加了UNNotificationServiceExtension擴(kuò)展的情況下,可以在服務(wù)里下載圖片靖榕,生成圖片、視頻等的本地緩存星压,UNNotificationAttachment根據(jù)緩存數(shù)據(jù)生成并添加到UNNotificationContent中,交由UI顯示

UNNotificationAction竣贪,是通知中添加的action匕争,展示在通知欄的下方甘桑。默認(rèn)以的button樣式展示春缕。有一個(gè)文本輸入的子類UNTextInputNotificationAction票灰⌒加兀可以在點(diǎn)擊button之后彈出一個(gè)鍵盤,輸入信息手报。用戶點(diǎn)擊信息和輸入的信息可以在UNNotificationResponse中獲取

User Notifications UI Framework介紹:

關(guān)系圖:

User Notifications UI Framework類關(guān)系圖

10.?UNNotificationContentExtension<協(xié)議>陈肛,NotificationViewController實(shí)現(xiàn)該協(xié)議句旱,可以獲得iOS展示自定義UI時(shí)候分發(fā)的UNNotification對(duì)象和用戶交互的Response

11.NotificationViewController稚配,App添加Notification Content Extension擴(kuò)展的時(shí)候,自動(dòng)生成的Controller冒萄,可以定義通知UI的主題部分帅戒,由StoryBoard指定設(shè)計(jì)

iOS10注冊(cè)通知、回調(diào)處理

只簡(jiǎn)單介紹一下iOS10的通知注冊(cè)


UNUserNotificationCenter?*center?=?[UNUserNotificationCenter?currentNotificationCenter];

????//?必須寫代理瞎访,不然無法監(jiān)聽通知的接收與點(diǎn)擊

????center.delegate?=?self;

//設(shè)置預(yù)設(shè)好的交互類型,NSSet里面是設(shè)置好的UNNotificationCategory

????[center?setNotificationCategories:[self?createNotificationCategoryActions]];

????[center?getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings?*?_Nonnull?settings)?{

????????if(settings.authorizationStatus==UNAuthorizationStatusNotDetermined)?{

????????????[center?requestAuthorizationWithOptions:(UNAuthorizationOptionAlert?|?UNAuthorizationOptionBadge?|?UNAuthorizationOptionSound)?completionHandler:^(BOOL?granted,?NSError?*?_Nullable?error)?{

????????????????if(granted)?{

????????????????}?else{


????????????????}

????????????}];

????????}

????????else{

????????????//do?other?things

????????}

????}];



?-?(void)application:(UIApplication?*)application

didRegisterForRemoteNotificationsWithDeviceToken:(NSData?*)deviceToken?{

????//上傳token

}

-?(void)application:(UIApplication?*)application

didFailToRegisterForRemoteNotificationsWithError:(NSError?*)error?{

????//獲取token失敗,開發(fā)調(diào)試的時(shí)候需要關(guān)注,必要的情況下將其上傳到異常統(tǒng)計(jì)

}

//代理回調(diào)方法尼啡,通知即將展示的時(shí)候

-?(void)userNotificationCenter:(UNUserNotificationCenter?*)center?willPresentNotification:(UNNotification?*)notification?withCompletionHandler:(void?(^)(UNNotificationPresentationOptions?options))completionHandler{


????UNNotificationRequest?*request?=?notification.request;?//?原始請(qǐng)求

NSDictionary?*?userInfo?=?notification.request.content.userInfo;//userInfo數(shù)據(jù)

????UNNotificationContent?*content?=?request.content;?//?原始內(nèi)容

????NSString?*title?=?content.title;??//?標(biāo)題

????NSString?*subtitle?=?content.subtitle;??//?副標(biāo)題

????NSNumber?*badge?=?content.badge;??//?角標(biāo)

????NSString?*body?=?content.body;????//?推送消息體

????UNNotificationSound?*sound?=?content.sound;??//?指定的聲音

//建議將根據(jù)Notification進(jìn)行處理的邏輯統(tǒng)一封裝,后期可在Extension中復(fù)用~

????completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);?//?回調(diào)block,將設(shè)置傳入

}


//用戶與通知進(jìn)行交互后的response寺惫,比如說用戶直接點(diǎn)開通知打開App、用戶點(diǎn)擊通知的按鈕或者進(jìn)行輸入文本框的文本

-?(void)userNotificationCenter:(UNUserNotificationCenter?*)center?didReceiveNotificationResponse:(UNNotificationResponse?*)response?withCompletionHandler:(void(^)())completionHandler{


????UNNotificationRequest?*request?=?response.notification.request;?//?原始請(qǐng)求

NSDictionary?*?userInfo?=?notification.request.content.userInfo;//userInfo數(shù)據(jù)

????UNNotificationContent?*content?=?request.content;?//?原始內(nèi)容

????NSString?*title?=?content.title;??//?標(biāo)題

????NSString?*subtitle?=?content.subtitle;??//?副標(biāo)題

????NSNumber?*badge?=?content.badge;??//?角標(biāo)

????NSString?*body?=?content.body;????//?推送消息體

????UNNotificationSound?*sound?=?content.sound;?

//在此腔呜,可判斷response的種類和request的觸發(fā)器是什么,可根據(jù)遠(yuǎn)程通知和本地通知分別處理谤草,再根據(jù)action進(jìn)行后續(xù)回調(diào)


}

以上就是iOS10的通知中心注冊(cè)和設(shè)置管理的過程,一下還有一些比較有用API:

//獲取在Pending狀態(tài)下待觸發(fā)的通知

-?(void)getPendingNotificationRequestsWithCompletionHandler:(void(^)(NSArray?*requests))completionHandler;

//移除未觸發(fā)的通知

-?(void)removePendingNotificationRequestsWithIdentifiers:(NSArray?*)identifiers;

-?(void)removeAllPendingNotificationRequests;

//?通知已經(jīng)觸發(fā),但是還在操作系統(tǒng)的通知中心上枫浙,可以進(jìn)行查詢和刪除

-?(void)getDeliveredNotificationsWithCompletionHandler:(void(^)(NSArray?*notifications))completionHandler?__TVOS_PROHIBITED;

-?(void)removeDeliveredNotificationsWithIdentifiers:(NSArray?*)identifiers?__TVOS_PROHIBITED;

-?(void)removeAllDeliveredNotifications?__TVOS_PROHIBITED;

iOS10本地通知

UNMutableNotificationContent?*content?=?[[UNMutableNotificationContent?alloc]?init];

????content.title?=?@"\"Fly?to?the?moon\"";

????content.subtitle?=?@"by?Neo";

????content.body?=?@"the?wonderful?song?with?you~";

????content.badge?=?@0;

????NSString?*path?=?[[NSBundle?mainBundle]?pathForResource:@"image1"ofType:@"png"];

????NSError?*error?=?nil;

//將本地圖片的路徑形成一個(gè)圖片附件黄痪,加入到content中

????UNNotificationAttachment?*img_attachment?=?[UNNotificationAttachment?attachmentWithIdentifier:@"att1"URL:[NSURL?fileURLWithPath:path]?options:nil?error:&error];

????if(error)?{

????????NSLog(@"%@",?error);

????}

????content.attachments?=?@[img_attachment];

????//設(shè)置為@""以后,進(jìn)入app將沒有啟動(dòng)頁

????content.launchImageName?=?@"";

????UNNotificationSound?*sound?=?[UNNotificationSound?defaultSound];

????content.sound?=?sound;

????//設(shè)置時(shí)間間隔的觸發(fā)器

????UNTimeIntervalNotificationTrigger?*time_trigger?=?[UNTimeIntervalNotificationTrigger?triggerWithTimeInterval:10?repeats:NO];

????NSString?*requestIdentifer?=?@"time?interval?request";

????content.categoryIdentifier?=?@"";

????UNNotificationRequest?*request?=?[UNNotificationRequest?requestWithIdentifier:requestIdentifer?content:content?trigger:time_trigger];

????[[UNUserNotificationCenter?currentNotificationCenter]?addNotificationRequest:request?withCompletionHandler:^(NSError?*?_Nullable?error)?{

????????NSLog(@"%@",error);

????}];

這里面的圖片附件后面再述,過程上能感受到遭铺,通知數(shù)據(jù)部分在UNMutableNotificationContent中設(shè)置,附件UNNotificationAttachment也是在其中包含,categoryIdentifier為指定該通知對(duì)應(yīng)的交互樣式果正,也就是前面設(shè)置的UNNotificationCategory的對(duì)象辅肾,后面再述。然后創(chuàng)建觸發(fā)器新娜,UNTimeIntervalNotificationTrigger,觸發(fā)器有很多種,UNNotificationTrigger有四個(gè)子類:

UNPushNotificationTrigger衰粹,遠(yuǎn)程推送觸發(fā)器,一般是遠(yuǎn)程推送推過來的通知帶有這類觸發(fā)器

UNTimeIntervalNotificationTrigger,時(shí)間間隔觸發(fā)器泡态,定時(shí)或者是重復(fù),在本地推送設(shè)置中有用

UNCalendarNotificationTrigger,日歷觸發(fā)器亮钦,指定日期進(jìn)行通知

UNLocationNotificationTrigger蜡娶,地理位置觸發(fā)器,指定觸發(fā)通知的條件是地理位置CLRegion這個(gè)類型。

觸發(fā)器和內(nèi)容最后形成UNNotificationRequest睦霎,一個(gè)通知請(qǐng)求,本地通知的請(qǐng)求蚣旱,直接交給通知中心進(jìn)行發(fā)送碑幅,發(fā)送成功后,該通知會(huì)按照觸發(fā)器的觸發(fā)條件進(jìn)行觸發(fā)塞绿,并且會(huì)顯示到通知中心上沟涨,用戶可與指定的category交互方式與通知進(jìn)行交互

如下圖:

localTimeNotification.gif

iOS10遠(yuǎn)程通知

遠(yuǎn)程通知與本地通知的流程一樣位隶,只不過觸發(fā)器是UNPushNotificationTrigger拷窜,并且不需要形成request开皿,又Provider Service發(fā)送給APNs到iOS以后生成涧黄,在代理回調(diào)的函數(shù)中獲取request

通知的代理回調(diào)

上面代碼有些代理回調(diào)函數(shù),可以在這兩個(gè)代理回調(diào)函數(shù)里做一些事情


-?(void)userNotificationCenter:(UNUserNotificationCenter?*)center?willPresentNotification:(UNNotification?*)notification?withCompletionHandler:(void?(^)(UNNotificationPresentationOptions?options))completionHandler{

????????//該回調(diào)函數(shù)是在通知條即將顯示之前調(diào)用的

????if([request.trigger?isKindOfClass:[UNPushNotificationTrigger?class]])?{

????????//遠(yuǎn)程通知處理

????}

????if([request.trigger?isKindOfClass:[UNTimeIntervalNotificationTrigger?class]])?{

????????//時(shí)間間隔通知處理

????}

????if()?{

????????//加解密赋荆,數(shù)據(jù)下載,完成后調(diào)用completionHandler

????}

????else{

????????completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);

????}

}

如果你的App在前臺(tái)笋妥,一般在這個(gè)回調(diào)函數(shù)里做一些數(shù)據(jù)加解密、數(shù)據(jù)下載窄潭,然后將下載的數(shù)據(jù)組裝成UNNotificationAttachment或者是根據(jù)通知里面的content里面的userinfo里與后端服務(wù)約定好的修改通知對(duì)應(yīng)的categoryId春宣,調(diào)用相應(yīng)的交互組件到通知上,completionHandler在你想要做的邏輯完成以后調(diào)用嫉你。

如果App在前臺(tái)月帝,你接收到通知,不想顯示系統(tǒng)提示框幽污,想使用App 自定義的通知消息彈窗嚷辅,可以在completionHandler回調(diào)的時(shí)候傳入的opinion不要帶上UNAuthorizationOptionAlert,然后直接彈自定義的彈窗就Ok距误。

注意:改回調(diào)函數(shù)僅僅用來處理數(shù)據(jù)和重新選擇交互方式簸搞,其他遠(yuǎn)程推送到達(dá)設(shè)備要做的業(yè)務(wù)邏輯扁位,最好不要在此回調(diào)函數(shù)觸發(fā),保持職責(zé)單一


//用戶與通知進(jìn)行交互后的response趁俊,比如說用戶直接點(diǎn)開通知打開App域仇、用戶點(diǎn)擊通知的按鈕或者進(jìn)行輸入文本框的文本

-?(void)userNotificationCenter:(UNUserNotificationCenter?*)center?didReceiveNotificationResponse:(UNNotificationResponse?*)response?withCompletionHandler:(void(^)())completionHandler{

????//在此,可判斷response的種類和request的觸發(fā)器是什么寺擂,可根據(jù)遠(yuǎn)程通知和本地通知分別處理暇务,再根據(jù)action進(jìn)行后續(xù)回調(diào)

????if([response.actionIdentifier?isEqualToString:@""])?{


????}

????//也可根據(jù)response?判斷是否是text文本輸入

????if([response?isKindOfClass:[UNTextInputNotificationResponse?class]])?{

????????//該函數(shù)是在用戶點(diǎn)擊通知或者是與通知上面指定好的action進(jìn)行了交互回調(diào)的函數(shù),用戶觸發(fā)通知的業(yè)務(wù)邏輯最好放在此處

????}

}

iOS10通知交互怔软,UNNotificationAction與UNNotificationCategory

組合按鈕

組合文本框

首先說明的是般卑,iOS10通知上的交互只有兩種,一種是Button一種是text爽雄,就算使用了iOS10 Notification Content Extension也不能添加自定義的按鈕或者其他交互組件蝠检,因?yàn)椴粫?huì)響應(yīng)。


-(NSSet?*)createNotificationCategoryActions{

????//定義按鈕的交互button?action

????UNNotificationAction?*?likeButton?=?[UNNotificationAction?actionWithIdentifier:@"see1"title:@"I?love?it~"options:UNNotificationActionOptionAuthenticationRequired|UNNotificationActionOptionDestructive|UNNotificationActionOptionForeground];

????UNNotificationAction?*?dislikeButton?=?[UNNotificationAction?actionWithIdentifier:@"see2"title:@"I?don't?care~"options:UNNotificationActionOptionAuthenticationRequired|UNNotificationActionOptionDestructive|UNNotificationActionOptionForeground];

????//定義文本框的action

????UNTextInputNotificationAction?*?text?=?[UNTextInputNotificationAction?actionWithIdentifier:@"text"title:@"How?about?it~?"options:UNNotificationActionOptionAuthenticationRequired|UNNotificationActionOptionDestructive|UNNotificationActionOptionForeground];

????//將這些action帶入category

????UNNotificationCategory?*?choseCategory?=?[UNNotificationCategory?categoryWithIdentifier:@"seeCategory"actions:@[likeButton,dislikeButton]?intentIdentifiers:@[@"see1",@"see2"]?options:UNNotificationCategoryOptionNone];

????UNNotificationCategory?*?comment?=?[UNNotificationCategory?categoryWithIdentifier:@"seeCategory1"actions:@[text]?intentIdentifiers:@[@"text"]?options:UNNotificationCategoryOptionNone];

????return[NSSet?setWithObjects:choseCategory,comment,nil];

}

在上面封裝了上面兩張圖中所示的兩個(gè)category組合挚瘟,每一個(gè)category攜帶的action如圖所示叹谁,在通知中心初始化的時(shí)候設(shè)置app要支持的category。

1

2

UNUserNotificationCenter?*center?=?[UNUserNotificationCenter?currentNotificationCenter];

????[center?setNotificationCategories:[self?createNotificationCategoryActions]];

UNNotificationAction 在初始化的時(shí)候需要定義UNNotificationActionOptions乘盖,這個(gè)UNNotificationActionOptions的意思是:


typedef?NS_OPTIONS(NSUInteger,?UNNotificationActionOptions)?{


????//?Whether?this?action?should?require?unlocking?before?being?performed.

????//指定該動(dòng)作是否需要用戶解鎖驗(yàn)證身份

????UNNotificationActionOptionAuthenticationRequired?=?(1?<<?0),


????//?Whether?this?action?should?be?indicated?as?destructive.

????//指定用戶執(zhí)行該動(dòng)作是否要將通知從iOS的通知中心移除焰檩,以防止處理過該通知以后重復(fù)處理

????UNNotificationActionOptionDestructive?=?(1?<<?1),


????//?Whether?this?action?should?cause?the?application?to?launch?in?the?foreground.

????//指定通知action點(diǎn)擊后是否要進(jìn)入app到前臺(tái),如果到前臺(tái)订框,這個(gè)對(duì)Notification?Content?Extension的自定義的通知UI有意義析苫,

????//可以在Extension中處理用戶的點(diǎn)擊或者提交文字,那么就可以指定該action不需要進(jìn)入app穿扳,

????//UNNotificationActionOptionAuthenticationRequired這個(gè)就不要加入

????UNNotificationActionOptionForeground?=?(1?<<?2),

}?__IOS_AVAILABLE(10.0)?__WATCHOS_AVAILABLE(3.0)?__TVOS_PROHIBITED;

測(cè)試我們預(yù)設(shè)好的category


-(void)timeLoacl{

????UNMutableNotificationContent?*content?=?[[UNMutableNotificationContent?alloc]?init];

????content.title?=?@"\"Fly?to?the?moon\"";

????content.subtitle?=?@"by?Neo";

????content.body?=?@"the?wonderful?song?with?you~";

????content.badge?=?@0;

????NSString?*path?=?[[NSBundle?mainBundle]?pathForResource:@"image1"ofType:@"png"];

????NSError?*error?=?nil;

????UNNotificationAttachment?*img_attachment?=?[UNNotificationAttachment?attachmentWithIdentifier:@"att1"URL:[NSURL?fileURLWithPath:path]?options:nil?error:&error];

????if(error)?{

????????NSLog(@"%@",?error);

????}

????content.attachments?=?@[img_attachment];

????//設(shè)置為@""以后衩侥,進(jìn)入app將沒有啟動(dòng)頁

????content.launchImageName?=?@"";

????UNNotificationSound?*sound?=?[UNNotificationSound?defaultSound];

????content.sound?=?sound;


????UNTimeIntervalNotificationTrigger?*time_trigger?=?[UNTimeIntervalNotificationTrigger?triggerWithTimeInterval:5?repeats:NO];

????NSString?*requestIdentifer?=?@"time?interval?request";

//在此指定通知內(nèi)容的categoryIdentifier,就是上面我們預(yù)設(shè)好的category矛物,一個(gè)category代表一種交互組合類型

????content.categoryIdentifier?=?@"seeCategory1";

//????content.categoryIdentifier?=?@"seeCategory";

????UNNotificationRequest?*request?=?[UNNotificationRequest?requestWithIdentifier:requestIdentifer?content:content?trigger:time_trigger];


????[[UNUserNotificationCenter?currentNotificationCenter]?addNotificationRequest:request?withCompletionHandler:^(NSError?*?_Nullable?error)?{

????????NSLog(@"%@",error);

????}];

}

在點(diǎn)擊某個(gè)按鈕或者是輸入了文本后茫死,會(huì)在通知中心的代理回調(diào)函數(shù)里處理交互的response


-?(void)userNotificationCenter:(UNUserNotificationCenter?*)center?didReceiveNotificationResponse:(UNNotificationResponse?*)response?withCompletionHandler:(void(^)())completionHandler{

????//在此,可判斷response的種類和request的觸發(fā)器是什么履羞,可根據(jù)遠(yuǎn)程通知和本地通知分別處理峦萎,再根據(jù)action進(jìn)行后續(xù)回調(diào)

????if([response?isKindOfClass:[UNTextInputNotificationResponse?class]])?{

????????UNTextInputNotificationResponse?*?textResponse?=?(UNTextInputNotificationResponse*)response;

????????NSString?*?text?=?textResponse.userText;

????????//do?something

????}

????else{

????????if([response.actionIdentifier?isEqualToString:@"see1"])?{

????????????//I?love?it~的處理

????????}

????????if([response.actionIdentifier?isEqualToString:@"see2"])?{

????????????//I?don't?care~

????????????[[UNUserNotificationCenter?currentNotificationCenter]?removeDeliveredNotificationsWithIdentifiers:@[response.notification.request.identifier]];

????????}

????}

????completionHandler();

}

這里需要根據(jù)response的類型或者根據(jù)actionIdentifier來區(qū)分用戶的交互結(jié)果來處理邏輯

iOS10通知附件UNNotificationAttachment,展示圖片忆首、Gif爱榔、Audio和Video

gif通知


-(void)timeLoaclWithImage{

????UNMutableNotificationContent?*content?=?[[UNMutableNotificationContent?alloc]?init];

????content.title?=?@"\"Fly?to?the?moon\"";

????content.subtitle?=?@"by?Neo";

????content.body?=?@"the?wonderful?song?with?you~";

????content.badge?=?@0;

????NSString?*path?=?[[NSBundle?mainBundle]?pathForResource:@"image1"ofType:@"png"];

????NSError?*error?=?nil;

????UNNotificationAttachment?*img_attachment?=?[UNNotificationAttachment?attachmentWithIdentifier:@"att1"URL:[NSURL?fileURLWithPath:path]?options:nil?error:&error];

????if(error)?{

????????NSLog(@"%@",?error);

????}

????content.attachments?=?@[img_attachment];

????//設(shè)置為@""以后,進(jìn)入app將沒有啟動(dòng)頁

????content.launchImageName?=?@"";

????UNNotificationSound?*sound?=?[UNNotificationSound?defaultSound];

????content.sound?=?sound;


????UNTimeIntervalNotificationTrigger?*time_trigger?=?[UNTimeIntervalNotificationTrigger?triggerWithTimeInterval:5?repeats:NO];

????NSString?*requestIdentifer?=?@"time?interval?request";

????content.categoryIdentifier?=?@"seeCategory1";

????UNNotificationRequest?*request?=?[UNNotificationRequest?requestWithIdentifier:requestIdentifer?content:content?trigger:time_trigger];


????[[UNUserNotificationCenter?currentNotificationCenter]?addNotificationRequest:request?withCompletionHandler:^(NSError?*?_Nullable?error)?{

????????NSLog(@"%@",error);

????}];

}

UNNotificationAttachment需要指定image糙及、gif详幽、audio與video的文件路徑,

+ (nullable instancetype)attachmentWithIdentifier:(NSString *)identifier URL:(NSURL *)URL options:(nullable NSDictionary *)options error:(NSError *__nullable *__nullable)error;

此處有一個(gè)options的字典丁鹉,傳入的key有一下幾點(diǎn):


//?Key?to?manually?provide?a?type?hint?for?the?attachment.?If?not?set?the?type?hint?will?be?guessed?from?the?attachment's?file?extension.?Value?must?be?an?NSString.

extern?NSString?*?const?

//指定文件類型妒潭,查看文檔可以發(fā)現(xiàn)支持哪些文件

UNNotificationAttachmentOptionsTypeHintKey?__IOS_AVAILABLE(10.0)?__WATCHOS_AVAILABLE(3.0);


//?Key?to?specify?if?the?thumbnail?for?this?attachment?is?hidden.?Defaults?to?NO.?Value?must?be?a?boolean?NSNumber.

extern?NSString?*?const?

//指定通知上是否顯示文件的縮略圖

UNNotificationAttachmentOptionsThumbnailHiddenKey?__IOS_AVAILABLE(10.0)?__WATCHOS_AVAILABLE(3.0);


//?Key?to?specify?a?normalized?clipping?rectangle?to?use?for?the?attachment?thumbnail.?Value?must?be?a?CGRect?encoded?using?CGRectCreateDictionaryRepresentation.

//指定縮略圖的切割比例

extern?NSString?*?const?UNNotificationAttachmentOptionsThumbnailClippingRectKey?__IOS_AVAILABLE(10.0)?__WATCHOS_AVAILABLE(3.0);


//?Key?to?specify?the?animated?image?frame?number?or?the?movie?time?to?use?as?the?thumbnail.

//?An?animated?image?frame?number?must?be?an?NSNumber.?A?movie?time?must?either?be?an?NSNumber?with?the?time?in?seconds?or?a?CMTime?encoded?using?CMTimeCopyAsDictionary.

extern?NSString?*?const?

//影片切割時(shí)間

UNNotificationAttachmentOptionsThumbnailTimeKey?__IOS_AVAILABLE(10.0)?__WATCHOS_AVAILABLE(3.0);

從網(wǎng)上獲取gif下載后展示

-(void)timeLoaclWithGif{

????NSURLSessionConfiguration?*config?=?[NSURLSessionConfiguration?defaultSessionConfiguration];

????NSURLSession?*session?=?[NSURLSession?sessionWithConfiguration:config];

????NSURLSessionDataTask?*task?=?[session?dataTaskWithURL:[NSURL?URLWithString:@"http://ww3.sinaimg.cn/large/006y8lVagw1faknzht671g30b408c1l2.gif"]?completionHandler:^(NSData?*?_Nullable?data,?NSURLResponse?*?_Nullable?response,?NSError?*?_Nullable?error)?{

????????if(!error)?{

//緩存到tmp文件夾

????????????NSString?*path?=?[NSHomeDirectory()?stringByAppendingPathComponent:[NSString?stringWithFormat:@"tmp/%@att.%@",@([NSDate?date].timeIntervalSince1970),@"gif"]];

????????????NSError?*err?=?nil;

????????????[data?writeToFile:path?atomically:YES];

????????????UNNotificationAttachment?*gif_attachment?=?[UNNotificationAttachment?attachmentWithIdentifier:@"attachment"URL:[NSURL?fileURLWithPath:path]?options:@{UNNotificationAttachmentOptionsThumbnailClippingRectKey:[NSValue?valueWithCGRect:CGRectMake(0,?0,?1,?1)]}?error:&err];

????????????UNMutableNotificationContent?*content?=?[[UNMutableNotificationContent?alloc]?init];

????????????content.title?=?@"\"Fly?to?the?moon\"";

????????????content.subtitle?=?@"by?Neo";

????????????content.body?=?@"the?wonderful?song?with?you~";

????????????content.badge?=?@0;

????????????NSError?*error?=?nil;

????????????if(gif_attachment)?{

????????????????content.attachments?=?@[gif_attachment];

????????????}

????????????if(error)?{

????????????????NSLog(@"%@",?error);

????????????}

????????????//設(shè)置為@""以后悴能,進(jìn)入app將沒有啟動(dòng)頁

????????????content.launchImageName?=?@"";

????????????UNNotificationSound?*sound?=?[UNNotificationSound?defaultSound];

????????????content.sound?=?sound;

????????????UNTimeIntervalNotificationTrigger?*time_trigger?=?[UNTimeIntervalNotificationTrigger?triggerWithTimeInterval:1?repeats:NO];

????????????NSString?*requestIdentifer?=?@"time?interval?request";

????????????content.categoryIdentifier?=?@"seeCategory1";

????????????UNNotificationRequest?*request?=?[UNNotificationRequest?requestWithIdentifier:requestIdentifer?content:content?trigger:time_trigger];

????????????[[UNUserNotificationCenter?currentNotificationCenter]?addNotificationRequest:request?withCompletionHandler:^(NSError?*?_Nullable?error)?{

????????????????NSLog(@"%@",error);

????????????}];

????????}

????}];

????[task?resume];

}

在文件緩存以后,發(fā)起本地通知雳灾。值得注意的一點(diǎn)是漠酿,形成request發(fā)起以后,如果URL所代表的文件過大谎亩,打開通知的交互界面的時(shí)候會(huì)非常慢炒嘲,甚至有時(shí)候會(huì)出現(xiàn)資源顯示不出來,還有一點(diǎn)是匈庭,當(dāng)你在通知觸發(fā)展示以后夫凸,再通過request取出attachment文件的URL的時(shí)候,發(fā)現(xiàn)URL竟然發(fā)生了變化阱持,文件是緩存到一個(gè)叫pushstore的文件夾下夭拌,這個(gè)在后面介紹 Notification Service Extension與Notification Content Extension 數(shù)據(jù)共享的時(shí)候會(huì)討論該問題。

iOS10 Notification Service Extension:

Notification Service Extension是Xcode8中加入眾多extension的其中一種衷咽,Extension實(shí)際上是App提供了一個(gè)額外插件功能鸽扁,以供iOS操作系統(tǒng)調(diào)用,與App是宿主關(guān)系镶骗。

Notification Service Extension target

工作流程如下:

Notification Service Extension流程

Notification Service Extension的作用:

使得推送的數(shù)據(jù)在iOS系統(tǒng)展示之前桶现,經(jīng)過App開發(fā)者的Extension,可以在不啟動(dòng)App的情況下鼎姊,完成一些快捷操作邏輯骡和,比如上面的例子,如果你是個(gè)社交App相寇,可以在不啟動(dòng)App的情況下慰于,直接點(diǎn)贊回復(fù),而不用打開App裆赵,提高效率

雖然iOS10的推送數(shù)據(jù)包已經(jīng)達(dá)到4k东囚,但是對(duì)于一些圖片視頻gif還是無力的,有了Extension战授,可以在此下載完畢然后直接展示,豐富的圖片和視頻可以在此顯示

可以在此Extension中如果要完成1中所述的用戶行為操作桨嫁,則必須加強(qiáng)安全性植兰,服務(wù)端可以對(duì)推送的數(shù)據(jù)配合RSA算法用服務(wù)端的私鑰加密,在Extension中使用服務(wù)端私鑰解密璃吧,其實(shí)APNs從SSL數(shù)字安全證書到Json Web Token令牌楣导,已經(jīng)非常安全,但是大量的App使用第三方諸如JPush的推送服務(wù)畜挨,來跟APNs交互筒繁,業(yè)務(wù)數(shù)據(jù)跑在別人的管道上噩凹,當(dāng)然有所顧忌,所以毡咏,這個(gè)地方加密的更多現(xiàn)實(shí)意義是防止業(yè)務(wù)數(shù)據(jù)被第三方服務(wù)商窺探驮宴。

新建一個(gè)target

addtarget_notification_service_extension

這點(diǎn)沒什么好說的,BundleID 就是宿主App的BundleID.這里設(shè)置的ProductName 呕缭,自動(dòng)生成堵泽。

注意使用組織名與team證書。

在新生成的NotificationService文件里有如下方法


?-(void)didReceiveNotificationRequest:(UNNotificationRequest?*)request?withContentHandler:(void?(^)(UNNotificationContent?*?_Nonnull))contentHandler?{

????self.contentHandler?=?contentHandler;

????self.bestAttemptContent?=?[request.content?mutableCopy];

????self.bestAttemptContent.title?=@"";

????//?Modify?the?notification?content?here...

????NSDictionary?*?userInfo?=?request.content.userInfo;

????NSURLSessionConfiguration?*config?=?[NSURLSessionConfiguration?defaultSessionConfiguration];

????NSURLSession?*session?=?[NSURLSession?sessionWithConfiguration:config];

????//服務(wù)端與客戶端約定各種資源的url恢总,根據(jù)url資源進(jìn)行下載

????NSString?*?imageUrl?=?[userInfo?objectForKey:@"imageUrl"];

????NSString?*?gifUrl?=?[userInfo?objectForKey:@"gifUrl"];

????NSString?*?typeString?;

????NSURL?*?url;

????if(imageUrl.length>0)?{

????????url?=?[NSURL?URLWithString:imageUrl];

????????typeString?=?@"jpg";

????}

????if(gifUrl.length>0)?{

????????url?=?[NSURL?URLWithString:gifUrl];

????????typeString?=?@"gif";

????}

????if(url)?{

????????NSURLRequest?*?urlRequest?=?[NSURLRequest?requestWithURL:url?cachePolicy:NSURLRequestUseProtocolCachePolicy?timeoutInterval:5];

//注意使用DownloadTask迎罗,這點(diǎn)會(huì)詳細(xì)說明

????????NSURLSessionDownloadTask?*task?=?[session?downloadTaskWithRequest:urlRequest?completionHandler:^(NSURL?*?_Nullable?location,?NSURLResponse?*?_Nullable?response,?NSError?*?_Nullable?error)?{

????????????if(!error)?{

????????????????NSString?*path?=?[location.path?stringByAppendingString:[NSString?stringWithFormat:@".%@",typeString]];

????????????????NSError?*err?=?nil;

????????????????NSURL?*?pathUrl?=?[NSURL?fileURLWithPath:path];

????????????????[[NSFileManager?defaultManager]?moveItemAtURL:location?toURL:pathUrl?error:nil];

//下載完畢生成附件,添加到內(nèi)容中

????????????????UNNotificationAttachment?*resource_attachment?=?[UNNotificationAttachment?attachmentWithIdentifier:@"attachment"URL:pathUrl?options:nil?error:&err];

????????????????if(resource_attachment)?{

????????????????????self.bestAttemptContent.attachments?=?@[resource_attachment];

????????????????}

????????????????if(error)?{

????????????????????NSLog(@"%@",?error);

????????????????}

????????????????//設(shè)置為@""以后片仿,進(jìn)入app將沒有啟動(dòng)頁

????????????????self.bestAttemptContent.launchImageName?=?@"";

????????????????UNNotificationSound?*sound?=?[UNNotificationSound?defaultSound];

????????????????self.bestAttemptContent.sound?=?sound;

//回調(diào)給系統(tǒng)

????????????????self.contentHandler(self.bestAttemptContent);

????????????}

????????????else{

????????????????self.contentHandler(self.bestAttemptContent);

????????????}

????????}];

????????[task?resume];

????}

????else{

????????self.contentHandler(self.bestAttemptContent);

????}

}

6

-?(void)serviceExtensionTimeWillExpire?{

????//?Called?just?before?the?extension?will?be?terminated?by?the?system.

????//?Use?this?as?an?opportunity?to?deliver?your?"best?attempt"?at?modified?content,?otherwise?the?original?push?payload?will?be?used.

????self.contentHandler(self.bestAttemptContent);

}

WWDC2016上的俄羅斯口音小伙上臺(tái)講Notification Service Extension的時(shí)候纹安,明確提到了”You will get a short execution time, which means this is not for long background running tasks.“,但實(shí)際測(cè)試過程中砂豌,Notification Service Extension非常容易崩潰crash和內(nèi)存溢出out of memory钻蔑。

更加坑的是debug運(yùn)行的時(shí)候和真機(jī)運(yùn)行的時(shí)候,Notification Service Extension性能表現(xiàn)是不一樣的奸鸯,真機(jī)運(yùn)行的時(shí)候Notification Service Extension非常容易不起作用咪笑,我做了幾次實(shí)驗(yàn),圖片稍大娄涩,Notification Service Extension就崩潰了不起作用了窗怒,而相同的debug調(diào)試環(huán)境下則沒問題,我覺得他應(yīng)該也提提這個(gè)蓄拣,比如說你下載資源的時(shí)候最好分段緩存下載扬虚,真機(jī)環(huán)境下NSURLSessionDataTask下載數(shù)據(jù)不好使,必須使用NSURLSessionDownloadTask才可以球恤,這點(diǎn)很無奈辜昵。

iOS10 Notification Content Extension:

自定義通知UI

Notification Content Extension是另外一個(gè)擴(kuò)展,其內(nèi)容使用了UserNotificationsUIFramework咽斧,首先還是創(chuàng)建Notification Content Extension的target堪置。

Notification Content Extension

此時(shí)會(huì)得到Notification Content Extension與MainInterface,storyboard里面含有一個(gè)試圖控制器张惹,這個(gè)試圖控制器就是Notification點(diǎn)擊后中間顯示的那部分舀锨。這部分你可以自定義UI,注意的是該視圖控制器無法響應(yīng)交互控件宛逗,要想使用交互組件坎匿,就必須配合UNNotificationAction和category來對(duì)應(yīng)你的UI部分,還有一點(diǎn),Notification Content Extension只能有一個(gè)控制器替蔬,所以你要想定制多種UI告私,就需要代碼判斷加載不同的View來實(shí)現(xiàn)。

自定義UI部分.png

在視圖控制器部分承桥,代碼如下:

-?(void)didReceiveNotification:(UNNotification?*)notification?{

????self.label.text?=?notification.request.content.body;

????UNNotificationAttachment?*?attachment?=?notification.request.content.attachments.firstObject;

????if(attachment)?{

????????//開始訪問pushStore的存儲(chǔ)權(quán)限

????????[attachment.URL?startAccessingSecurityScopedResource];

????????NSData?*?data?=?[NSData?dataWithContentsOfFile:attachment.URL.path];

????????[attachment.URL?stopAccessingSecurityScopedResource];

????????self.imageView.image?=?[UIImage?imageWithData:data];

????}

}

-?(void)didReceiveNotificationResponse:(UNNotificationResponse?*)response?completionHandler:(void?(^)(UNNotificationContentExtensionResponseOption?option))completion;{

????if([response?isKindOfClass:[UNTextInputNotificationAction?class]])?{

????????//處理提交文本的邏輯

????}

????if([response.actionIdentifier?isEqualToString:@"see1"])?{

????????//處理按鈕3

????}

????if([response.actionIdentifier?isEqualToString:@"see2"])?{

????????//處理按鈕2

????}

????//可根據(jù)action的邏輯回調(diào)的時(shí)候傳入不同的UNNotificationContentExtensionResponseOption

????completion(UNNotificationContentExtensionResponseOptionDismiss);

}

加入你有了Service Extension在前面下載好了圖片或者是視頻驻粟,在自定義UI部分你想獲取,就可以通過UNNotificationAttachment * attachment = notification.request.content.attachments.firstObject;查找附件來獲取數(shù)據(jù)快毛,但是必須注意格嗅,前面提到的是,形成附件后唠帝,文件的實(shí)際存儲(chǔ)被移到了pushStore的一個(gè)系統(tǒng)級(jí)別的緩存文件夾屯掖,此時(shí)需要調(diào)用NSURL在iOS8開始提供的兩個(gè)方法來獲取權(quán)限,提取數(shù)據(jù)襟衰。

startAccessingSecurityScopedResource

stopAccessingSecurityScopedResource

點(diǎn)擊按鈕后贴铜,回調(diào)的方法是didReceiveNotificationResponse,在前面已經(jīng)演示過瀑晒,在這绍坝,可以不用打開App進(jìn)而完成一些交互動(dòng)作。

Info.plist文件有一些設(shè)置需要表明

Info.plist設(shè)置

UNNotificationExtensionCategory改成數(shù)組苔悦,將你自定義的UI支持的categoryIdentifier一一放上轩褐,這樣,APNs推過來的數(shù)據(jù)中category包含哪個(gè)值玖详,就調(diào)用哪個(gè)UNNotificationCategory設(shè)置好的actions交互組合

UNNotificationExtensionInitialContentSizeRatio把介,自定義內(nèi)容的高度與寬度的比值,當(dāng)然也可以在ViewDidLoad中修改preferredContentSize來完成這一目標(biāo)

UNNotificationExtensionDefaultContentHidden蟋座,決定是否在自定義UI下部顯示通知的原內(nèi)容拗踢,默認(rèn)是顯示

Extensions 數(shù)據(jù)共享:

ServiceExtension與ContentExtension配合使用是非常棒的組合,在ServiceExtension中預(yù)先下載好數(shù)據(jù)向臀,用戶點(diǎn)擊后在ContentExtension中直接展示巢墅,這樣交互會(huì)比較流暢,有一個(gè)問題是券膀,如果你想在不打開App的時(shí)候使用自定義的action來與用戶交互君纫,就必須加ContentExtension,因?yàn)橹挥兴芙邮沼脩酎c(diǎn)擊action的response三娩,ServiceExtension是沒有的庵芭。

如果你想使你的App在打開的時(shí)候訪問到這些數(shù)據(jù),同樣可以根據(jù)UNNotificationAttachment來查找雀监,但是更好的方案我個(gè)人覺得可以是用App Group來解決這個(gè)問題,當(dāng)然App Group的過多討論是偏離本文章的話題的。

動(dòng)態(tài)配置通知交互:

上面我們可以知道会前,Notification可以配上很多category與action來自定義交互方式好乐,但都是硬編碼來實(shí)現(xiàn),有時(shí)候我們想讓某個(gè)actionIdentifier對(duì)應(yīng)的按鈕文字改變一下瓦宜,或者是某個(gè)category對(duì)應(yīng)的actions改變一下蔚万,來滿足運(yùn)營(yíng)活動(dòng)的靈活性,需要思考動(dòng)態(tài)配置UNNotificationCategory和UNNotificationAction的問題临庇。有如下這個(gè)方案反璃,可以把UNNotificationCategory和UNNotificationAction做成配置文件,如下:

{

?????"NotificationConfig":?{

????????"UNNotificationCategory":?{

????????????"seeCategory":?{

????????????????"identifier":?"seeCategory",

????????????????"actions":?["see1","see2"],

????????????????"options":?0

????????????}

????????},

????????"UNNotificationAction":?{

????????????"see1":?{

????????????????"identifier":?"see1",

????????????????"title":?"I?love?it~",

????????????????"options":?4

????????????},

????????????"see2":?{

????????????????"identifier":?"see2",

????????????????"title":?"I?dont't?care~",

????????????????"options":?4

????????????}

????????}

????}

}

然后在通知中心設(shè)置categorys的時(shí)候


-(NSSet?*)createNotificationCategoryActions{

????if(HBCONFIGOBJECT.moduleConfig.userNotificationConfig)?{

??????//讀取json文件

????????NSDictionary?*?notificationConfig;

????????NSDictionary?*?UNNotificationCategorys?=[notificationConfig?objectForKey:@"UNNotificationCategory"];

????????NSDictionary?*?UNNotificationActions?=?[notificationConfig?objectForKey:@"UNNotificationAction"];

????????NSMutableSet?*?set?=?[NSMutableSet?set];

????????for(NSString?*?categoryKey?inUNNotificationCategorys.allKeys)?{

????????????NSDictionary?*?cateDict?=?UNNotificationCategorys[categoryKey];

????????????NSString?*?cateId?=?[cateDict?objectForKey:@"identifier"];

????????????NSArray?*?cateActions?=?[cateDict?objectForKey:@"actions"];

????????????NSNumber?*?cateOptions?=?[cateDict?objectForKey:@"options"];

????????????NSMutableArray?*?actionsArr?=?[[NSMutableArray?alloc]init];

????????????for(NSString?*?actionKey?incateActions)?{

????????????????NSDictionary?*?actionDict?=?[UNNotificationActions?objectForKey:actionKey];

????????????????if(actionDict)?{

????????????????????NSString?*?actionId?=?[actionDict?objectForKey:@"identifier"];

????????????????????NSString?*?actionTitle?=?[actionDict?objectForKey:@"title"];

????????????????????NSNumber?*?actionOption?=?[actionDict?objectForKey:@"options"];

????????????????????UNNotificationAction?*?action?=?[UNNotificationAction?actionWithIdentifier:actionId?title:actionTitle?options:actionOption.unsignedIntegerValue];

????????????????????[actionsArr?addObject:action];

????????????????}

????????????}

????????????UNNotificationCategory?*?category?=?[UNNotificationCategory?categoryWithIdentifier:cateId?actions:actionsArr?intentIdentifiers:cateActions?options:cateOptions.unsignedIntegerValue];

????????????[set?addObject:category];

????????}

????????returnset;

????}

????else

????{

????????returnnil;

????}

}

這樣就可以任意組合category和actions了假夺,json文件可以在App內(nèi)部做全量更新淮蜈,在運(yùn)營(yíng)活動(dòng)之前,就下發(fā)好給客戶端已卷。

有一個(gè)問題是梧田,ContentExtension需要在plist里指定category,所以建議將categoryIdentifier按照一定格式進(jìn)行序列化取名侧蘸,在ContentExtension提前寫入0-10等很多的category裁眯,方面動(dòng)態(tài)配置的時(shí)候取用。

運(yùn)營(yíng)如何使用通知與推送:

Instagram上iOS10通知的使用

iOS10推出了十分出色的通知以后,我經(jīng)常使用的Instagram、Twitter蜜笤、Facebook等都及時(shí)跟進(jìn)精置,做出了非常好的交互,我希望微信團(tuán)隊(duì)能在通知上快速預(yù)覽內(nèi)容和回復(fù)上面增加此功能搬泥。

其實(shí),這個(gè)話題是我非常想討論的,作為工程師埋虹,有得天獨(dú)厚的條件深刻理解最新最前沿的技術(shù),那么娩怎,這些技術(shù)如何產(chǎn)生現(xiàn)實(shí)意義搔课,如何使用,在這點(diǎn)上截亦,工程師是非常具有優(yōu)勢(shì)的爬泥,假如你了解硅谷的工程師文化,你就會(huì)發(fā)現(xiàn)崩瓤,硅谷的科技公司很少有產(chǎn)品經(jīng)理的袍啡,大部分出色的功能和優(yōu)質(zhì)的用戶體驗(yàn)是由工程師打造的,詳情可以參考MacTalk的一篇文章《硅谷不需要產(chǎn)品經(jīng)理》却桶。

真正的工程師文化境输,不像國(guó)內(nèi)的開發(fā)者認(rèn)為的是在某一技術(shù)領(lǐng)域非常深的理論研究蔗牡,在國(guó)外的開發(fā)者眼里,真正的工程師文化是一群善于創(chuàng)造并且有巨大的改變現(xiàn)實(shí)世界的能力的工程師文化嗅剖,話說回來辩越,現(xiàn)如今,移動(dòng)端的工程師很多很多信粮,像本篇這樣的技術(shù)介紹類的文章數(shù)不勝數(shù)黔攒,技術(shù)水平差不多的工程師非常之多,你如何脫穎而出强缘?這是你需要思考的督惰,我的建議是,作為工程師旅掂,跟你一樣熟悉API和開發(fā)技術(shù)的人多了去了赏胚,但是如果你能知道技術(shù)在各種場(chǎng)景下的最佳使用方案,并且能切實(shí)改變現(xiàn)實(shí)情況辞友,舉個(gè)栅哀,iOS10的通知你是了解,但怎么用才能更好的提升你的App的用戶體驗(yàn)称龙?更好的提高你的App在某些功能場(chǎng)景下的用戶使用成本留拾?怎么樣才能讓運(yùn)營(yíng)活動(dòng)通過通知提高活躍度?如果你有這樣的各種解決方案鲫尊,你就是勝出者~比方說痴柔,你是社交類App的開發(fā)者,你有一堆技術(shù)解決方案在手疫向,能夠切實(shí)提升用戶體驗(yàn)的咳蔚,你是電商類開發(fā)者,你有通知的技術(shù)使用解決方案能夠更好的支撐運(yùn)營(yíng)活動(dòng)的搔驼。

那iOS10的通知能想到哪些使用場(chǎng)景呢谈火?

運(yùn)營(yíng)活動(dòng)可以配上活動(dòng)海報(bào)或者是動(dòng)圖海報(bào),在用戶點(diǎn)擊好能更好的查看運(yùn)營(yíng)活動(dòng)詳情

即時(shí)通訊類的App可以通過自定義ContentExtension來在通知上完成回復(fù)消息

比方說舌涨,你有個(gè)秒殺活動(dòng)糯耍,通知一下來,用戶立馬可以通過iOS10的通知交互完成秒殺預(yù)定囊嘉,然后再啟動(dòng)App慢慢付款~這個(gè)用戶體驗(yàn)的提升那是相當(dāng)巨大的

比方說温技,你可以通過推送收取一些用戶對(duì)某個(gè)活動(dòng)或者新版本的反饋意見?使用TextAction來做

你是否可可以發(fā)個(gè)可視化的賬單給用戶扭粱,在自定義UI上顯示舵鳞?

……

再來說說技術(shù)方案吧,上面的場(chǎng)景要想實(shí)現(xiàn)琢蛤,有個(gè)問題是蜓堕,通知的ServiceExtension和ContentExtension拿到了用戶反饋的信息抛虏,那這些信息該怎么辦~方案如下:

最新通知交互方案

這是個(gè)簡(jiǎn)單的單推交互方案,其中需要由動(dòng)態(tài)化配置Category與actions支撐俩滥,同時(shí)要做好加解密工作嘉蕾。

以上贺奠,就是本次討論通知和推送的主要內(nèi)容

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末霜旧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子儡率,更是在濱河造成了極大的恐慌挂据,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件儿普,死亡現(xiàn)場(chǎng)離奇詭異崎逃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)眉孩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門个绍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浪汪,你說我怎么就攤上這事巴柿。” “怎么了死遭?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵广恢,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我呀潭,道長(zhǎng)钉迷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任钠署,我火速辦了婚禮糠聪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谐鼎。我一直安慰自己舰蟆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布该面。 她就那樣靜靜地躺著夭苗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪隔缀。 梳的紋絲不亂的頭發(fā)上题造,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音猾瘸,去河邊找鬼界赔。 笑死丢习,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的淮悼。 我是一名探鬼主播咐低,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼袜腥!你這毒婦竟也來了见擦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤羹令,失蹤者是張志新(化名)和其女友劉穎鲤屡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體福侈,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酒来,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肪凛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堰汉。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖伟墙,靈堂內(nèi)的尸體忽然破棺而出翘鸭,到底是詐尸還是另有隱情,我是刑警寧澤远荠,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布矮固,位于F島的核電站,受9級(jí)特大地震影響譬淳,放射性物質(zhì)發(fā)生泄漏档址。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一邻梆、第九天 我趴在偏房一處隱蔽的房頂上張望守伸。 院中可真熱鬧,春花似錦浦妄、人聲如沸尼摹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蠢涝。三九已至,卻和暖如春阅懦,著一層夾襖步出監(jiān)牢的瞬間和二,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工耳胎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惯吕,地道東北人惕它。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像废登,于是被迫代替她去往敵國(guó)和親淹魄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載自:iOS10里的通知與推送 原文 通知和推送是一種東西么堡距? iOS 10通知 推送 圖1為通知甲锡,圖2為推送也...
    路漫漫其修遠(yuǎn)兮Wzt閱讀 943評(píng)論 0 1
  • 介紹一下iOS10的通知新功能,用戶體驗(yàn)的提升和開發(fā)者能夠發(fā)揮的地方非常多吏颖,使得iOS更具有競(jìng)爭(zhēng)力搔体。 1.iOS ...
    F麥子閱讀 3,824評(píng)論 3 4
  • 愛情即將到來的那一刻是那么的令人心動(dòng)。當(dāng)在東京人潮涌動(dòng)的大街上劝术,鮑勃終于把夏洛特?fù)砣霊阎兴醵啵谒利惖碾p唇上深...
    S小姐love閱讀 180評(píng)論 0 0
  • 家人們衬吆,早上好! 分享一篇文章绳泉,這是今天早上咱們校長(zhǎng)發(fā)在工作群里的逊抡,我轉(zhuǎn)發(fā)給大家。 題目:《親愛的孩子零酪,我允許你不...
    陽光溫溫閱讀 250評(píng)論 0 2
  • 開始100天看書以來冒嫡,看了兩本小說,另外一本都不想提了四苇,太差勁孝凌。第二本就是《圍城》了,不得不說是真精彩月腋。熄燈之后在...
    上下春秋閱讀 140評(píng)論 0 0