iOS【NotificationContent】

=======================================================
如需通知项目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模板

iOS【NotificationContent】_第1张图片
截屏2020-12-19 下午4.23.58.png
2、创建对应的id、开发证书、发布证书
iOS【NotificationContent】_第2张图片
截屏2020-12-18 下午8.05.53.png
iOS【NotificationContent】_第3张图片
截屏2020-12-18 下午8.06.18.png
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请求。

iOS【NotificationContent】_第4张图片
截屏2020-12-19 下午5.26.27.png
iOS【NotificationContent】_第5张图片
截屏2020-12-19 下午5.30.51.png

调试推送,没有走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:
使用时须指定使用文件附件的内容,并且文件格式必须是支持的类型之一。
创建后,将其分配给内容对象的附件属性。
附件通知支持的类型如下图:

iOS【NotificationContent】_第6张图片
QQ20160918-3.png-45.5kB

UNNotificationAttachmentOptionsThumbnailHiddenKey,是一个BOOL值,为YES时候,缩略图将隐藏,默认为YES;
UNNotificationAttachmentOptionsThumbnailClippingRectKey剪贴矩形的缩略图;
UNNotificationAttachmentOptionsThumbnailTimeKey,一般影片附件会用到,指的是用影片中的某一秒来做这个缩略图;

你可能感兴趣的:(iOS【NotificationContent】)