=======================================================
如需通知项目B里拿到主项目A里的数据,可以使用共享
iOS【NotificationContent-App Group共享】
通知送达率检查
:通过NotificationContent 可以埋点数据,通知送达上报
=======================================================
App配置了通知服务扩展程序后,每个通知都会执行以下过程:
1、App收到通知。
2、系统创建扩展类的实例对象并在后台启动它。
3、你的扩展程序会执行内容编辑和/或下载某些内容操作。
4、如果你的扩展程序执行太长时间而不能完成它的工作,将会收到通知并被立即终止。
5、通知显示给用户。
NotificationContent:新建的通知项目就当一个新的项目,需要创建对应的id、开发证书、发布证书;
1、创建Service Extension
使用Xcode打开项目,选中File -> New -> Target...
,在出现的弹窗中选择Notification Service Extension模板
2、创建对应的id、开发证书、发布证书
3、使推送走NotificationService的处理:
服务端设置"mutable-content":1
,这样推送过来就会走NotificationService的处理逻辑
{
"aps":{
"alert":{
"title":"iOS 10 title",
"subtitle":"iOS 10 subtitle",
"body":"iOS 10 body"
},
"my-attachment":"http://img01.xxx.jpg",
"mutable-content":1,
"category":"myNotificationCategory1",
"sound":"default",
"badge":3
}
}
#import "NotificationService.h"
@interface NotificationService ()
@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
NSDictionary *userInfo = request.content.userInfo;
// 统计远程推送到达率
[self postDisplaydata:userInfo];
NSString *soundName = nil;
NSString *title = nil;
NSString *body = nil;
NSString *subtitle = nil;
NSString *imagePath = userInfo[@"image"];
NSDictionary *apsDic = userInfo[@"aps"];
if ([apsDic isKindOfClass:[NSDictionary class]]) {
soundName = apsDic[@"sound"];
NSDictionary *alertDic = apsDic[@"alert"];
if ([alertDic isKindOfClass:[NSDictionary class]]) {
title = alertDic[@"title"];
subtitle = alertDic[@"subtitle"];
body = alertDic[@"body"];
if (apsDic[@"image"]) {
imagePath = apsDic[@"image"];
}
}
}
if ([body isKindOfClass:[NSString class]] && body.length>0) {
self.bestAttemptContent.body = body;
}
if ([title isKindOfClass:[NSString class]] && title.length>0) {
self.bestAttemptContent.title = title;
}
if ([subtitle isKindOfClass:[NSString class]] && subtitle.length>0) {
self.bestAttemptContent.subtitle = subtitle;
}
//self.bestAttemptContent.launchImageName = @"startLaunchImage";
if ([soundName isKindOfClass:[NSString class]] && soundName.length>0) {
self.bestAttemptContent.sound = [UNNotificationSound soundNamed:soundName];
}
if (![imagePath isKindOfClass:[NSString class]] || imagePath.length==0) {
self.contentHandler(self.bestAttemptContent);
return;
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSURL *imageURL = [NSURL URLWithString:imagePath];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
NSString *userDocument = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [NSString stringWithFormat:@"%@/notifications.jpg", userDocument];
// 一定要先删除老的图片
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
[imageData writeToFile:path atomically:YES];
NSURL *url = [NSURL fileURLWithPath:path];
UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"attachment" URL:url options:nil error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
if (attachment) {
self.bestAttemptContent.attachments = @[attachment];
}
self.contentHandler(self.bestAttemptContent);
});
});
}
//下载超时,则通过下面的方法,改成展示原有系统样式。
- (void)serviceExtensionTimeWillExpire {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
self.contentHandler(self.bestAttemptContent);
}
- (void)postDisplaydata:(NSDictionary *)userInfo {
NSString *postUrl = @"http://abc.com";
NSDictionary *dict = @{@"key" : @"app_receive_push",
@"Token" : @"abcdexxxToken",
@"deviceType" : @"iOS",
@"af_push_id" : STLNotifyToString(@"pushId"),};
[STLNotificationRequestManager POST:postUrl parameters:dict];
}
@end
//封装请求类
@implementation STLNotificationRequestManager
/**
统计远程推送达到率
@param URL 统计地址
@param dic 上报数据
*/
+ (void)POST:(NSString *)URL parameters:(NSDictionary *)dic {
if (![dic isKindOfClass:[NSDictionary class]]) return;
if (![URL isKindOfClass:[NSString class]]) return;
//创建配置信息
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
//设置请求超时时间:7秒
configuration.timeoutIntervalForRequest = 7;
//创建会话
NSURLSession *session = [NSURLSession sessionWithConfiguration: configuration delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString: URL]];
//设置请求方式:POST
[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"content-Type"];
[request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Accept"];
NSDictionary *requestParams = [[NSDictionary alloc] initWithDictionary:dic];
STLLog(@"GGGGG request params: %@",requestParams);
//data的字典形式转化为data
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:requestParams options:NSJSONWritingPrettyPrinted error:nil];
//设置请求体
[request setHTTPBody:jsonData];
NSURLSessionDataTask * dataTask =[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
STLLog(@"GGGGGURL:---%@",URL);
if (error == nil) {
NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
STLLog(@"GGGGGGGREQ success:%@ 11",responseObject);
}else{
STLLog(@"GGGGGGGREQ error:%@",error);
}
}];
[dataTask resume];
}
本地测试
- (void)testNotificationContent {
// 1.创建通知内容
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = @"occc通知";
content.subtitle = @"occc subtitle";
content.body = @"occc body";
content.badge = @1;
NSError *error = nil;
NSString *path = [[NSBundle mainBundle] pathForResource:@"logoTitle60@2x" ofType:@"png"];
// 2.设置通知附件内容
UNNotificationAttachment *att = [UNNotificationAttachment attachmentWithIdentifier:@"att1" URL:[NSURL fileURLWithPath:path] options:nil error:&error];
if (error) {
NSLog(@"attachment error %@", error);
}
content.attachments = @[att];
content.launchImageName = @"logoTitleShow@2x";
// 2.设置声音
UNNotificationSound *sound = [UNNotificationSound defaultSound];
content.sound = sound;
// 3.触发模式
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5 repeats:NO];
// 4.设置UNNotificationRequest
NSString *requestIdentifer = @"TestRequest";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:requestIdentifer content:content trigger:trigger];
//5.把通知加到UNUserNotificationCenter, 到指定触发点会被触发
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
}];
}
DEBUG 调试
target选择自己创建的NotificationServiceExtension,
点击运行,发送推送,推送消息收到了,
"mutable-content": 1,也有放到推送消息里,如果还是没有走断点,
选择点击Attach to Process by PID or Name..
如果是http请求,需要在plist里开启支持http请求。
调试推送,没有走didReceiveNotificationRequest的几个可能的原因:
1、调试时,target选择不对(停止运行按钮旁边那个)
2、推送的数据没有带上"mutable-content": 1
3、推送的target设置的系统版本要求高于真机系统。
消息字段说明
// 1.附件数组,存放UNNotificationAttachment类
@property (NS_NONATOMIC_IOSONLY, copy) NSArray*attachments ; // 2.应用程序角标,0或者不传,意味着角标消失
@property (NS_NONATOMIC_IOSONLY, copy, nullable) NSNumber *badge;// 3.主体内容
@property (NS_NONATOMIC_IOSONLY, copy) NSString *body ;// 4.app通知下拉预览时候展示的图
@property (NS_NONATOMIC_IOSONLY, copy) NSString *launchImageName;// 5.UNNotificationSound类,可以设置默认声音,或者指定名称的声音
@property (NS_NONATOMIC_IOSONLY, copy, nullable) UNNotificationSound *sound ;// 6.推送内容的子标题
@property (NS_NONATOMIC_IOSONLY, copy) NSString *subtitle ;// 7.通知线程的标识
@property (NS_NONATOMIC_IOSONLY, copy) NSString *threadIdentifier;// 8.推送内容的标题
@property (NS_NONATOMIC_IOSONLY, copy) NSString *title ;// 9.远程通知推送内容
@property (NS_NONATOMIC_IOSONLY, copy) NSDictionary *userInfo;// 10.category标识
@property (NS_NONATOMIC_IOSONLY, copy) NSString *categoryIdentifier;
UNTimeIntervalNotificationTrigger (通知触发模式)
UNTimeIntervalNotificationTrigger *triggerOne = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5 repeats:NO];
NSDateComponents *components = [[NSDateComponents alloc] init];
// 注意,weekday是从周日开始的,
// 周一早上 7:00 上班
components.weekday = 2;
components.hour = 7;
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger >triggerWithDateMatchingComponents:components repeats:YES];
UNLocationNotificationTrigger (本地通知)
地理位置的一种通知,使用这个通知,你需要导入
import这个系统类库。
1、如果用户进入或者走出某个区域会调用下面两个方法
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region代理方法反馈相关信息
2、一到某个经纬度就通知,判断包含某一点么
// 不建议使用!!!!!!CLRegion *region = [[CLRegion alloc] init];// 不建议使用!!!!!!
CLCircularRegion *circlarRegin = [[CLCircularRegion alloc] init];
[circlarRegin containsCoordinate:(CLLocationCoordinate2D)];
UNLocationNotificationTrigger *trigger4 = [UNLocationNotificationTrigger triggerWithRegion:circlarRegin repeats:NO];
UNNotificationAttachment (附件内容通知)
在UNNotificationContent类中,有个附件数组的属性,
这就是包含UNNotificationAttachment类的数组了。
UNNotificationAttachment(附件通知)
是指可以包含音频,图像或视频内容,并且可以将其内容显示出来的通知。
使用本地通知时可以在通知创建时,将附件加入即可。
对于远程通知则必须实现使用UNNotificationServiceExtension类通知服务扩展。
创建附件的方法是attachmentWithIdentifier:URL:options:error:。
使用时须指定使用文件附件的内容,并且文件格式必须是支持的类型之一。
创建后,将其分配给内容对象的附件属性。
附件通知支持的类型如下图:
UNNotificationAttachmentOptionsThumbnailHiddenKey,是一个BOOL值,为YES时候,缩略图将隐藏,默认为YES;
UNNotificationAttachmentOptionsThumbnailClippingRectKey剪贴矩形的缩略图;
UNNotificationAttachmentOptionsThumbnailTimeKey,一般影片附件会用到,指的是用影片中的某一秒来做这个缩略图;