iOS 通知扩展插件

  • Notification Content Extension

    • 通知内容扩展,是在展示通知时展示一个自定义的用户界面。
  • Notification Service Extension

    • 通知服务扩展,是在收到通知后,展示通知前,做一些事情的。比如,增加附件,网络请求等。

Notification Service Extension

  • 目前只找到aps推送支持
  • 主要是处理一下附件相关的下载

新建一个target

  • 老的xcode版本开启VoIP功能也是在 Background Modes 中直接勾选就开启了,但是新版的xcode移除了这个选项,所以只能在 info.plist 文件中去手动添加
  • 参考1
  • 参考2

代码实现

@interface NotificationService : UNNotificationServiceExtension

@end

#import "NotificationService.h"
#import <UIKit/UIKit.h> @interface NotificationService () @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent; @end @implementation NotificationService
// 系统接到通知后,有最多30秒在这里重写通知内容(在此方法可进行一些网络请求,如上报是否收到通知等操作)
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
NSLog(@"%s",__FUNCTION__);
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy]; // Modify the notification content here...
NSLog(@"%@",request.content);
// 添加附件
//1. 下载
NSURL *url = [NSURL URLWithString:@"https://tva1.sinaimg.cn/large/008i3skNgy1gtir9lwnj0j61x40gsabl02.jpg"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (!error) {
//2. 保存数据
NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject
stringByAppendingPathComponent:@"download/image.jpg"];
UIImage *image = [UIImage imageWithData:data];
NSError *err = nil;
[UIImageJPEGRepresentation(image, 1) writeToFile:path options:NSAtomicWrite error:&err];
//3. 添加附件
UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"remote-atta1" URL:[NSURL fileURLWithPath:path] options:nil error:&err];
if (attachment) {
self.bestAttemptContent.attachments = @[attachment];
}
}else{
self.bestAttemptContent.title = @"标题";
self.bestAttemptContent.subtitle = @"子标题";
self.bestAttemptContent.body = @"body";
}
//4. 返回新的通知内容
self.contentHandler(self.bestAttemptContent);
}];
[task resume];
}
// 处理过程超时,则收到的通知直接展示出来
- (void)serviceExtensionTimeWillExpire {
NSLog(@"%s",__FUNCTION__);
self.contentHandler(self.bestAttemptContent);
} @end

注意事项

  • UNNotificationAttachment:attachment 支持

    • 音频 5M(kUTTypeWaveformAudio/kUTTypeMP3/kUTTypeMPEG4Audio/kUTTypeAudioInterchangeFileFormat)
    • 图片10M(kUTTypeJPEG/kUTTypeGIF/kUTTypePNG)
    • 视频50M(kUTTypeMPEG/kUTTypeMPEG2Video/kUTTypeMPEG4/kUTTypeAVIMovie)

UINotificationConentExtension

配置项目

  • 新建target,打开推送服务

配置info.plist

  • 配置info.plist,和Notification Service Extension进行关联

  • 找到这个 UNNotificationExtensionCategory,写到Notification Service Extension中,可以配置多个,对应多个界面
   self.bestAttemptContent.categoryIdentifier = @"myNotificationCategory";// 和NotificationConentExtension关联
self.contentHandler(self.bestAttemptContent);

自定义UI

  • 如果我们想要隐藏系统默认的内容页面,也就是下面的那部分,头是隐藏不了的;只需要在Info.plist里添加字段UNNotificationExtensionDefaultContentHidden,bool类型并设置其值为YES;

  • 可以直接修改stroryboard

  • 添加Action,可以添加基本的事件


#import "NotificationViewController.h"
#import <UserNotifications/UserNotifications.h>
#import <UserNotificationsUI/UserNotificationsUI.h> @interface NotificationViewController () <UNNotificationContentExtension,UIActionSheetDelegate> @property IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation NotificationViewController - (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%s",__FUNCTION__);
// 添加action
UNNotificationAction * likeAction; //喜欢
UNNotificationAction * ingnoreAction; //取消
UNTextInputNotificationAction * inputAction; //文本输入 likeAction = [UNNotificationAction actionWithIdentifier:@"action_like" title:@"点赞"
options:UNNotificationActionOptionForeground];
inputAction = [UNTextInputNotificationAction actionWithIdentifier:@"action_input"title:@"评论"
options:UNNotificationActionOptionForeground textInputButtonTitle:@"发送"textInputPlaceholder:@"说点什么"];
ingnoreAction = [UNNotificationAction actionWithIdentifier:@"action_cancel"title:@"忽略" options:UNNotificationActionOptionDestructive];
NSString *categoryWithIdentifier = @"myNotificationCategory";// 和info.plist中配置的id一样
UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:categoryWithIdentifier actions:@[likeAction,inputAction,ingnoreAction] intentIdentifiers:@[] options:UNNotificationCategoryOptionNone]; NSSet *sets = [NSSet setWithObjects:category,nil];
[[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:sets];
} - (void)didReceiveNotification:(UNNotification *)notification {
self.label.text = notification.request.content.body;
NSLog(@"didReceiveNotification:%@",notification.request.content);
for (UNNotificationAttachment * attachment in notification.request.content.attachments) {
NSLog(@"url:%@",attachment.URL);
// 显示图片
if([attachment.URL startAccessingSecurityScopedResource]){
NSData *data = [NSData dataWithContentsOfURL:attachment.URL];
self.imageView.image = [UIImage imageWithData:data];
[attachment.URL stopAccessingSecurityScopedResource];
} }
} - (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion {
NSLog(@"response:%@",response);
if ([response.actionIdentifier isEqualToString:@"action_like"]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion(UNNotificationContentExtensionResponseOptionDismiss);
});
} else if ([response.actionIdentifier isEqualToString:@"action_input"]) {
UNTextInputNotificationResponse *inputAction = (UNTextInputNotificationResponse*)response;
NSLog(@"输入内容:%@",inputAction.userText);
// TODO: 发送评论
completion(UNNotificationContentExtensionResponseOptionDismiss);
} else if ([response.actionIdentifier isEqualToString:@"action_cancel"]) {
completion(UNNotificationContentExtensionResponseOptionDismiss);
} else {
completion(UNNotificationContentExtensionResponseOptionDismiss);
}
completion(UNNotificationContentExtensionResponseOptionDoNotDismiss);
}
@end
  • info.plist

  • aps 格式
{
"aps":
{
"alert":
{
"title":"iOS10远程推送标题",
"subtitle" : "iOS10 远程推送副标题",
"body":"这是在iOS10以上版本的推送内容,并且携带来一个图片附件"
},
"badge":1,
"mutable-content":1,
"media":"image",
"image-url":"https://tva1.sinaimg.cn/large/008i3skNgy1gtmd6b4whhj60fq0g6tb502.jpg"
}
}

iOS 通知扩展插件的更多相关文章

  1. 使用 Swift 制作一个新闻通知中心插件(1)

    input[type="date"].form-control,.input-group-sm>input[type="date"].input-grou ...

  2. Swift 制作一个新闻通知中心插件1

    使用 Swift 制作一个新闻通知中心插件(1) 随着 iOS 8 的发布,苹果为开发者们开放了很多新的 API,而在这些开放的接口中 通知中心插件 无疑是最显眼的一个.通知中心就不用过多介绍了,相信 ...

  3. 使用 Swift 制作一个新闻通知中心插件(2)

    我们在第一部分的文章中详细讲解了创建一个通知中心插件的整体过程.我们成功的在通知中心里面显示了新闻列表.但是截止到目前,我们还不能从通知中心的列表中查看新闻的详细内容.在这次的教程中,我们就以上次的教 ...

  4. 100个精选zencart扩展插件

    100个精选zencart扩展插件 特别推荐 1. 数据库备份 2. 产品横向布局. 3. 邮件订阅Newsletter Subscribe. 4. google 翻译google_translate ...

  5. jupyter notebook设置主题背景,字体和扩展插件

    windows上安装Anaconda (IPython notebook) Anaconda是一个包与环境的管理器,一个Python发行版,以及一个超过1000多个开源包的集合.它是免费和易于安装的, ...

  6. 认识Chrome扩展插件

    1.前言 现如今的时代,绝大多数人都要跟浏览器打交道的,说到浏览器那肯定是Chrome浏览器一家独大,具体数据请看 知名流量监测机构 Statcounter 公布了 7 月份全球桌面浏览器市场份额,主 ...

  7. 提高工作效率的神器:基于前端表格实现Chrome Excel扩展插件

    Chrome插件,官方名称extensions(扩展程序):为了方便理解,以下都称为插件. 我们开发的插件需要在浏览器里面运行,打开浏览器,通过右上角的三个点(自定义及控制)-更多工具-拓展程序-打开 ...

  8. iOS通知的整理笔记

    iOS通知用于高耦合界面的传值确实方便快捷. 需要实现模态弹出的视图控制器上,有一个视图控制器可以导航.这必定要将这个视图控制器的导航视图控制器naVC.view添加到模态弹出的视图控制器presen ...

  9. BlazeMeter发布chrome扩展插件,支持JMeter脚本创建

    BlazeMeter发布chrome扩展插件,支持JMeter脚本创建http://www.automationqa.com/forum.php?mod=viewthread&tid=3898 ...

随机推荐

  1. linux base脚本编写-自动领取微信红包

    bash脚本编写 语法 变量 定义: your_name = "ABC" 使用: echo $your_name 只读变量 a = "123" readonly ...

  2. 【C++】STL算法

    STL算法 标签:c++ 目录 STL算法 一.不变序列算法 1.熟悉的min(), max() 2.找最值还自己动手么?不了不了 3.熟悉的find()和新学会的count() 二.变值算法 1.f ...

  3. 面试突击17:HashMap除了死循环还有什么问题?

    面试合集:https://gitee.com/mydb/interview 本篇的这个问题是一个开放性问题,HashMap 除了死循环之外,还有其他什么问题?总体来说 HashMap 的所有" ...

  4. jvm锁的四种状态 无锁状态 偏向锁状态 轻量级锁状态 重量级锁状态

    一:java多线程互斥,和java多线程引入偏向锁和轻量级锁的原因? --->synchronized是在jvm层面实现同步的一种机制.  jvm规范中可以看到synchronized在jvm里 ...

  5. javascript 获取<td>标签内的值。

    当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HTML DOM 模型被构造为对象的树. 通过可编程的对象模型,JavaScript 获得了足够的能力来 ...

  6. grpc基础讲解和golang实现grpc通信小案例

    grpc简介 gRPC由google开发,是一款语言中立.平台中立.开源的远程过程调用系统 gRPC客户端和服务端可以在多种环境中运行和交互,例如用java写一个服务端,可以用go语言写客户端调用 g ...

  7. gin框架中的会话控制

    Cookie介绍 Http协议是无状态的,服务器不能记录浏览器的访问状态,也就是说服务器不能判断请求的客户端是否已经登录 Cookie就是解决http协议无状态的方案之一 Cookie实际上就是服务器 ...

  8. Tomcat-部署web工程方式

    Tomcat(部署web工程) 第一种方法:只需要把web工程的目录拷贝到Tomcat的webapps目录下即可 1,在webapps目录下创建一个book工程, 2,或者把做的工程内容拷贝到weba ...

  9. 多线程-停止线程方式-Interrupt

    1 package multithread4; 2 /* 3 * 停止线程: 4 * 1,stop方法. 5 * 6 * 2,run方法结束. 7 * 8 * 怎么控制线程的任务结束呢? 9 * 任务 ...

  10. python08day

    内容回顾 数据类型的补充 str:pass tuple: (1)----->int count 计数 index 通过元组获取索引 list sort 排序从小到大 sort(reverse=T ...