iOS 10 推送通知

苹果的推送通知从iOS3开始出现, 每一年都会更新一些新的用法, 譬如:

  • iOS 7 出现的Silent remote notifications(远程静默推送)
  • iOS 8 出现的Category(分类, 也可称之为快捷回复)
  • iOS 9 出现的Text Input action(文本框快捷回复).

随着iOS10的到来 , 苹果对远程通知和本地通知进行了大范围的更新.
iOS10推出了全新的UserNotifications框架(iOS10之前从属于UIKit框架).

新的推送通知框架, 整合了本地推送和远程推送的点击处理方法, 使得以前专门处理推送点击的方法只能处理静默推送了.

远程推送的实现原理:



1 打开App时: 发送UDID和BundleID给APNs加密后返回deviceToken
2 获取Token后,App调用接口,将用户身份信息和deviceToken发给服务器,服务器记录
3 当推送消息时, 服务器按照用户身份信息找到存储的deviceToken,将消息和deviceToken发送给APNs
4 苹果的APNs通过deviceToken, 找到指定设备的指定程序, 并将消息推送给用户

实现远程推送功能的前提:



1 真机
2 调试阶段的证书

  • iOS_development.cer 用于真机调试的证书
  • aps_development.cer 用于真机推送调试能的证书
  • xxx.mobileprovision 描述文件,记录了能够调试的手机、电脑和程序

3 发布阶段的证书

  • iOS_distribution.cer 用于发布app的证书
  • aps.cer 用于发布时,让app有推送功能的证书
  • xxx.mobileprovision 描述文件,记录了能够发布app的电脑

iOS10 全新远程通知Demo:


一. 注册远程推送并获取DeviceToken

1.创建iOS的项目,并输入项目名字
2.在AppDelegate中导入头文件:

#import <UserNotifications/UserNotifications.h>

3.在application:didFinishLaunchingWithOptions方法中, 注册远程通知

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    //请求通知权限, 本地和远程共用
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

    [center requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) {
            NSLog(@"请求成功");
        } else {
            NSLog(@"请求失败");
        }
    }];

    //注册远程通知
    [[UIApplication sharedApplication] registerForRemoteNotifications];

    //设置通知的代理
    center.delegate = self;

    return YES;
}

4.在接收远程推送的DeviceToken方法中, 获取Token

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    //将来需要将此Token上传给后台服务器
    NSLog(@"token:%@", deviceToken);
}

二. iOS10远程推送通知的处理方法



当点击了推送后, 如果你希望进行处理. 那么在iOS10中, 还需要设置UNUserNotificationCenter的delegate, 并遵守UNUserNotificationCenterDelegate协议.

以及实现下面实现3个方法, 用于处理点击通知时的不同情况的处理

* userNotificationCenter:willPresentNotification:withCompletionHandler: 前台运行

* userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: 后台运行时点击横幅、消息栏消息

* application:didReceiveRemoteNotification:fetchCompletionHandler: 静默推送、App杀死后横幅和消息栏消息点击唤起App

//设置通知的代理
center.delegate = self;

1.前台运行 会调用的方法
前台运行: 指的是程序正在运行中, 用户能看见程序的界面.
iOS10会出现通知横幅, 而在以前的框架中, 前台运行时, 不会出现通知的横幅.

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
{
    NSDictionary *userInfo = notification.request.content.userInfo;

    //前台运行推送 显示红色Label
    [self showLabelWithUserInfo:userInfo color:[UIColor redColor]];

    //可以设置当收到通知后, 有哪些效果呈现(声音/提醒/数字角标)
    completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
}

2.后台运行点击消息会调用的方法
后台运行: 指的是程序已经打开, 用户看不见程序的界面, 如锁屏和按Home键.
程序退出: 指的是程序没有运行, 或者通过双击Home键,关闭了程序.

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler
{
    NSDictionary *userInfo = response.notification.request.content.userInfo;

    //后台显示绿色Label
    [self showLabelWithUserInfo:userInfo color:[UIColor greenColor]];

    completionHandler();
}

3.静默推送通知 会调用的方法
静默推送: iOS7以后出现, 不会出现提醒及声音.
要求:

  • 推送的payload中不能包含alert及sound字段
  • 需要添加content-available字段, 并设置值为1
  • 例如: {"aps":{"content-available":"1"},"PageKey”":"2"}
//如果是以前的旧框架, 此方法 前台/后台/退出/静默推送都可以处理
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    //静默推送 显示蓝色Label
    [self showLabelWithUserInfo:userInfo color:[UIColor blueColor]];

    completionHandler(UIBackgroundFetchResultNewData);
}

4.处理通知的公用方法
开发中, 点击通知的逻辑应当看自己程序的需求.
这里为了方便演示, 简单的将通知的值, 通过UILabel显示在主界面上

- (void)showLabelWithUserInfo:(NSDictionary *)userInfo color:(UIColor *)color
{
    UILabel *label = [UILabel new];
    label.backgroundColor = color;
    label.frame = CGRectMake(0, 250, [UIScreen mainScreen].bounds.size.width, 300);
    label.text = userInfo.description;
    label.numberOfLines = 0;
    [[UIApplication sharedApplication].keyWindow addSubview:label];
}

三. 测试远程推送

PushMeBaby是一个简单的模拟服务器的Mac小程序, 可以将内容提交给苹果的APNs服务器.
为了测试远程通知, 我们需要安装此程序.
请前往www.github.com, 搜索并下载PushMeBaby

使用时:

  1. 编译该项目, 如果报错, 则注释报错的代码, 不影响实际使用.
  2. 进入苹果开发者网站, 获取真机调试用的远程推送证书, 导入到项目中
  3. 将之前获取到的DeviceToken, 及测试的文字, 填入该项目中的AppDelegate中的init方法中.
  4. 运行此项目, 会出现一个Mac小程序, 点击Push即可发送远程通知.
- (id)init {
    self = [super init];
    if(self != nil) {
        self.deviceToken = @"de20184c ef0461d5 12c76422 f5b78240 5f657e18 ebf91c9f 01d5560c e2913102";
        self.payload = @"{\"aps\":{\"alert\":{\"title\":\"传智播客\",\"subtitle\":\"黑马程序员\",\"body\":\"iOS10远程&本地推送教程\"},\"badge\":1,\"sound\":\"default\"},\"PageKey\":\"1\"}";
        self.certificate = [[NSBundle mainBundle] pathForResource:@"aps_development" ofType:@"cer"];
    }
    return self;
}

四.补充

因为推送的回调Api方法过多, 初次接触可能会有些头大,虽然从iOS 10起,苹果对于推送的授权(本地+远程)方式有所调整, 而且采用了使用代理的方式. 而我们也可以采取的实现方式是:

1. 通过requestAuthorizationWithOptions:授权
2. 不设置UNUserNotificationCenter 的 delegate 
3. 这样还会走之前iOS 9的回调方法

五. 回调API

  • application: didReceiveRemoteNotification: fetchCompletionHandler:前台收到推送消息时,不会有弹框提醒
  • userNotificationCenter: willPresentNotification: withCompletionHandler:可以通过设置回调参数,根据回调参数内是否传入UNNotificationPresentationOptionAlert,如果有,则在前台收到推送时,也会有弹框提醒,在系统通知栏内可见推送消息,如果不传入,则不会有弹框提醒,系统通知栏不可见
    completionHandler( UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound );

对于收到推送后, 通知消息的获取与进入App的方式有关:

    1. App未运行时:
      1.1 点击通知消息进入, 会执行didFinishLaunchWithOptions:方法,通过options获取通知消息
      1.2 点击应用图标进入,会执行didFinishLaunchWithOptions方法,但options中不包含notification信息
  • 2.App后台运行:
    2.1 点击通知消息进入,会执行didReceiveRemoteNotification:方法(不同iOS版本的后台方法),从而获取推送消息
    2.2 点击应用图标进入,会执行didReceiveRemoteNotification方法不会被调用,无法获取到推送消息

  • 对于1.2和2.2场景, 可以通过后台协助, 每次点击应用图标进入后,向后台请求是否有新的未读推送,通过请求的方式获取推送信息.

  • 对于1.1&1.2场景, 如果远程通知到达时应用程序未运行,则application: didReceiveRemoteNotification: fetchCompletionHandler:该方法将启动应用程序并在启动选项字典中提供适当的信息。

if the app is not running when a remote notification arrives, 
the method launches the app and provides the appropriate information in the launch options dictionary. 
The app does not call this method to handle that remote notification. 
Instead, your implementation of the 
application:willFinishLaunchingWithOptions: 
or 
application:didFinishLaunchingWithOptions: 
method needs to get the remote notification payload data and respond appropriately.
关于角标:
App当前角标 收到推送 变化
角标为0 推送badge > 0 角标 = badge
角标为0 推送badge = 0 不显示角标
角标不为0 推送badge > 0 角标 = badge (最后一条推送中的badge)
角标不为0 推送badge = 0 角标 = 0 , 同时在通知栏清空之前的推送记录
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容