ios10推送详解

作者: 消逝彼得 | 来源:发表于2016-09-12 11:24 被阅读1676次

    上个月接到一个需求,做ios10的推送,意图冲击AppStore头条.瞬间抓狂,工具都还没有,于是赶紧安装xcodeBeta版,ios10Beta版,然后就开始无尽的查资料,毕竟新功能,毕竟没做过........不过还好,在发布会之前赶出来了,由于本人比较懒,拖到现在才写出来,接下来就是见证奇迹的时刻!

    原理

    ios10 push1.jpg

    图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider。
    APNS 是Apple Push Notification Service(Apple Push服务器)的缩写,是苹果的服务器。

    上图可以分为三个阶段。

    第一阶段:.net应用程序把要发送的消息、目的iPhone的标识打包,发给APNS。
    第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPhone。
    第三阶段:iPhone把发来的消息传递给相应的应用程序, 并且按照设定弹出Push通知。

    ios10 push2.jpg

    从上图我们可以看到。

    1、首先是应用程序注册消息推送。

    2、 IOS跟APNS Server要deviceToken。应用程序接受deviceToken。

    3、应用程序将deviceToken发送给PUSH服务端程序。

    4、 服务端程序向APNS服务发送消息。

    5、APNS服务将消息发送给iPhone应用程序。

    xcode8以后测试环境证书就可以自动生成了,所以就不再多说.

    创建

    很久以前写过ios9的today extension,与其类似,同样需要创建一个target,


    D0B7D515-925E-4890-98EC-2150AC9C22E9.png

    如图,Notification Content负责自定义通知UI,Notification Service Extension负责接收并处理数据

    屏幕快照 2016-09-12 上午10.49.01.png

    正活

    ios的拓展类是不能独立联网请求数据的,但是之前做today的时候查过一些别的app,下拉通知栏的时候有些app可以抓到包,估计是单独做了一个网络请求的封装,只是瞎猜,如有雷同,纯属巧合.但是通知就不用那么麻烦了.首先从网上随便挑选一张图片(限定https协议):https://homeba.s3.amazonaws.com/__sized__/scene/2c0f3bdb7715fed7190fd87e5e5340e4-1473387950-crop-c0-5__0-5-590x442-85.jpg,推送格式和可以自选,详情可见:https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html.

    屏幕快照 2016-09-12 上午11.01.37.png

    上图是我用的格式,"aps"内部的内容ios会自动获取归类.
    alert是通知的文字内容,
    sound是通知声音,在这取默认,
    badge是否显示程序徽章,
    重点是mutable-content,这个字段决定了调用自定义通知界面,也就是Notification Content控制器
    category是和后台商量好的一个值,显示action,也就是通知下面的按钮,可以扩展一些操作而不必进入程序.
    "aps"外部就可以添加一些需要的字段,这就看具体需求了.
    推送工具方面的准备工作就已经完成了,下面开始代码干货.

      - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    NSString * attchUrl = [request.content.userInfo objectForKey:@"image"];
    //下载图片,放到本地
    UIImage * imageFromUrl = [self getImageFromURL:attchUrl];
    
    //获取documents目录
    NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * documentsDirectoryPath = [paths objectAtIndex:0];
    
    NSString * localPath = [self saveImage:imageFromUrl withFileName:@"MyImage" ofType:@"png" inDirectory:documentsDirectoryPath];
    if (localPath && ![localPath isEqualToString:@""]) {
        UNNotificationAttachment * attachment = [UNNotificationAttachment attachmentWithIdentifier:@"photo" URL:[NSURL URLWithString:[@"file://" stringByAppendingString:localPath]] options:nil error:nil];
        if (attachment) {
            self.bestAttemptContent.attachments = @[attachment];
        }
    }
    self.contentHandler(self.bestAttemptContent);
    

    }

    因为不能方便的使用SDImage框架,所以网络请求只能自己松手,丰衣足食,另外,ios10通知虽然可以加载图片,但是只能加载本地的图片,所以这里需要做一个处理,先把图片请求下来,再存到本地

      - (UIImage *) getImageFromURL:(NSString *)fileURL {
    NSLog(@"执行图片下载函数");
    UIImage * result;
    //dataWithContentsOfURL方法需要https连接
    NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileURL]];
    result = [UIImage imageWithData:data];
    
    return result;
    

    }

        //将所下载的图片保存到本地
    -(NSString *) saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
    NSString *urlStr = @"";
    if ([[extension lowercaseString] isEqualToString:@"png"])
    {
        urlStr = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"png"]];
        [UIImagePNGRepresentation(image) writeToFile:urlStr options:NSAtomicWrite error:nil];
    } else if ([[extension lowercaseString] isEqualToString:@"jpg"] ||
               [[extension lowercaseString] isEqualToString:@"jpeg"])
    {
        urlStr = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"jpg"]];
        [UIImageJPEGRepresentation(image, 1.0) writeToFile:urlStr options:NSAtomicWrite error:nil];
    } else
    {
        NSLog(@"extension error");
    }
    return urlStr;
    

    }

    然后数据方便就已经完成了,最后一步,自定义UI并获取图片.自带的storyboard还是很好用的.

    屏幕快照 2016-09-12 上午11.18.31.png

    做好约束就可以加图片啦!
    - (void)didReceiveNotification:(UNNotification *)notification {
    NSLog(@"嘿嘿");
    self.label.text = notification.request.content.body;
    UNNotificationContent * content = notification.request.content;
    UNNotificationAttachment * attachment = content.attachments.firstObject;
    if (attachment.URL.startAccessingSecurityScopedResource) {
    self.imageView.image = [UIImage imageWithContentsOfFile:attachment.URL.path];
    }
    }
    就是这么简单,大功告成!!!(松一大口气.....)

    来一个效果图,哈哈

    ![IMG_1456.PNG](http:https://img.haomeiwen.com/i1043176/a3407ef1b6c33d34.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    最后欢迎大家浏览我们的官方网站:https://homeba.in/

    相关文章

      网友评论

      • 消逝彼得:不好意思,忙瞎了,也没时间看简书,声音的话我一直用默认,抽空我试一下别的,也可以加我QQ互相交流
      • 范特西V:多谢这么详细的总结!根据你的几篇教程,做了iOS10的推送的适配,并用development模式测试,能正常获取到DeviceToken,也能正常收到推送信息。。就是指定了 'sound' => 'push.caf',在iOS9收到推送能播放自定义的声音,但是在iOS10里就不起作用了,仍然是播放系统推送声音,不知你在测试的时候,有无在iOS10里遇到这个问题?
      • 消逝彼得:你是说在NotificationViewController里面?viewDidLoad理论上只执行一次,所以获取本地图片需要在didReceiveNotification,但是只能获取本地图片,获取远程图片需要在NotificationService里面,然后把图片保存到本地才可以,所以有点搞不清你的意思
      • zero000:您好,我想问下,iOS10中,在viewDidLoad中,我通过图片链接下载一张图片到本地, 在按钮的点击事件中,创建本地通知(附带创建UNNotificationAttachment对象),第一次点击按钮本地通知正常(能携带图片);但是第二次点击按钮本地通知不携带图片,原因:UNNotificationAttachment创建失败(error = Error Domain=UNErrorDomain Code=100 "Invalid attachment file URL" UserInfo={NSLocalizedDescription=Invalid attachment file URL}),请问这是为什么呢?
      • zero000:您好 ,我想问下,notification content extension,适用于本地通知吗,我写了一个本地通知,添加了notification content extension (没有添加notification service extension),但是还是只显示系统默认的样式。
        zero000:@zero000 解决了
      • 冰凉的橘子:请问楼主 NotificationService中的 - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler 方法是如何触发的呢?我发送通知之后,在Service Extension打的断点没有作用。
        消逝彼得:@冰凉的橘子 真机能收到通知?
        冰凉的橘子:@消逝彼得运行target了,但是在target中didReceiveNotificationRequest 方法的断点没用。 我现在可以触发本地的UNNotificationAttachment方法。有什么需要添加或者注意的地方吗?比如target或info设置。
        消逝彼得:@冰凉的橘子 你要运行NotificationService的target
      • kakatimo:不错
      • 51d110d37245:大哥,求您封装一个公共类的 demo 呗,新技术看着好费劲啊,~~~~(>_<)~~~~
        消逝彼得:@麦兜是我滴 额,最近有点忙,也就没多整理,不懂的可以直接问我 :sunglasses:
      • butterflyer:楼主有没有demo给看看吗。。。
        消逝彼得:@butterflyer 额,最近有点忙,没单独去弄,直接粘贴上了,你有啥直接问我也可以
      • 快到碗里来____:666666666666
      • 俊洋洋:6666666666666

      本文标题:ios10推送详解

      本文链接:https://www.haomeiwen.com/subject/thyeettx.html