<pre>上一篇中講到Message中的一些特性,本次主要講下Notification的特性</pre>
iOS10相對(duì)于之前的版本,主要是開發(fā)者可以使用Extension的形式修改和展示內(nèi)容,主要是<code>UNNotificationServiceExtension</code>和<code>UNNotificationContentExtension</code>。同時(shí)也添加了其他方面的支持,例如<code>UNNotificationTrigger</code>、<code>UNNotificationAttachment</code>、<code>UNNotificationAction</code>。本次講的主要有以下幾點(diǎn):
- UNNotificationTrigger(通知觸發(fā)條件設(shè)定)
- UNNotificationAttachment (通知附件)
- UNNotificationContentExtension (通知內(nèi)容擴(kuò)展)
- UNNotificationServiceExtension (通知服務(wù)擴(kuò)展)
- UNNotificationAction (通知響應(yīng)事件)
1、UNNotificationTrigger(通知觸發(fā)條件設(shè)定)
主要是針對(duì)本地通知觸發(fā)時(shí)機(jī)的設(shè)置,可以使用下面方式設(shè)置:
- UNPushNotificationTrigger:這個(gè)是蘋果通知服務(wù)的 Trigger,對(duì)外沒有暴露任何接口屬性,不需要開發(fā)者創(chuàng)建,由系統(tǒng)創(chuàng)建。
- UNTimeIntervalNotificationTrigger(時(shí)間觸發(fā)器):通過初始化方法設(shè)置通知的timeInterval(觸發(fā)間隔)
和repeats(是否重復(fù)觸發(fā)),若 repeats 設(shè)置為 false,通知將在 timeInterval 之后被推送。 - UNCalendarNotificationTrigger(日期觸發(fā)器):類似 UNTimeIntervalNotificationTrigger,也是時(shí)間觸發(fā)器,只不過初始化時(shí)第一個(gè)參數(shù)為 DateComponents類型,可設(shè)置具體的觸發(fā)時(shí)間比如8:00 AM等,也可設(shè)置是否重復(fù)觸發(fā)。
- UNLocationNotificationTrigger(位置觸發(fā)器):通過設(shè)置 CLRegion類型參數(shù)設(shè)置位置信息,當(dāng)用戶處于某一區(qū)域時(shí),自動(dòng)推送通知。
使用:
//設(shè)置Notification內(nèi)容
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:@"title!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:@"body" arguments:nil];
content.subtitle = [NSString localizedUserNotificationStringForKey:@"subtitle" arguments:nil];
content.sound = [UNNotificationSound defaultSound];
//初始化時(shí)間觸發(fā)器
UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:10 repeats:NO];
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"Identifier"
content:content
trigger:trigger];
// 請(qǐng)求計(jì)劃推送
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if(error)
{
NSLog(@"%@",error);
}
}];
2、UNNotificationAttachment(通知附件)
蘋果所支持的推送附件類型包含視頻,音頻,圖片,蘋果的文檔中對(duì)文件的類型和大小做了如下限制:傳送門
使用說明:
- 本地通知:
設(shè)置<code>UNMutableNotificationContent</code>如下屬性
@property (NS_NONATOMIC_IOSONLY, copy) NSArray <UNNotificationAttachment *> *attachments```
- 遠(yuǎn)程通知:
通過URL地址下載資源,然后將資源設(shè)置到
request.content.attachments中示例代碼:
- (void)handlerImageWith:(NSString *)attachUrl{
[self downloadFileAndSave:[NSURL URLWithString:attachUrl] handler:^(NSURL *localUrl) {
if (localUrl){
UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"image_download" URL:localUrl options:nil error:nil];
self.bestAttemptContent.attachments = @[attachment];
}
self.contentHandler(self.bestAttemptContent);
}];
}
- (void)downloadFileAndSave:(NSURL *)url handler:(void (^)(NSURL *))handler{
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url
completionHandler:^(NSURL * _Nullable location,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
NSURL *localURL = nil;
if(!error){
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// response.suggestedFilename : 建議使用的文件名,一般跟服務(wù)器端的文件名一致
NSString *file = [caches stringByAppendingPathComponent:response.suggestedFilename];
// 將臨時(shí)文件剪切或者復(fù)制Caches文件夾
NSFileManager *mgr = [NSFileManager defaultManager];
// AtPath : 剪切前的文件路徑
// ToPath : 剪切后的文件路徑
[mgr moveItemAtPath:location.path toPath:file error:nil];
if (file && ![file isEqualToString: @""])
{
localURL = [NSURL URLWithString:[@"file://" stringByAppendingString:file]];
}
}
handler(localURL);
}];
[downloadTask resume];
}
注意事項(xiàng):
- UNNotificationContent 的 attachments雖然是一個(gè)數(shù)組,但是系統(tǒng)只會(huì)展示第一個(gè) attachment 對(duì)象的內(nèi)容。不過你依然可以發(fā)送多個(gè) attachments,然后在要展示的時(shí)候再重新安排它們的順序,以顯示最符合情景的圖片或者視頻。另外,你也可能會(huì)在自定義通知展示 UI 時(shí)用到多個(gè) attachment。
- 在當(dāng)前 beta (iOS 10 beta 4) 中,serviceExtensionTimeWillExpire被調(diào)用之前,你有 30 秒時(shí)間來處理和更改通知內(nèi)容。對(duì)于一般的圖片來說,這個(gè)時(shí)間是足夠的。但是如果你推送的是體積較大的視頻內(nèi)容,用戶又恰巧處在糟糕的網(wǎng)絡(luò)環(huán)境的話,很有可能無法及時(shí)下載完成。
- 如果你想在遠(yuǎn)程推送來的通知中顯示應(yīng)用 bundle 內(nèi)的資源的話,要注意 extension 的 bundle 和 app main bundle 并不是一回事兒。你可以選擇將圖片資源放到 extension bundle 中,也可以選擇放在 main bundle 里??傊?,你需要保證能夠獲取到正確的,并且你具有讀取權(quán)限的 url。關(guān)于從 extension 中訪問 main bundle,可以參看這篇回答。
- 系統(tǒng)在創(chuàng)建 attachement 時(shí)會(huì)根據(jù)提供的 url 后綴確定文件類型,如果沒有后綴,或者后綴無法不正確的話,你可以在創(chuàng)建時(shí)通過 UNNotificationAttachmentOptionsTypeHintKey
來指定資源類型。 - 如果使用的圖片和視頻文件不在你的 bundle 內(nèi)部,它們將被移動(dòng)到系統(tǒng)的負(fù)責(zé)通知的文件夾下,然后在當(dāng)通知被移除后刪除。如果媒體文件在 bundle 內(nèi)部,它們將被復(fù)制到通知文件夾下。每個(gè)應(yīng)用能使用的媒體文件的文件大小總和是有限制,超過限制后創(chuàng)建 attachment 時(shí)將拋出異常??赡艿乃绣e(cuò)誤可以在 UNError中找到。
- 你可以訪問一個(gè)已經(jīng)創(chuàng)建的 attachment 的內(nèi)容,但是要注意權(quán)限問題。可以使用 startAccessingSecurityScopedResource來暫時(shí)獲取以創(chuàng)建的 attachment 的訪問權(quán)限。比如:
if(notification.request.content.attachments && notification.request.content.attachments.count > 0){
NSURL *imageUrl = notification.request.content.attachments[0].URL;
if([imageUrl startAccessingSecurityScopedResource]){
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = [[UIImage alloc] initWithData:imageData];
self.imageView.image = image;
[imageUrl stopAccessingSecurityScopedResource];
}
}
3、UNNotificationContentExtension(通知內(nèi)容擴(kuò)展)
通知內(nèi)容擴(kuò)展需要新建一個(gè) UNNotificationContentExtension Target,之后只需在 viewcontroller 的中實(shí)現(xiàn)相應(yīng)的接口,即可以對(duì) app 的通知頁面進(jìn)行自定義擴(kuò)展,擴(kuò)展主要用于自定義 UI。擴(kuò)展頁面樣式可以在 plist 中配置,字段說明如下:
- UNNotificationExtensionCategory: 要讓通知支持內(nèi)容擴(kuò)展,需要將通知的 categoryIdentifier(類型標(biāo)示) 加入此處。
- UNNotificationExtensionDefaultContentHidden: 默認(rèn)內(nèi)容隱藏,如果設(shè)為 YES,則最下面通知 content 部分會(huì)隱藏。
- UNNotificationExtensionIntialContentSizeRation: 初始內(nèi)容 Size 的比例。也可以在 viewDidLoad 中使用 self.preferredContentSize 直接設(shè)置 Size。
使用說明:
遠(yuǎn)程和本地通知最終都可以使用此擴(kuò)展自定義 UI,只需將通知的 categoryIdentifier(類型標(biāo)示) 加入到 plist 中即可。
- 本地推送時(shí),確保設(shè)置的 content.categoryIdentifier(通知內(nèi)容類型標(biāo)示) 已加入 plist 中。
- 遠(yuǎn)程推送,需要設(shè)置 category 字段,且確保值也已加入 plist 中。
4、UNNotificationServiceExtension (通知服務(wù)擴(kuò)展)
UNNotificationServiceExtension 提供在遠(yuǎn)程推送將要被 push 出來前,處理推送顯示內(nèi)容的機(jī)會(huì)。此時(shí)可以對(duì)通知的 request.content 進(jìn)行內(nèi)容添加,如添加附件,userInfo 等。服務(wù)器推送實(shí)例:
{
"aps" : {
"alert" : {
"title" : "title",
"body" : "Your message Here"
},
// 開啟可變內(nèi)容
"mutable-content" : "1",
// 加入自定義數(shù)據(jù),圖片 url 路徑
"image":"http://....jpg"
}
}
示例代碼:
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
NSDictionary *apsDic = [request.content.userInfo objectForKey:@"aps"];
NSString *attachUrl = [apsDic objectForKey:@"image"];
if(attachUrl){
[self handlerImageWith:attachUrl];
}
}
5、UNNotificationAction(通知響應(yīng)事件)
代表一個(gè)響應(yīng)通知的事件??梢詾槊總€(gè)通知設(shè)置不同的交互事件。下拉推送通知或處在鎖屏界面?zhèn)然ㄖ獣r(shí),會(huì)出現(xiàn)交互按鍵。
交互事件主要分為以下兩類:
-
UNNotificationAction:
普通點(diǎn)擊按鍵,可設(shè)置 identifier、 title 及 點(diǎn)擊后的響應(yīng),例如:foreground 前臺(tái)響應(yīng),destructive 點(diǎn)擊后銷毀通知,authenticationRequired 響應(yīng)前是否需要解鎖。甚至可以使用 UNNotificationAction + accessoryInputView 結(jié)合,達(dá)到加入自定義輔助輸入控件的效果 -
UNTextInputNotificationAction:
當(dāng)然也可以直接使用系統(tǒng)類 UNTextInputNotificationAction 創(chuàng)建輸入框,但是風(fēng)格比較固定。
示例代碼:
- (void)registerNotificationCategory{
UNTextInputNotificationAction *inputAction = [UNTextInputNotificationAction actionWithIdentifier:@"action_reply" title:@"回復(fù)" options:UNNotificationActionOptionForeground];
UNNotificationAction *cancelAction = [UNNotificationAction actionWithIdentifier:@"action_cancel" title:@"取消" options:UNNotificationActionOptionDestructive];
UNNotificationCategory *saySomething = [UNNotificationCategory categoryWithIdentifier:saySomethingCategory actions:@[inputAction,cancelAction] intentIdentifiers:@[] options:UNNotificationCategoryOptionCustomDismissAction];
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:saySomething]];
}
響應(yīng)處理:
- 若處于 UNNotificationContentExtension 通知擴(kuò)展界面時(shí),點(diǎn)擊 【回復(fù)】按鍵會(huì)回調(diào) UNNotificationContentExtension 擴(kuò)展接口的方法:
// If implemented, the method will be called when the user taps on one
// of the notification actions. The completion handler can be called
// after handling the action to dismiss the notification and forward the
// action to the app if necessary.
- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption option))completion;{
}
- 如果不支持 UNNotificationContentExtension則點(diǎn)擊【回復(fù)】回調(diào) UNUserNotificationCenterDelegate 中的方法:
// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
}
補(bǔ)充:iOS10中可以在前臺(tái)中收到通知了,需要添加一下代碼:
\\ notificationHandler實(shí)現(xiàn)UNUserNotificationCenterDelegate
[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self.notificationHandler];