IOS10通知新特性:可以带附件缩略图,体验更好

iOS开发的童鞋都知道,苹果的APNS push在IOS10之前有字符数限制,智能包含简单的标题,描述。而,IOS 10的到来,可谓是对通知进行了一次极致体验的变革。

写在前面:

通知原理:

IOS10通知新特性:可以带附件缩略图,体验更好

在IOS使用新通知之前,需要在app启动之后注册devicetoken:

  1.   if (IOS10) {
  2.         //iOS10特有
  3.         UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  4.         // 必须写代理,不然无法监听通知的接收与点击
  5.         center.delegate = self;
  6.         [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
  7.             if (granted) {
  8.                 // 点击允许
  9.                 NSLog(@"注册成功");
  10.                 [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
  11.                     NSLog(@"%@", settings);
  12.                 }];
  13.             } else {
  14.                 // 点击不允许
  15.                 NSLog(@"注册失败");
  16.             }
  17.         }];
  18.     }
  19.     else if (IOS8) {
  20.         //ios 8 and later
  21.         //        [self setPriviteNotificationBtnStyleWithTitle:@"TWO" indifier:@"TWO"];
  22.         //
  23.         //        [self setPriviteNotificationBtnStyleWithTitle:@"ONE" indifier:@"ONE"];
  24.         //
  25.         //        [self setPriviteNotificationBtnStyleWithTitle:@"THREE" indifier:@"TEST"];
  26.         _customTypes = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
  27.         UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:_customTypes categories:_customCategorySet];
  28.         [application registerUserNotificationSettings:mySettings];
  29. //        [application registerForRemoteNotifications];
  30.     } else {
  31.         [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert |UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
  32.     }
  33. //    [application registerForRemoteNotifications];//

然后,需要在appdelegate中实现相应的代理方法:需要注意IOS10的deviceToken获取和之前的版本没有区别,主要的区别在于注册和后续的监听通知事件的代理方法。

  1. //本地推送通知  
  2. -(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
  3. {
  4.     //成功注册registerUserNotificationSettings:后,回调的方法  
  5.     NSLog(@"%@",notificationSettings);
  6. }
  7. -(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
  8. {
  9.     //收到本地推送消息后调用的方法  
  10.     NSLog(@"%@",notification);
  11. }
  12. -(void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler
  13. {
  14.     //在非本App界面时收到本地消息,下拉消息会有快捷回复的按钮,点击按钮后调用的方法,根据identifier来判断点击的哪个按钮,notification为消息内容  
  15.     NSLog(@"%@----%@",identifier,notification);
  16.     completionHandler();//处理完消息,最后一定要调用这个代码块  
  17. }
  18. //远程推送通知  
  19. -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
  20. {
  21.     //向APNS注册成功,收到返回的deviceToken  
  22. }
  23. -(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
  24. {
  25.     //向APNS注册失败,返回错误信息error  
  26. }
  27. -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
  28. {
  29.     //收到远程推送通知消息  
  30. }
  31. -(void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler
  32. {
  33.     //在没有启动本App时,收到服务器推送消息,下拉消息会有快捷回复的按钮,点击按钮后调用的方法,根据identifier来判断点击的哪个按钮  
  34. }

接下来我就带着大家去使用iOS 10的新特性之:

第一步:建立立监听target

我们需要新建立一个target,File->new->target 选择NotificationServiceExtension这个扩展。

如图:

IOS10通知新特性:可以带附件缩略图,体验更好

接下来我们会得到一个继承于UNNotificationServiceExtension的服务拓展。

这个服务拓展target很特殊,相当于是主target的一个子APP,但是没有界面,唯一的作用是IOS 10新特性通知到达用户手机会被这个target捕捉,我们提前预处理后即可显示给用户,显示给用户是我们修改后的通知,理论上是任何字段都可以提前修改,在这里我们只是下载附件图片,而对标题,副标题不处理。

有人会问:那么如何NotificationServiceExtension捕捉APNS推送呢?

第二部:让服务端修改通知数据结构字段

且看如下apns推送数据结构,我们发现多了一个"mutable-content":"1"  这个标记字段,是的,这个字段就是使用附件类型必须要增加的一个字段。有了这个字段,我们的target就能事先拦截到服务端给我们推送的通知结构。

  1.  { "aps": {
  2.          "alert":{"badge":"1","title":"报警标题","body":"你家来贼了!","category":"myCategory","sound":"default","type":"16"},
  3.          "mutable-content":"1" 
  4.          },
  5.      "myCustomData":{
  6.          "ctime":"1473679115",
  7.          "subType":"1",
  8.          "toTab":"live",
  9.          "type":"16",
  10.          "media-Type":"image",
  11.          "mediaUrl":"http://www.shumobaijia.com/"
  12.          }
  13. }

大家只需要关注:"mutable-content":"1"  , "media-Type":"image", "mediaUrl"三个字段即可,其他字段是我自己的app业务逻辑需要的。media-Type可以自己随便定义名字,我是为了以后拓展媒体类型使用的。同时我们必须携带附件URL地址,我们的目的就是使用附件,可以是一张图片,可以是一个声音或者视频文件,不过不能太大,太大会导致我们来不及下载完。

第三:拦截后获取URL字段

在我们新加的Extension中didReceiveNotificationRequest监听方法下开始如下代码逻辑:

  1. - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
  2.     self.contentHandler = contentHandler;
  3.     self.bestAttemptContent = [request.content mutableCopy];
  4.     // Modify the notification content here...
  5.     self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [has changed]", self.bestAttemptContent.title];
  6.     // 附件
  7.     NSDictionary *dict =  self.bestAttemptContent.userInfo;
  8.     NSDictionary *notiDict = dict[@"myCustomData"];
  9.     NSString *imgUrl = [NSString stringWithFormat:@"%@",notiDict[@"mediaUrl"]];
  10.     if (!imgUrl.length) {
  11.         self.contentHandler(self.bestAttemptContent);
  12.     }
  13.     [self loadAttachmentForUrlString:imgUrl withType:@"image" completionHandle:^(UNNotificationAttachment *attach) {
  14.         if (attach) {
  15.             self.bestAttemptContent.attachments = [NSArray arrayWithObject:attach];
  16.         }
  17.         self.contentHandler(self.bestAttemptContent);
  18.     }];
  19. }

使用到的下载方法:loadAttachmentForUrlString

注意:如果你的app需要和子target进行数据交互,需要去苹果开发平台,在开发证书app IDS中打开App group功能,之后就可以通过一个共享的存储区域实现数据传递。比如,本例中:我在主app用户登陆后,把Cookie等信息存储为Library/Caches/myTextPushCookie ,然后在通知target中去获取,这样就可以拿到登录cookie,有人问:为什么需要登录cookie?原因是:我们自己的app可以不用,因为我们下载的附件是随便的一个图片,但是如果你的附件图片是用户私有的,那怎么办?为了安全,需要登录验证才可以拉取该用户的图片信息。

  1. - (void)loadAttachmentForUrlString:(NSString *)urlStr  withType:(NSString *)type   completionHandle:(void(^)(UNNotificationAttachment *attach))completionHandler{
  2.     __block UNNotificationAttachment *attachment = nil;
  3.     NSURL *attachmentURL = [NSURL URLWithString:urlStr];
  4.     NSString *fileExt = [self fileExtensionForMediaType:type];
  5.     NSError *err = nil;
  6.     NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.myText.app"];
  7.     containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/myTextPushCookie"];
  8.     NSString *resultCookie = [NSString stringWithContentsOfURL:containerURL encoding:NSUTF8StringEncoding error:&err];
  9.     NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
  10.     sessionConfiguration.HTTPAdditionalHeaders = @{
  11.                                                    @"Cookie": resultCookie,
  12.                                                    @"HTTPMethod"  : @"GET"
  13.                                                    };
  14.     NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
  15.     [[session downloadTaskWithURL:attachmentURL
  16.                 completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
  17.                     if (error != nil) {
  18.                         NSLog(@"%@", error.localizedDescription);
  19.                     } else {
  20.                         NSFileManager *fileManager = [NSFileManager defaultManager];
  21.                         NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:fileExt]];
  22.                         [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error];
  23.                         NSError *attachmentError = nil;
  24.                         attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:localURL options:nil error:&attachmentError];
  25.                         if (attachmentError) {
  26.                             NSLog(@"%@", attachmentError.localizedDescription);
  27.                         }
  28.                     }
  29.                     completionHandler(attachment);
  30.                 }] resume];
  31. }
  32. - (NSString *)fileExtensionForMediaType:(NSString *)type {
  33.     NSString *ext = type;
  34.     if ([type isEqualToString:@"image"]) {
  35.         ext = @"jpg";
  36.     }
  37.     if ([type isEqualToString:@"video"]) {
  38.         ext = @"mp4";
  39.     }
  40.     if ([type isEqualToString:@"audio"]) {
  41.         ext = @"mp3";
  42.     }
  43.     return [@"." stringByAppendingString:ext];
  44. }

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: