iOS10富文本推送通知 | 大专栏
Table of Contents
1. Xcode推送开关
2. APNs推送格式定义
2.1. 普通推送的格式
2.2. iOS10富文本推送扩展字段
3. 推送消息处理
3.3.1. 暂存处理资源
3.3.2. 解析图片地址
3.3.3. 下载图片
3.3.4. 缓存图片内容
3.3.5. Attachment封装
3.3.6. 图片推送样式
3.3.7. Service Time Expire的回调处理
3.1. 新建一个Notification Service Extension
3.2. bundle identifier命名
3.3. NotificationService类
4. 推送消息界面
4.1. 新建Notification Content Extention
4.2. 自定义界面
4.3. 自定义界面对应的类
4.4. category设置
4.5. 最终效果
4.6. 其他需要注意的点
5. 参考资料
苹果在iOS10系统时推出了UNNotification用户消息framework,这个framework相比以往的Remote Notification和Local Notification,增加了不少功能。
列出iOS10 Notification的新功能。
这篇文章我们讨论的是新增的Rich Notification部分。
1 Xcode推送开关
App远程推送开关:
如果你的App要使用推送功能,首先需要打开App的远程推送开关。打开推送的后台模式:
iOS7开始,苹果提供了后台接收远程消息的功能,进程在后台存活时也能接收到消息- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler NS_AVAILABLE_IOS(7_0);
2 APNs推送格式定义
2.1 普通推送的格式
以下是一个普通的APNs推送消息收到后的消息体,包含了title, body, sound, badge等基本的消息元素。
{"aps": {"alert": {"title": "Wanda Wealth Big Gift!","body": "Wanda Wealth will give you 100,000 bonus if you participate our Moon Lover's Activity!"},"sound": "default","badge": 10 } }
2.2 iOS10富文本推送扩展字段
富文本推送本质上是允许App改变推送消息的UI样式,所以需要在aps消息体里加入字段mutable-content。
category字段表示该条消息属于哪个类别,将会由相对象的Notification Service来做相应的处理,iOS10后允许开发者建立多个Notification Service来处理相应APNs消息体。
attachment-image是我们自定义的字段,表示该条推送附带的图片URL地址。你也可以根据自己业务逻辑自定义字段语义,比如可以定义attach-url, attach-type,这样可以区别是附带的图片还是视频。
{"aps": {// alert, sound, badge, ...// ......"mutable-content": 1,"category": "push-message-category", }"attachment-image": "https://caifu.xinshengdaxue.com/assets/logo.png"}
3 推送消息处理
推送消息收到后,我们需要先下载attachment-image,保存在缓存中。苹果提供了Notification Service Extension的消息推送服务扩展,开发者可以在这里拿到消息体,解析得到attachment-image自定义字段后作下载缓存处理。
3.1 新建一个Notification Service Extension
下图展示了新建的过程,在Xcode里点击File->New->Target->Notficiation Service Extension
3.2 bundle identifier命名
在命名BundleID的时候需要注意的是,其前缀最好包含App Target的bundleID。
3.3 NotificationService类
当新建好Extension后,Xcode为我们新建了NotificationService类,它继承了UNNotificationServiceExtension框架类。
该类有两个回调方法,第一个是接收到推送消息后的回调,用于下载富文本内容。
serviceExtensionTimeWillExpire提醒App,Extension将要结束,我们可以在这里做一些暂停下载,标记标志位等工作,以等下次App重新唤醒的时候在UIApplicationDelegate的回调中继续下载。
@interface UNNotificationServiceExtension : NSObject// Call contentHandler with the modified notification content to deliver. If the handler is not called before the service's time expires then the unmodified notification will be delivered.// You are expected to override this method to implement push notification modification.- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent *contentToDeliver))contentHandler;// Will be called just before this extension is terminated by the system. You may choose whether to override this method.- (void)serviceExtensionTimeWillExpire;@end
3.3.1 暂存处理资源
didReceiveRemoteNotification回调提供了contentHandler回调block,调用后系统会知道这条消息是否已被处理。由于图片、文件或视频的下载可能是异步下载,所以需要暂存这些处理资源。
self.contentHandler = contentHandler;self.bestAttemptContent = [request.content mutableCopy];
3.3.2 解析图片地址
我们先要从UNNotficationRequest参数中解析到attachment-image内容
NSString *attachUrl = [request.content.userInfo objectForKey:@"attachment-image"];
3.3.3 下载图片
以下的代码使用的是同步下载方案,仅为Demo代码,后续上生产环境需要使用异步代码完成。
- (UIImage *)getImageFromUrl:(NSString *)url { NSLog(@"NotificationService, getImageFromUrl: %@", url);UIImage *result;NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]]; result = [UIImage imageWithData:data];return result; }
3.3.4 缓存图片内容
下载好图片后,需要缓存图片内容。其中uuidStr是缓存图片名,saveImage将UIImage存储到Document目录下(其实应当存在Cache)目录下。
NSString *uuidStr = @"2B3CB2BD-1626-4192-A72A-0FA3B1A02279";NSString *localPath = [self saveImage:image withFileName:uuidStr ofType:@"png" inDirectionary:docPath];if (localPath.length > 0) {NSURL *localPathUrl = [NSURL URLWithString:[@"file://" stringByAppendingString:localPath]]; }
3.3.5 Attachment封装
图片下载后,就可以封装成UNNotificationAttachment供系统回调调用。
UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:kPushNotificationImageAttachment URL:localPathUrl options:nil error:nil];if (attachment) {self.bestAttemptContent.attachments = @[attachment]; }self.contentHandler(self.bestAttemptContent);
3.3.6 图片推送样式
经过上面几步操作,我们最终在系统消息中心显示了带图片的推送样式。
3.3.7 Service Time Expire的回调处理
以下代码简单地处理了Time Expire回调,简单地将bestAttemptContent回调给系统。在这里可能图片并没有下载完全,所以bestAttempContent仅仅是文字的显示。
- (void)serviceExtensionTimeWillExpire {self.contentHandler(self.bestAttemptContent); }
4 推送消息界面
iOS10的Notification Content Extension为开发者提供了自定义force touch推送消息后展开的UI界面的能力。我们可以展示文字、图片、视频,以及Notification Action,如消息回复、订阅、稍后阅读等。
4.1 新建Notification Content Extention
下图展示了新建的过程,在Xcode里点击File->New->Target->Notficiation Content Extension
4.2 自定义界面
Extension创建后,其Info.plist里指定了NSExtensionMainStoryboard字段,表示自定义界面使用相应名字的storyboard;下图是一个定制化的界面,显示一张正方形的图片:
4.3 自定义界面对应的类
上面的storyboard对应的类是NotificationViewController,我们在它的didReceiveNotification:的回调函数中渲染界面。
UNNotification其实就是上面的Notification Service下载图片后封装成Attachment后塞回给系统,系统再封装成一个UNNotification,传给NotificationViewController。开发者只需要从UNNotification中取出Attachment中的图片地址,生成UIImage后显示即可。
- (void)didReceiveNotification:(UNNotification *)notification { NSLog(@"NotificationViewController, didReceiveNotification: %@", notification.description);UNNotificationContent *content = notification.request.content;UNNotificationAttachment *attachment = content.attachments.firstObject;if (attachment.URL.startAccessingSecurityScopedResource) {self.imageView.image = [UIImage imageWithContentsOfFile:attachment.URL.path]; } }
4.4 category设置
Notification Service负责下载,Notification Content负责展示。category的作用是分发不同的推送消息给相应的Notification Content。
category需要在Info.plist中进行配置,设置UNNotificationExtensionCategory的值为上面提到过的aps中的相应值,push-message-category。
4.5 最终效果
我们使用了李笑来老师 财富自由之路 网站的favicon,也是他的头像。下图就是消息force touch后展示的样子。
你可以根据自己App的设计来重新布局你的消息展示形式。
4.6 其他需要注意的点
我们在这里仅仅是给出了富文本消息最简单的示例,有一些point可能需要你自己去查询研究。
自定义Notification Content的时候,你可以不使用Storyboard,直接使用代码进行布局。需要修改Info.plist中的内容
Storyboard中我们没有显示消息体,而force touch后,我们看到了消息体。需要研究一下保留展示原消息体的配置项
以上代码使用了同步下载图片的策略,可以改成异步下载策略
5 参考资料
How to send iOS 10 Notifications using the Push Notifications API
这篇里面基本上是要集成第三方推送框架pusher这家的push SDK才能做,也就是说代码是调用他们的,所以并没有提供url解析下载的步骤,仅供开发参。iOS 10 Rich Push Notification Example Projects
这个是CleverTap第三方推送平台,里面有他们的Demo工程,其实并没有提供如何实现Rich Notification的技术细节。所以仅做参考,demo代码不全。iOS 10消息推送(UserNotifications)秘籍总结(二)
这篇文章是最靠谱的,所以根据这篇的内容,我们开发了带图片显示的Rich Notification,大家看完这篇文章,同样可以看看这篇里讲到的更多的内容。