iOS 远程推送消息处理

developer.jpeg

一、引言

应用开发到一定阶段的时候,运行为了吸引用户提高应用的使用频率,消息推送这个简单的功能是比不可少的。对于 iOS 应用的推送分为本地推送和远程推送,常用的应该是远程推送。在 iOS 10 发布之后,对远程推送进行了一次比较大的升级,之前也没有仔细研究过,今天突然发现了之前存在很多误区,特此记录。我的推送服务用的是极光推送。

二、远程推送的分类状态

远程推送一般情况下根据 App 的运行状态分成 前台、后台、未启动 三种状态。

  1. 在 iOS 10 之前 我们要对这三种状态分别处理:

    1.1 应用在前台运行时,这时候收到远程推送,系统默认不会有任何响应,但是我们可以通过下面这个方法捕获到推送的消息内容进行处理,常见的处理操作(比如打开应用的某个指定页面),但是如果这时候就直接打开页面,对用户来说就比较不友好了,我正在使用你突然直接给我跳转一个新页面,WC,这是神马逻辑。所以这种处理逻辑很不好。比较友好的处理方式可以是模仿系统推送一样,在顶部弹出一个 view 显示消息的内容,几秒后消失,用户可以点击也可以不点击(github 上也有封装好开源库,使用起来非常方便)。还有一种处理方式就是在应用内对应的 tab 或 item 上设置角标来提示用户有新内容。也可以将远程消息转换为本地推送来处理。

    1.2 应用在后台挂起时,就比较好处理了,点击消息进入应用也会执行下面的方法。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // Required, iOS 7 Support
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    [JPUSHService setBadge:0];
    [JPUSHService handleRemoteNotification:userInfo];
    if (application.applicationState == UIApplicationStateActive) { 
          //如果是在前台运行,可以将推送消息转换为本地推送消息,实现类似远程推送的效果
        UILocalNotification *localNotification = [[UILocalNotification alloc] init];
        localNotification.userInfo = userInfo;
        localNotification.soundName = UILocalNotificationDefaultSoundName;
        localNotification.alertBody = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"];
        localNotification.fireDate = [NSDate date];
        [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    } else if (application.applicationState == UIApplicationStateInactive){
       //如果是在后台挂起,用户点击进入是UIApplicationStateInactive这个状态
       // TODO...
    }
    // 这个方法必须调用
    completionHandler(UIBackgroundFetchResultNewData);
}

1.3 应用未启动收到远程推送消息是,会调用:

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

与点击应用图标进入应用的流程是一样的,区别在于 launchOptions 这个参数,如果是点击推送消息进入,launchOptions 会包含推送消息的内容,所以可以根据 launchOptions 来判断。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // app关闭时,收到推送, 程序未启动,退出状态(如果是点击推送消息进入应用,launchOptions 会包含推送消息的内容。如果是点击图标进入则 launchOptions 不包含)
    if (launchOptions) {
        NSDictionary *userInfo = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
        if (userInfo) {
           //TODO...
        }
    }
    return YES;
}

获取到消息后,就可以对消息进行处理了。

  1. 在 iOS 10 之后,接受推送消息的方法变为:
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler
// 极光用的是下面这个方法
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler API_AVAILABLE(ios(10.0))

这个方法了。

\color{red}{对于一开始提到的误区来了}, iOS 10 的远程推送消息不在区分应用的状态了。无论当应用是在前台运行还是后台挂起状态,当接收到推送消息时,都会以横幅的形式提示用户(挂起时屏幕未锁定是横幅提示,屏幕锁定就会在通知中心里面),所以用户点击消息的处理可以放在一起不用再区分状态。

\color{red}{And ? 你以为这就完了么,没有!!!} 最大的坑来了。 一开始处理消息的时候,分作两种状态处理的, 应用未启动和前台后台。应用未启动用的上面提到的方式。但是测试的时候发现,推界面推了两次,由于未启动状态还不能连着真机测试,log 也没有异常,只能是加 toast 和 alert 来一步一步调试。发现原来是处理消息的方法调用了两次。那么问题来了,为什么会调用两次?一次是在 didFinishLaunchingWithOptions 调用的,那么另一次呢,在 didReceiveNotificationResponse 中。这就是 iOS 跟之前的不同之处。之前跟本不会调用。找到问题根源就好处理了,可以把 didFinishLaunchingWithOptions 中的处理删除,只用 didReceiveNotificationResponse 里面的一套处理逻辑就好,这样做事最简单方便的,也比较好维护。但是如果你的应用兼容 iOS 9 一下的系统就要分情况对待了。

  1. 在 iOS 6 之前,接收消息的方法是:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

不过现在应该没有老系统的机器了吧? 所以可以忽略这种情况。

三、总结

以上就是这次新应用推送消息遇到的问题,对于 iOS 10 之后的这种处理方法,在 iOS 11.4.1 系统和 12.0.1 系统上的效果都是一样的,目前手边没有 10 的系统没法测试,但是个人认为应该不会有什么区别。

如果看文章的小伙伴有跟我不一样的结论,欢迎指正。

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

推荐阅读更多精彩内容