iOS 远程推送

概念相关

1.什么是远程推送通知?

  • 顾名思义,就是从远程服务器推送给客户端的通知(需要联网)
  • 远程推送服务,又称为APNs(Apple Push Notification Services)

2.为什么需要远程推送通知?

  • 传统获取数据的局限性:只要用户关闭了app,就无法跟app的服务器沟通,无法从服务器上获得最新的数据内容

  • 远程推送通知可以解决以上问题:不管用户打开还是关闭app,只要联网了,都能接收到服务器推送的远程通知

3.所有的苹果设备,在联网状态下,都会与苹果的服务器建立长连接

什么是长连接?
只要联网了,就一直建立连接

长连接的作用:
时间校准
系统升级
查找我的iPhone

长连接的好处:
数据传输速度快
数据保持最新状态

4.远程推送原理
客户端发送设备的UDID和程序的bundle ID请求苹果服务器(SSL安全),客户端获得Token号存储起来,客户端再将Token号和用户信息等(如QQ号等)绑定发送给公司服务器,公司服务器保存token号和账户的关联信息,在适当时候,公司根据token号再通知苹果服务器进行消息推送

远程推送原理

准备工作

  1. 开发iOS程序的推送功能, iOS端需要做的事

  2. 请求苹果获得deviceToken

    UDID : 目的是将来可以找到手机
    Bundle ID : 目的是将来可以找到手机中的程序

  3. 得到苹果返回的deviceToken

  4. 发送deviceToken给公司的服务器

  5. 监听用户对通知的点击

  6. 调试iOS的远程推送功能必备条件:真机、付费开发者账号

  7. 调试推送需要的证书文件
    1> aps_development.cer : 推送测试证书,某台电脑就能调试某个app的推送服务
    2> ios_development.cer : 调试证书,让电脑具备真机调试的能力(调试设备)
    3> iphone5_qq.mobileprovision :描述文件, 某台电脑就能利用某台设备调试某个程序

  8. 发布具有推送服务的app
    1> aps_production.cer : 如果发布的程序中包含了推送服务,就必须安装这个证书
    2> ios_distribution.cer : 让电脑具备发布程序的能力
    3> qq.mobileprovision : 某台电脑就能发布某个程序

记得推送证书要给后台!!!
  1. 如何创建推送证书?
    创建调试用的推送证书流程跟创建普通调试证书一样, 多了一个选择BundlD ID的过程 (如果之前配置的是通配符Bundld ID ,则无法使用Push功能)
    1.选择推送证书


    选择推送证书

    2.打开Bundle ID设置,确保push选项是enabled状态,不是可点击edit进行编辑


    保证是enabled状态

3.或点击编辑


点击编辑

打勾后进行配置


打勾后进行配置

4.配置成功后钥匙串中多了一个证书,一个调试,一个push
钥匙串

代码实现:(前提:确保bundleID和网站的配置一样)

要注意,由于iOS8 以后推送需要用户授权,所以AppDelegate中要分别适配不同版本

  1. 注册推送,注册后就会向苹果服务器发送Token号
    iOS8和iOS7注册通知对比:
  2. 多了一个授权的方法UIUserNotificationSettings
  3. 以前的方法中Remove换成了User


    注册推送
  4. 注册远程推送完成后调用,该方法返回Token,一般在这个方法中将Token发给公司服务器作保存
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
打印Token号

注意:安装程序之后,无论运行多少次,Token都不应该发送改变!
但是在Xcode7中这个选项打开和关闭的Token值不一样!打开的时候才是真正的Token值!

注意在Xcode 7 之后必须打开推送的选项,否则可能会导致请求的token不一样!
打开推送选项

代码优化:
上面方法每次都需要请求Token,Token号只有第一次才需要请求,所以可以进行判断第一次才需要请求Token
可以用一个字典包装Token号,并存起来,下次读取如果字典里有值就不需要再请求了
注意:如果客户端更换了用户信息,就需要重新请求Token,删除本地信息重新请求,并删除公司服务器端Token信息(也可不删除添加一个),保证推送到新登录的账户上

3.模拟服务器测试推送:

Easy APNs Provider 工具
PushMeBaby 工具

PushMeBaby 使用方法
(1)导入推送调试证书文件

导入推送证书

(2)更改 ApplicationDelegate 中init方法中的对应值


修改Token号

(3)运行,点击推送


点击推送

(4)推送成功程序右上角就会有一个1的角标
推送成功!

4.接收到通知后程序回调的代理方法

注意:要考虑三种情况,后台、前台、退出程序。远程推送和本地推送一样,都需要在两个地方做代码的处理:

  1. 接受到通知时调用的代理方法中(前台和后台)
  2. 启动时的 didFinishLaunchingWithOptions方法中(退出状态),用 launchOptions [UIApplicationLaunchOptionsRemoteNotificationKey]获取远程通知对象

(1)前台和后台的推送回调这个代理方法(退出的设置在didFinishLaunchingWithOptions方法中)

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;

(2)前台、后台和退出的推送都会调用这个代理方法(iOS 7之后可用)

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;
注意:

(1)如果实现了该方法会导致上面方法失效
(2)会有如下警告:在方法中调用下handler就好了,注意该handler需要一个参数
completionHandler(UIBackgroundFetchResultNewData);


处理警告

(3)还有警告,需要添加一个值在info.plist中,可用到界面把后台模式更改一下


处理警告

勾选remote notifications

AppDelegate中的全部代码

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 设置要注册的通知类型,iOS8以后配置授权
    if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
        UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else {
        // 如果是iOS8以前,设置要注册的通知类型
        UIRemoteNotificationType type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:type];
    }

     // iOS7之前,如退出程序后接收到推送,想要处理获取通知后的事件要在下面代码中
    if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
        // 获取到通知对象, 进行处理
        NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey][@"userInfo"];
        // 退出程序测试方法,真正接收到了通知就在界面上创建一个红色的View(控制台无法打印)
        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 375, 200)];
        label.text = userInfo.description;
        label.numberOfLines = 0;
        [self.window.rootViewController.view addSubview:label];
    }
    return YES;
}

#pragma mark 远程推送注册完毕, 服务器返回Token时, 调用此方法
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    // 将来要在这里将Token 发送给自己的服务器做保存
    NSLog(@"deviceToken: %@", deviceToken);
}

#pragma mark 接收到远程推送的消息时调用此方法(后台和前台时可用)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    // 记得要判断用户是否在前台
    if (application.applicationState == UIApplicationStateActive) {
        NSLog(@"不要自动跳转/ 给用户提示");
        return ;
    }
    // 将来需要取消角标的数字, 是根据用户是否做了某些操作, 来更改数字角标的值
    // 获取推送的值
    NSInteger count = [userInfo[@"aps"][@"badge"] intValue];
    // 设置相关的属性
    application.applicationIconBadgeNumber = count;
}

#pragma mark 接收到远程推送的消息时调用此方法(前、后、退出都可用,iOS7以后可用)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // 测试添加一个label表示接收到通知
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 375, 200)];
    label.text = userInfo.description;
    label.numberOfLines = 0;
    [self.window.rootViewController.view addSubview:label];
    // 不调用该block会报错
    completionHandler(UIBackgroundFetchResultNewData);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容