iOS10远程推送自定义通知---消息包含图片视频处理(全)

不说废话,直接正题
这里做消息的自定义通知页面,我会把一些需要注意的都写出来。
1.通知创建、注册以及授权。
注意:(1)包含头文件

#ifdef NSFoundationVersionNumber_iOS_9_x_Max
//iOS10通知新框架
#import <UserNotifications/UserNotifications.h>
//iOS10 自定义通知界面
#import <UserNotificationsUI/UserNotificationsUI.h>
#endif

(2).Link Binary With Libraries包含相应的framework包


屏幕快照 2018-10-12 下午2.28.00.png

下面是Appdelegate的部分代码,包含了通知的代理方法和通知互动页面的代理方法

    /* -------------自定义通知------------- */
    //申请授权
    //1.创建通知中心
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    //设置通知中心的代理(iOS10之后监听通知的接收时间和交互按钮的响应是通过代理来完成的)
    center.delegate = self;
    //2.通知中心设置分类
    [center setNotificationCategories:[NSSet setWithObjects:[self createCatrgory], nil]];
    //3.请求授权
    /**UNAuthorizationOption
     UNAuthorizationOptionBadge   = (1 << 0),红色圆圈
     UNAuthorizationOptionSound   = (1 << 1),声音
     UNAuthorizationOptionAlert   = (1 << 2),内容
     UNAuthorizationOptionCarPlay = (1 << 3),车载通知     */
    [center requestAuthorizationWithOptions:UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted == YES) {
            NSLog(@"授权成功");
        }
    }];
//当APP处于前台的时候接收到通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    //此处省略十万行代码
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler {
    //收到推送的请求
    UNNotificationRequest *request = response.notification.request;
    //收到推送的内容
    UNNotificationContent *content = request.content;
    //收到用户的基本信息
    NSDictionary *userInfo = content.userInfo;
    //收到推送消息的角标
    NSNumber *badge = content.badge;
    //收到推送消息body
    NSString *body = content.body;
    //推送消息的声音
    UNNotificationSound *sound = content.sound;
    // 推送消息的副标题
    NSString *subtitle = content.subtitle;
    // 推送消息的标题
    NSString *title = content.title;
    if ([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        NSLog(@"iOS10 收到远程通知:%@",userInfo);
        //此处省略一万行需求代码。。。。。。
        NSString *msaage = @"";
        if ([response.actionIdentifier isEqualToString:@"textInputAction"]) {
            msaage = ((UNTextInputNotificationResponse *)response).userText;
            NSLog(@"input:%@", content);
        } else if ([response.actionIdentifier isEqualToString:@"getItforeGround"]) {
            NSLog(@"收到");
            msaage = @"收到";
        } else if ([response.actionIdentifier isEqualToString:@"kownDestructive"]) {
            NSLog(@"我现在不方便,等下再回复你");
            msaage = @"我现在不方便,等下再回复你";
        }
        NSString *msgType = userInfo[@"type"];
        NSString *msgTo   = userInfo[@"id"];
        // 发送消息
        [self sendMessageWith:msaage msgType:msgType msgTo:msgTo];
    } else {
        // 判断为本地通知
        //此处省略一万行需求代码。。。。。。
        NSLog(@"iOS10 收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
    }
    completionHandler();
}
#pragma mark - 创建通知分类(交互按钮)
- (UNNotificationCategory *)createCatrgory {
    //文本交互(iOS10之后支持对通知的文本交互)
    /**options
     UNNotificationActionOptionAuthenticationRequired  用于文本
     UNNotificationActionOptionForeground  前台模式,进入APP
     UNNotificationActionOptionDestructive  销毁模式,不进入APP     */
    UNTextInputNotificationAction *textInputAction = [UNTextInputNotificationAction actionWithIdentifier:@"textInputAction" title:@"点击输入回复消息" options:UNNotificationActionOptionAuthenticationRequired textInputButtonTitle:@"发送" textInputPlaceholder:@"还有多少话要说……"];
    //不打开应用按钮   快捷回复
    UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"getItforeGround" title:@"收到" options:UNNotificationActionOptionDestructive];
    UNNotificationAction *action2 = [UNNotificationAction actionWithIdentifier:@"kownDestructive" title:@"我现在不方便,等下再回复你" options:UNNotificationActionOptionDestructive];
    //创建分类
    /**
     Identifier:分类的标识符,通知可以添加不同类型的分类交互按钮
     actions:交互按钮
     intentIdentifiers:分类内部标识符  没什么用 一般为空就行
     options:通知的参数
     UNNotificationCategoryOptionCustomDismissAction:自定义交互按钮
     UNNotificationCategoryOptionAllowInCarPlay:车载交互
     */
    UNNotificationCategory *category = [UNNotificationCategory
                                        categoryWithIdentifier:@"myMessageNotificationCategory"
                                        actions:@[textInputAction,action1,action2]
                                        intentIdentifiers:@[]
                                        options:UNNotificationCategoryOptionCustomDismissAction];
    return category;
}

2.创建target Notification Content Extension,步骤如下如


屏幕快照 2018-10-12 上午10.21.39.png
屏幕快照 2018-10-12 上午10.23.14.png

创建UI……此处略
然后就是通过didReceiveNotification对空间赋值
注意:此处需要注意的是图片、视频或者音频文件获取的时候一定要开启文件安全访问权限[attachment.URL startAccessingSecurityScopedResource],我因为没开启这个一直没权限打开,差点人给奔溃了:一直没有权限打开,还有当时不知道怎么打断点调试。

- (void)didReceiveNotification:(UNNotification *)notification {
    if (notification.request.content.attachments.count > 0) {
        NSDictionary *userInfo = notification.request.content.userInfo;
        NSString *fileType = userInfo[@"media"][@"type"];
        UNNotificationAttachment *attachment = (UNNotificationAttachment *)notification.request.content.attachments.firstObject;
//        self.label.text = [NSString stringWithFormat:@"%@", attachment.URL];
        if ([fileType isEqualToString:@"image"]) {
            //如果动态加载图片可以通过UNNotificationAttachment获取
            self.playerImageView.hidden = YES;
            if ([attachment.URL startAccessingSecurityScopedResource]) {//获取文件安全访问权限
                NSData *imageData = [NSData dataWithContentsOfURL:attachment.URL];
                UIImage *image = [UIImage imageWithData:imageData];
                if (image.size.width <= self.view.frame.size.width - 20) {
                    _imgConstraintW.constant = image.size.width;
                    _imgConstraintH.constant = image.size.height;
                } else {
                    _imgConstraintW.constant = self.view.frame.size.width - 20;
                    _imgConstraintH.constant = (self.view.frame.size.width - 20) * image.size.height/image.size.width;
                }
                [self.imgView setImage:image];
                [attachment.URL stopAccessingSecurityScopedResource];//结束文件安全访问
            }
        } else if ([fileType isEqualToString:@"video"]) {
            if ([attachment.URL startAccessingSecurityScopedResource]) {
                _playerImageViewH.constant = 40;
                _playerImageView.image = [UIImage imageNamed:@"theme1_discover_icon_videoplaybig"];
                NSURL *url = attachment.URL;
                UIImage *image = [self firstFrameWithVideoURL:url size:CGSizeMake(self.view.frame.size.width, self.view.frame.size.width/2)];
                if (image.size.width <= self.view.frame.size.width - 20) {
                    _imgConstraintW.constant = image.size.width;
                    _imgConstraintH.constant = image.size.height;
                } else {
                    _imgConstraintW.constant = self.view.frame.size.width - 20;
                    _imgConstraintH.constant = (self.view.frame.size.width - 20) * image.size.height/image.size.width;
                }
                [self.imgView setImage:image];
//                _imgConstraintH.constant = self.view.frame.size.width/2;
                AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:url];
                self.myPlayer = [[AVPlayer alloc] initWithPlayerItem:item];
                self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.myPlayer];
                self.playerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, image.size.height+20);
                self.playerLayer.backgroundColor = [UIColor grayColor].CGColor;
                //设置播放窗口和当前视图之间的比例显示内容
                self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
                [self.view.layer addSublayer:self.playerLayer];
                self.myPlayer.volume = 1.0f;
                [self.myPlayer play];
                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.myPlayer.currentItem];
                
                [attachment.URL stopAccessingSecurityScopedResource];
            }
        }
    } else {
        _imgConstraintH.constant = 0;
        _playerImageView.hidden = YES;
    }
}

- (void)playbackFinished:(NSNotification *)notifi {
    NSLog(@"播放完成");
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    self.myPlayer = nil;
    [self.playerLayer removeFromSuperlayer];
    self.playerLayer = nil;
}

#pragma mark ---- 获取图片第一帧
- (UIImage *)firstFrameWithVideoURL:(NSURL *)url size:(CGSize)size
{
    // 获取视频第一帧
    NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
    AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:url options:opts];
    AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:urlAsset];
    generator.appliesPreferredTrackTransform = YES;
    generator.maximumSize = CGSizeMake(size.width, size.height);
    NSError *error = nil;
    CGImageRef img = [generator copyCGImageAtTime:CMTimeMake(0, 10) actualTime:NULL error:&error];
//    self.label.text = [NSString stringWithFormat:@"**%@  **%@", url, error];
    if (img) {
        return [UIImage imageWithCGImage:img];
    }
    return nil;
}

如果只有文字,以上就可以结束了。最后需要注意的是UNNotificationExtensionCategory要和你创建通知的时候id一致,同时也要和APS中的id一致。
UNNotificationExtensionDefaultContentHidden这个是是否显示系统给的的通知页面


屏幕快照 2018-10-12 上午10.16.08.png

3.推送了图片、视频、音频文件需要打开的接着往下。由于这些都涉及到下载文件,所以我们需要一个创建target Notification Service Extension来拦截推送下载文件,创建如图


屏幕快照 2018-10-12 上午10.25.23.png

注意:如果资源路径是http的,通知不会进Notification Service,这时候需要暂时返回http协议。则需要在info.plist添加App Transport Security Settings字典,在其中添加Allow Arbitrary Loads bool类型为YES


屏幕快照 2018-12-22 上午8.46.46.png

下面就是拦截后下载文件并打包的代码:

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    // 下载并关联附件
    NSString *urlString = self.bestAttemptContent.userInfo[@"media"][@"url"];
    
//    #warning 这里是添加视频播放按钮
//    NSString *fileType = self.bestAttemptContent.userInfo[@"media"][@"type"];
//    if ([fileType isEqualToString:@"video"]) {
//        
//    }
    
    [self loadAttachmentForUrlString:urlString
                   completionHandler: ^(UNNotificationAttachment *attachment) {
                       self.bestAttemptContent.attachments = [NSArray arrayWithObjects:attachment, nil];
                       [self contentComplete];
                   }];
}

- (void)serviceExtensionTimeWillExpire {
    //这里进行操作超时后的补救···例如将图片替换成默认图片等等
    self.bestAttemptContent.title = @"下载资源超时";
    [self contentComplete];
}

- (void)contentComplete {
    [self.session invalidateAndCancel];
    self.contentHandler(self.bestAttemptContent);
}

- (void)loadAttachmentForUrlString:(NSString *)urlString
                 completionHandler:(void (^)(UNNotificationAttachment *))completionHandler {
    __block UNNotificationAttachment *attachment = nil;
    __block NSURL *attachmentURL = [NSURL URLWithString:urlString];
    NSString *fileExt = [@"." stringByAppendingString:[urlString pathExtension]];
    
    //下载附件
    _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    NSURLSessionDownloadTask *task;
    task = [_session downloadTaskWithURL:attachmentURL
                       completionHandler: ^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
                           
                           if (error != nil) {
                               NSLog(@"%@", error.localizedDescription);
                           } else {
                               NSFileManager *fileManager = [NSFileManager defaultManager];
                               NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path
                                                                         stringByAppendingString:fileExt]];
                               NSLog(@"*****localURL:%@", localURL);
                               [fileManager moveItemAtURL:temporaryFileLocation
                                                    toURL:localURL
                                                    error:&error];
                               NSError *attachmentError = nil;
                               NSString * uuidString = [[NSUUID UUID] UUIDString];
                               //将附件信息进行打包
                               attachment = [UNNotificationAttachment
                                             attachmentWithIdentifier:uuidString
                                             URL:localURL
                                             options:nil
                                             error:&attachmentError];
                               if (attachmentError) {
                                   NSLog(@"%@", attachmentError.localizedDescription);
                               }
                           }
                           
                           completionHandler(attachment);
                       }];
    [task resume];
}

最后贴上aps

文字aps
{
    "aps":{
        "alert":{
            "body":"test: 我不知道你在想什么,还是那个地点那条街",
            "title":"外滩十八号"
        },
        "badge":1,
        "category":"myMessageNotificationCategory",
        "sound":"default"
    },
    "id":"test",
    "type":"chat"
}
图片aps
{
    "aps":{
        "alert":{
            "body":"test: 图片",
            "title":"外滩十八号"
        },
        "badge":1,
        "category":"myMessageNotificationCategory",
        "sound":"default",
        "mutable-content":"1"
    },
    "id":"test18",
    "type":"chat",
    "media":{
        "type":"image",
        "url":"https://www.fotor.com/images2/features/photo_effects/e_bw.jpg"
        }
}
视频aps
{
    "aps":{
        "alert":{
            "body":"test: 视频",
            "title":"外滩十八号"
        },
        "badge":1,
    "category":"myMessageNotificationCategory",
        "sound":"default",
        "mutable-content":"1"
    },
    "id":"test18",
    "type":"chat",
    "media":{
        "type":"video",
        "url":"http://olxnvuztq.bkt.clouddn.com/WeChatSight1.mp4"
        }
}

4.在Notification Content Extension中获取文件,然后进行相应处理,步骤2代码中有图片和视频的一些处理。
搞定收工。
自定义通知调试参考
https://github.com/liuyanhongwl/ios_common/blob/master/files/App-Extension-Tips.md
推送工具下载
https://github.com/KnuffApp/Knuff/releases

因为在公司的app上做的,所以就没有demo,来两张效果图

IMG_1173.PNG
IMG_1172.PNG
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容