iOS底层音视频开发iOS开发基础知识

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

2018-10-12  本文已影响78人  点点_星光

不说废话,直接正题
这里做消息的自定义通知页面,我会把一些需要注意的都写出来。
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

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

- (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
上一篇下一篇

猜你喜欢

热点阅读