iOS10-UserNotifications

1. 簡介

  1. UserNotifications官方文檔說明
  2. 內(nèi)容豐富;可以獲得用戶是否同意推送等notification setting信息;提供trigger;app在前臺可以捕捉并處理即將觸發(fā)的推送
  3. 框架是UserNotifications.framework;支持UserNotificationsUI.framework自定義通知的UI展示

2. UserNotifications.framework

2.1 本地通知的trigger

  1. 新功能trigger,可以在特定條件觸發(fā),有三類:UNTimeIntervalNotificationTrigger、UNCalendarNotificationTrigger、UNLocationNotificationTrigger
  2. UNTimeIntervalNotificationTrigger:一段時(shí)間后觸發(fā)
//2min后提醒
UNTimeIntervalNotificationTrigger *trigger1 = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:120 repeats:NO];
  1. UNCalendarNotificationTrigger :調(diào)用triggerWithDateMatchingComponents:repeats: 進(jìn)行注冊;時(shí)間點(diǎn)信息用 NSDateComponents
//每周日早上 8:00 提醒
NSDateComponents *components = [[NSDateComponents alloc] init];
components.weekday = 1;
components.hour = 8;
UNCalendarNotificationTrigger *trigger2 = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];
//NSDateComponets的注意點(diǎn),有了時(shí)間并不能得到weekday
   NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
   dateComponents.day = 11;
   dateComponents.month = 7;
   dateComponents.year = 2016;
   //輸出結(jié)果是NSDateComponentUndefined = NSIntegerMax
   NSLog(@"%td", dateComponents.weekday);
   //根據(jù)calendar計(jì)算出當(dāng)天是周幾
   NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
   NSDate *date = [gregorianCalendar dateFromComponents:dateComponents];
   NSInteger weekday = [gregorianCalendar component:NSCalendarUnitWeekday fromDate:date];
   NSLog(@"%td", weekday);
   
   dateComponents.weekday = weekday;
   NSLog(@"%@", dateComponents);
  1. UNLocationNotificationTrigger:調(diào)用triggerWithRegion:repeats:進(jìn)行注冊,地區(qū)信息使用CLRegion,可以配置region屬性 notifyOnEntry和notifyOnExit,是在進(jìn)入地區(qū)、從地區(qū)出來或者兩者都要的時(shí)候進(jìn)行通知
//圓形區(qū)域,進(jìn)入時(shí)候進(jìn)行通知
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(37.335400, -122.009201);
CLCircularRegion* region = [[CLCircularRegion alloc] initWithCenter:center
                radius:2000.0 identifier:@"Headquarters"];
region.notifyOnEntry = YES;
region.notifyOnExit = NO;
UNLocationNotificationTrigger* trigger = [UNLocationNotificationTrigger
                triggerWithRegion:region repeats:NO];

2.2 Content

UNNotificationContent:屬性readOnly
UNMutableNotificationContent:屬性有title、subtitle、body、badge、sound、lauchImageName、userInfo、attachments、categoryIdentifier、threadIdentifier

本地消息內(nèi)容 內(nèi)容限制大小 展示
title NSString 限制在一行,多出部分省略號
subtitle NSString 限制在一行,多出部分省略號
body NSString 通知欄出現(xiàn)時(shí),限制在兩行,多出部分省略號;預(yù)覽時(shí),全部展示

注意點(diǎn): body中printf風(fēng)格的轉(zhuǎn)義字符,比如說要包含%,需要寫成%% 才會(huì)顯示,\同樣


notification

2.2.1 attachments

  1. 本地推送和遠(yuǎn)程推送同時(shí)都可支持附帶Media Attachments。不過遠(yuǎn)程通知需要實(shí)現(xiàn)通知服務(wù)擴(kuò)展UNNotificationServiceExtension,在service extension里面去下載attachment,但是需要注意,service extension會(huì)限制下載的時(shí)間,并且下載的文件大小也會(huì)同樣被限制。這里畢竟是一個(gè)推送,而不是把所有的內(nèi)容都推送給用戶。所以你應(yīng)該去推送一些縮小比例之后的版本。比如圖片,推送里面附帶縮略圖,當(dāng)用戶打開app之后,再去下載完整的高清圖。視頻就附帶視頻的關(guān)鍵幀或者開頭的幾秒,當(dāng)用戶打開app之后再去下載完整視頻。
  2. attachment支持圖片,音頻,視頻,附件支持的類型及大小
  3. 系統(tǒng)會(huì)在通知注冊前校驗(yàn)附件,如果附件出問題,通知注冊失敗;校驗(yàn)成功后,附件會(huì)轉(zhuǎn)入attachment data store;如果附件是在app bundle,則是會(huì)被copy來取代move
  4. media attachments可以利用3d touch進(jìn)行預(yù)覽和操作
  5. attachment data store的位置?利用代碼測試 獲取在磁盤上的圖片文件作為attachment,會(huì)發(fā)現(xiàn)注冊完通知后,圖片文件被移除,在app的沙盒中找不到該文件在哪里; 想要獲取已存在的附件內(nèi)容,文檔中提及可以通過UNUserNotificationCenter中方法,但目前文檔中這2個(gè)方法還是灰的
getDataForAttachment:withCompletionHandler: 
getReadFileHandleForAttachment:withCompletionHandler:
sound notification

2.2.2 代碼片段示例

UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:@"Hello 5 seconds!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:@"Hello_message_body" arguments:nil];                                             
content.subtitle = [NSString localizedUserNotificationStringForKey:@"good day" arguments:nil];
content.sound = [UNNotificationSound defaultSound];

//NSURL *url = [[NSBundle mainBundle] URLForResource:@"image_1" withExtension:@"jpeg"];
NSURL *url = [[NSBundle mainBundle] URLForResource:@"xiongben" withExtension:@"gif"];
UNNotificationAttachment *attch = [UNNotificationAttachment attachmentWithIdentifier:@"photo" URL:url options:nil error:nil];
content.attachments = @[attch];

//......

2.3 actions

與UILocalNotification相似,也有action和category,在UserNotifications框架中對應(yīng)UNNotificationActionUNNotificationCategory

2.3.1 代碼片段示例

UNNotificationAction *enterAction = [UNNotificationAction actionWithIdentifier:@"enterApp" title:@"進(jìn)入應(yīng)用" options:UNNotificationActionOptionForeground];
UNNotificationAction *ingnoreAction = [UNNotificationAction actionWithIdentifier:@"ignore" title:@"忽略" options:UNNotificationActionOptionDestructive];
UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:@"helloIdentifier" actions:@[enterAction,ingnoreAction] minimalActions:@[enterAction,ingnoreAction] intentIdentifiers:@[] options:UNNotificationCategoryOptionNone];
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObjects:category, nil]];

2.4 注冊通知過程

  1. UNUserNotificationCenter規(guī)劃所有通知,管理和通知相關(guān)的行為;通過currentNotificationCenter獲取單例
  2. 獲取通知權(quán)限,通過requestAuthorizationWithOptions:completionHandler: 向用戶請求打開權(quán)限; getNotificationSettingsWithCompletionHandler: 可以返回通知權(quán)限狀態(tài)
  3. 設(shè)置UNMutableNotificationContent,通過通過categories配置可操作的通知
  4. 利用trigger設(shè)置通知出發(fā)的條件
  5. requestWithIdentifier:content:trigger:初始化UNNotificationRequest
  6. addNotificationRequest:withCompletionHandler: 注冊通知
  7. removePendingNotificationRequestsWithIdentifiers: 或者removeAllPendingNotificationRequests 可以取消通知

2.4.1 代碼示例

//authorization
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound)
                      completionHandler:^(BOOL granted, NSError * _Nullable error) {
                          if(granted)
                          {
                              NSLog(@"授權(quán)成功");
                          }
                      }];
//regitser
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:@"Hello 5 seconds!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:@"Hello_message_body" arguments:nil];
content.subtitle = [NSString localizedUserNotificationStringForKey:@"good day" arguments:nil];
content.sound = [UNNotificationSound defaultSound];

// Deliver the notification in ten seconds.
UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:10 repeats:NO];
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"FiveSecond"
                                                                      content:content
                                                                      trigger:trigger];

// Schedule the notification.
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
    if(error)
    {
        NSLog(@"%@",error);
    }
}];

2.5 UNUserNotificationCenterDelegate

  1. 主要2個(gè)方法:接收通知,處理用戶行為
  2. 通過userNotificationCenter:willPresentNotification:withCompletionHandler:將通知傳遞給前臺運(yùn)行的app
  3. 通過userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:將用戶對通知響應(yīng)結(jié)果告訴app

2.6 Structures

Structures desc
UNAuthorizationOptions badge、sound、alert、carPlay(在行車模式下也可以展示通知)
UNNotificationActionOptions autheticationRequired、destructive、foreground
UNNotificationPresentationOptions badge、sound、alert

3. UserNotificationsUI.framework

UserNotificationsUI文檔

3.1 UNNotificationContentExtension

  1. 如何自定義通知界面
  2. wwdc-2016-rich-notifications-in-ios-10
  3. 注意:stackoverflow上答案
    自定義界面(來自網(wǎng)絡(luò))

4. UNNotificationServiceExtension

4.1 模擬發(fā)送remote notification

NWPusher

4.1.1 app注冊遠(yuǎn)程通知,獲取deviceToken

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    [[UIApplication sharedApplication] registerForRemoteNotifications];
    
    return YES;
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(nonnull NSData *)deviceToken
{
    NSLog(@"deviceToken:%@",deviceToken);
    NSString *deviceTokenSt = [[[[deviceToken description]
                                 stringByReplacingOccurrencesOfString:@"<" withString:@""]
                                stringByReplacingOccurrencesOfString:@">" withString:@""]
                               stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSLog(@"deviceTokenSt:%@",deviceTokenSt);
}

4.2 調(diào)用到ServiceExtension的條件

  1. 遠(yuǎn)程通知展示alert給用戶
  2. 遠(yuǎn)程通知aps json字段中必須包含mutable-content鍵,并且值為1

4.3 主要處理函數(shù)

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
                   withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    // Modify the notification content here...
    self.contentHandler(self.bestAttemptContent);
}

在該方法下載附件,或者做其他處理變動(dòng),可以做到在通知到達(dá)用戶手機(jī)前做修改

4.3.1 aps內(nèi)容

{
"aps":
    {
        "alert":
        {
            "title":"hello",
            "subtitle" : "Session 01",
            "body":"it is a beautiful day"
        },
        "category":"helloIdentifier",
        "badge":1,
        "mutable-content":1,
        "sound":"default",
        "image":"https://picjumbo.imgix.net/HNCK8461.jpg?q=40&w=200&sharp=30"
    }
}

4.3.2 示例代碼

在上述didReceiveNotificationRequest: withContentHandler:方法中對image鍵值路徑請求數(shù)據(jù)下載到本地,然后通過url設(shè)置attach

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
                   withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];
    
    NSDictionary *apsDic = [request.content.userInfo objectForKey:@"aps"];
    NSString *attachUrl = [apsDic objectForKey:@"image"];
    NSLog(@"%@",attachUrl);
    
    //下載圖片,放到本地
    UIImage * imageFromURL = [self getImageFromURL:attachUrl];
    
    //獲取document目錄
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES );
    NSString *documentsDirectoryPath = [paths objectAtIndex:0];
    NSLog(@"document path: %@",documentsDirectoryPath);
    
    NSString *localPath = [self saveImage:imageFromURL withFileName:@"MyImage" ofType:@"png" inDirectory:documentsDirectoryPath];
    if (localPath && ![localPath  isEqualToString: @""])
    {
        UNNotificationAttachment *attch= [UNNotificationAttachment attachmentWithIdentifier:@"photo"
                                                                                        URL:[NSURL URLWithString:[@"file://" stringByAppendingString:localPath]]
                                                                                    options:nil
                                                                                      error:nil];
        if(attch)
        {
            self.bestAttemptContent.attachments = @[attch];
        }
    }
    
    self.contentHandler(self.bestAttemptContent);
}
   //另一種下載方式
    NSURLSession *session = [NSURLSession sharedSession];
    NSURL *url = [NSURL URLWithString:attachUrl];
    
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url
                                                        completionHandler:^(NSURL * _Nullable location,
                                                                            NSURLResponse * _Nullable response,
                                                                            NSError * _Nullable 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: @""])
                                                            {
                                                                UNNotificationAttachment *attch= [UNNotificationAttachment attachmentWithIdentifier:@"photo"
                                                                                                                                                URL:[NSURL URLWithString:[@"file://" stringByAppendingString:file]]
                                                                                                                                            options:nil
                                                                                                                                              error:nil];
                                                                if(attch)
                                                                {
                                                                    self.bestAttemptContent.attachments = @[attch];
                                                                }
                                                            }
                                                            self.contentHandler(self.bestAttemptContent);
                                                        }];
    [downloadTask resume];

4.3.3 git代碼地址

MyUserNotificationTestDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

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