美文网首页ios 知识小集iOS大咖学习之路
个推推送,APP接收到推送后的操作(前台与非前台的处理不同)

个推推送,APP接收到推送后的操作(前台与非前台的处理不同)

作者: Elvist | 来源:发表于2016-08-28 21:50 被阅读5476次
图1 个推推送服务框架图

首先,按照个推SDK集成指南配置好一个完整的工程。或者直接下载现有工程(需要修改bundle identifier、kGtAppId、kGtAppKey、kGtAppSecret)。
** 如有错误和待完善的地方,还请指正。 **

新建推送:


图2 注:Badge参数为icon的角标

本文将介绍对推送消息的两种处理方式。
在接收到推送消息时,分为3种情况,本文还将后两者细分为两种情况:

  1. APP处于前台
    1.1 APP接收到推送后推送后首先弹出一个Alert提示是否跳转页面
  2. APP处于后台
    2.1 点击通知栏使APP进入前台后,直接跳转页面
    2.2 点击icon图标使APP进入前台后,不作操作
  3. APP处于关闭状态
    3.1 点击通知栏启动APP,直接跳转页面
    3.2 点击icon图标启动APP,不作操作

方式一:

首先为AppDelegate添加一个属性,

// 用来判断是否是通过点击通知栏开启(唤醒)APP
@property (nonatomic) BOOL isLaunchedByNotification;

当通过点击通知栏来启动或唤醒APP时,会调用didReceiveRemoteNotification:方法,在该方法里将isLaunchedByNotification的值置为YES:

/** APP已经接收到“远程”通知(推送) - 透传推送消息  */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    
    // 当APP处于后台或者关闭状态,点击通知栏就会先走这个方法,再使得个推SDK收到透传消息回调
    // 处理APNs代码,通过userInfo可以取到推送的信息(包括内容,角标,自定义参数等)。如果需要弹窗等其他操作,则需要自行编码。
    NSLog(@"\n>>>APP已经接收到“远程”通知(推送)[Receive RemoteNotification - Background Fetch]:%@\n\n",userInfo);
    completionHandler(UIBackgroundFetchResultNewData);
    
    self.isLaunchedByNotification = YES;
}

然后会调用以下方法(当APP处于前台时会直接调用此方法),其中payloadData的值转为NSString对象即为图2中的消息内容里的JSON数据:

/** SDK收到透传消息回调 */
- (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
    
    // 收到个推消息
    NSString *payloadMsg = nil;
    if (payloadData) {

        payloadMsg = [[NSString alloc] initWithBytes:payloadData.bytes
                                              length:payloadData.length
                                            encoding:NSUTF8StringEncoding];
    }

    // 当app不在前台时,接收到的推送消息offLine值均为YES
    // 判断app是否是点击通知栏消息进行唤醒或开启
    // 如果是点击icon图标使得app进入前台,则不做操作,并且同一条推送通知,此方法只执行一次
    if (offLine) {
        
        // 离线消息,说明app接收推送时不在前台
        if (self.isLaunchedByNotification) {
            
            // app是通过点击通知栏进入前台
            [[NSNotificationCenter defaultCenter] postNotificationName:kNOTIFICATION_PUSH object:nil userInfo:@{kNOTIFICATION_PUSH : payloadMsg}];
            self.isLaunchedByNotification = NO;
        } else {
            
            // app是通过点击icon进入前台,在这里不做操作
            
        }
    } else if(!self.isLaunchedByNotification) {
        
        // app已经处于前台,提示框提示
        [[NSNotificationCenter defaultCenter] postNotificationName:kNOTIFICATION_ALERT object:nil userInfo:@{kNOTIFICATION_ALERT : payloadMsg}];
    }elf.isLaunchedByNotification = NO;
    }
}

2.2和3.2情况下的问题

这两种情况下,如果用户不点击通知栏而是点击桌面icon图标启动或唤起APP,会直接调用GeTuiSdkDidReceivePayloadData:方法,根据本文的方式处理的话确实不会有任何操作,但是通知栏的消息仍然存在,如果再次点击通知栏消息,仍会调动didReceiveRemoteNotification:方法,但是不会再调用GeTuiSdkDidReceivePayloadData:方法,这样的话isLaunchedByNotification的值会被置为YES,而且无法再被置为NO。
解决办法:在app进入前台后通过将Badge角标置为0来移除通知栏信息,代码如下:

- (void)applicationDidBecomeActive:(UIApplication *)application {

    // 这里的写法是为了在app进入前台后,清除通知栏消息
    NSInteger badge = [UIApplication sharedApplication].applicationIconBadgeNumber;
    badge = badge == 1 ? 2 : 1;
    // 这里经过两次赋值才可以移除通知栏消息
    [UIApplication sharedApplication].applicationIconBadgeNumber = badge;
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;

//    // 下面这个方法只有Badge角标不为0时才执行,如果个推推送时Badge为0,那么不会走下面的方法
//    if (badge) {
//    
//        badge = badge == 1 ? 2 : 1;
//        [UIApplication sharedApplication].applicationIconBadgeNumber = badge;
//        [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
//    }
}

方式二:

这种方式默认在通过点击icon使app进入前台时不做操作。
当通过点击通知栏来启动或唤醒APP时,会调用didReceiveRemoteNotification:方法,接收到的推送内容包含在userInfo参数里,可以在此方法里对推送消息进行操作:

/** APP已经接收到“远程”通知(推送) - 透传推送消息  */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    
    // 当APP处于后台或者关闭状态,点击通知栏就会先走这个方法,再使得个推SDK收到透传消息回调
    // 处理APNs代码,通过userInfo可以取到推送的信息(包括内容,角标,自定义参数等)。如果需要弹窗等其他操作,则需要自行编码。
    NSLog(@"\n>>>APP已经接收到“远程”通知(推送)[Receive RemoteNotification - Background Fetch]:%@\n\n",userInfo);
    completionHandler(UIBackgroundFetchResultNewData);
   
    // app是通过点击通知栏进入前台
    [[NSNotificationCenter defaultCenter] postNotificationName:kNOTIFICATION_PUSH object:nil userInfo:@{kNOTIFICATION_PUSH : payloadMsg}];
}

同时,由于系统方法调用完成后,个推仍会调用一次GeTuiSdkDidReceivePayloadData:方法,需要在GeTuiSdkDidReceivePayloadData:方法里判断当前消息是否为offLine离线消息,如果是离线消息则不做任何处理:

/** SDK收到透传消息回调 */
- (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
    
    // 收到个推消息
    NSString *payloadMsg = nil;
    if (payloadData) {

        payloadMsg = [[NSString alloc] initWithBytes:payloadData.bytes
                                              length:payloadData.length
                                            encoding:NSUTF8StringEncoding];
    }

    // 当app在前台时,接收到的推送消息offLine值均为NO
    // 对于离线消息,这里不做操作
    if (!offLine) {
        
        // app已经处于前台,提示框提示
        [[NSNotificationCenter defaultCenter] postNotificationName:kNOTIFICATION_ALERT object:nil userInfo:@{kNOTIFICATION_ALERT : payloadMsg}];
    }
}

对于角标的处理可以参考方式一中的处理方法。

相关文章

网友评论

  • listen_blue:楼主有没有Dome?
  • 郭磊_2a92:楼主你好,用您的方法现在遇到一个问题,通知栏上不止一条信息,点击其中一条进入app后会把所有的通知栏上需要跳转的页面全部跳转了,怎么判断是点击了哪条通知栏上的信息呢?楼主帮忙看一下,挺急的
    69662402cbe0:我也遇到了这个问题,想问下怎么解决的呢
  • charles_14ff:楼主你要,我现在遇到一个问题,当把强制关掉,收到消息,点击消息栏,进入不能跳转到指定的页面。
  • 054ce4d15908:楼主你好,为什么我前台能接收到消息,执行了GeTuiSdkDidReceivePayloadData这个方法,我退出后台时发出一条消息,在后台不能接收,只能再次进入前台才能接收,怎么做才能实现在后台时,消息显示在通知栏里,在前台出现弹框啊,
    hu9134:你好,请问实现了吗?我也遇到了同样的问题
  • 8abf4a1d1d51:楼主你好,请问当app打开后,锁屏,然后远程推送收到消息后,解锁,应该怎么实现 notification 也 pop up view 出来?
    我现在app foreground时,收到远程推送会直接pop up 一个view出来

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {

    if application.applicationState == .active {
    NotificationCenter.default.post(name: .JoinTable, object: nil, userInfo: userInfo)
    print("B'1 - new msg active")
    } else if application.applicationState == .background {
    NotificationCenter.default.post(name: .JoinTable, object: nil, userInfo: userInfo)
    print("B'2 - new msg background")
    UIApplication.shared.applicationIconBadgeNumber = 0
    } else if application.applicationState == .inactive {
    NotificationCenter.default.post(name: .JoinTable, object: nil, userInfo: userInfo)
    print("B'3 - new msg inactive")
    UIApplication.shared.applicationIconBadgeNumber = 0
    } else {
    print("B'4 - new msg unknown")
    }
    }
    我的didreceiveremotenotificaiton 是这么写的,不过还有一个小问题,为什么app在后台时,每次这里run 的都是inavtive,很奇怪为什么不是background。
    谢谢
  • 哈哈大p孩:楼主您好,我用后台写好的管理平台发消息,为什么我只有在前台的时候,才能收到透传消息的推送消息,在后台或者应用程序杀死的情况下,都收不到消息?求解答 :joy:
    ychen3022:@哈哈大p孩 我也遇到了这样的问题 不知道怎么解决
  • 字母B一路向北:楼主,我怎么实验得出的是程序在前台时走得这个方法-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
    }
    字母B一路向北:@Elvist 好的,谢谢
    Elvist:@字母B一路向北 走这个方法的话说明个推服务器判定你的ClientID不在线,可能是个推SDK连接的问题
  • 不可以被嘲笑的大树:@不可以被嘲笑的大树 两个方法都可以处理离线消息消息是么 如果点击提示拦进来 两个方法中都处理了离线消息 那是不是就造成重复了
    Elvist:@不可以被嘲笑的大树 在一个里面处理推送消息就可以
  • 不可以被嘲笑的大树:那就是说 如果用户在后台收到推送点击提示栏进来 首先经过didReceiveRemoteNotification 我们也可以在这个方法里面 拿到推送的内容 可以直接处理 也可以说在GeTuiSdkDidReceivePayloadData 方法里面拿到推送的内容处理是么
    不可以被嘲笑的大树:@Elvist 好的 感谢楼主 下午看了很多帖子说法不一感觉困惑 现在很清晰 再一次感谢楼主
    Elvist:@不可以被嘲笑的大树 对。而且我建议在GeTuiSdkDidReceivePayloadData 里处理推送消息,这样无论你是用各种方式启动或唤醒App,都可以接收到推送消息并进行处理
  • 不可以被嘲笑的大树:想请问楼主下 如果App在后台收到推送 点击通知栏 或者点击App图标进入应用 都会经过GeTuiSdkDidReceivePayloadData这个代理方法么
    Elvist:@不可以被嘲笑的大树 可以
    不可以被嘲笑的大树:@Elvist GeTuiSdkDidReceivePayloadData 有一个offline 参数 我们可以通过这个是否离线来决定处理不处理离线的消息是么?
    Elvist:会的

本文标题:个推推送,APP接收到推送后的操作(前台与非前台的处理不同)

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