美文网首页
『ios』个推集成适配 9.0起步

『ios』个推集成适配 9.0起步

作者: butterflyer | 来源:发表于2018-12-20 16:05 被阅读84次
    image.png

    最近在搞个推,记录下吧。
    由于公司产品要求在前台的时候也需要跟后台时一样的弹窗,所以顺便搞了下本地推送。

    第一步 照着文档复制粘贴一把梭

    - (void)registerRemoteNotification {
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // Xcode 8编译会调用
            UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
            center.delegate = self;
            [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) {
                if (!error) {
                    NSLog(@"request authorization succeeded!");
                }
            }];
            [[UIApplication sharedApplication] registerForRemoteNotifications];
    #else // Xcode 7编译会调用
            UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
            [[UIApplication sharedApplication] registerForRemoteNotifications];
            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    #endif
        } else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
            UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
            [[UIApplication sharedApplication] registerForRemoteNotifications];
            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
            
        } else {
            UIRemoteNotificationType apn_type = (UIRemoteNotificationType)(UIRemoteNotificationTypeAlert |UIRemoteNotificationTypeSound |UIRemoteNotificationTypeBadge);
            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:apn_type];
        }
    }
    

    对于 9.0系统

    -(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
        TVMLOG(@"%@",notification.userInfo);
        TVMLOG(@"%d",[UIApplication sharedApplication].applicationState);
        if (application.applicationState != UIApplicationStateActive) {
          [[TVMPushJumpManager shareInstance]jumpWithUserInfo:notification.userInfo];
        }
    }
    - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{
        [application registerForRemoteNotifications];
    }
    //     didReceiveNotification  GeTuiSdkDidRegisterClient GeTuiSdkDidReceivePayloadData
    /** 远程通知注册成功委托 */
    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
        // [3]:向个推服务器注册deviceToken 为了方便开发者,建议使用新方法
        [GeTuiSdk registerDeviceTokenData:deviceToken];
    }
    -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
        TVMLOG(@"%@",userInfo);
    }
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        // 将收到的APNs信息传给个推统计
        [GeTuiSdk handleRemoteNotification:userInfo];
    
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive) {
             self.isResponseUserNotification = YES;
        }
        completionHandler(UIBackgroundFetchResultNewData);
    }
    
    

    对于 10.0系统

    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
    //  iOS 10: App在前台获取到通知
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
        // 根据APP需要,判断是否要提示用户Badge、Sound、Alert
        completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);
    }
    //  iOS 10: 点击通知进入App时触发,在该方法内统计有效用户点击数
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
        
        TVMLOG(@"didReceiveNotification:%@", response.notification.request.content.userInfo);
        if ([response.notification.request.identifier isEqual:@"TVMLocalPushKey"]) {
            [[TVMPushJumpManager shareInstance]jumpWithUserInfo:response.notification.request.content.userInfo];
        }
        self.isResponseUserNotification = YES;
        // [ GTSdk ]:将收到的APNs信息传给个推统计
        [GeTuiSdk handleRemoteNotification:response.notification.request.content.userInfo];
        completionHandler();
    }
    #endif
    

    因为个推ios端只支持消息透传

    /** SDK启动成功返回cid */
    - (void)GeTuiSdkDidRegisterClient:(NSString *)clientId {
        //个推SDK已注册,返回clientId
    //      [TVMHelper showMessageAlert:@"GeTuiSdkDidRegisterClient" Title:@"clientId"];
        TVMLOG(@"\n>>>[GeTuiSdk RegisterClient]:%@\n\n", clientId);
    }
    /** SDK收到透传消息回调 */
    - (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
        NSError *error=nil;
        NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:payloadData options:NSJSONReadingMutableContainers error:&error];
        NSDictionary *msgInfoDic = dic[@"msgInfo"];
        NSString *title=[NSString stringWithFormat:@"%@",msgInfoDic[@"title"]];
        NSString *detail=[NSString stringWithFormat:@"%@",msgInfoDic[@"body"]];
        TVMLOG(@"%@",dic);
    //当app从后台点进来的时候,offline是YES isResponseUserNotification 为 YES代表从状态栏点击进来的  为NO为从icon点进来的
        if (self.isResponseUserNotification == YES && offLine == YES) {
            [[TVMPushJumpManager shareInstance]jumpWithUserInfo:dic];
        }
        // 当app不在前台时,接收到的推送消息offLine值均为YES
        // 判断app是否是点击通知栏消息进行唤醒或开启
        // 如果是点击icon图标使得app进入前台,则不做操作,并且同一条推送通知,此方法只执行一次
        if (!offLine) {//  离线消息已经有苹果的apns推过消息了,避免上线后再次受到消息
            //本地推送
            if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0){
                [[TVMLocalPushManager shareInstance] registerNotification:1 andTitle:title andMess:detail andUserInfo:dic];
            }else{
                [[TVMLocalPushManager shareInstance] registerLocalNotificationInOldWay:1 andTitle:title andMess:detail andUserInfo:dic];
            }
            return;
        }
    }
    

    然后是本地推送部分,因为10.0用了UserNotifications 所以

    #pragma mark -- 本地推送
    
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
    -(void)registerNotification:(NSInteger )alerTime andTitle:(NSString*)title andMess:(NSString*)mes andUserInfo:(NSDictionary *)userInfo{
    
        UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
        UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
        content.title = [NSString localizedUserNotificationStringForKey:title arguments:nil];
        content.body = [NSString localizedUserNotificationStringForKey:mes
                                                             arguments:nil];
        content.sound = [UNNotificationSound defaultSound];
        content.userInfo=userInfo;
        [content.userInfo setValue:TVMLocalPushKey forKey:@"identifier"];
        UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
                                                      triggerWithTimeInterval:alerTime repeats:NO];
        UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:TVMLocalPushKey
                                                                              content:content trigger:trigger];
        //添加推送成功后的处理!
        [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
        }];
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[UIApplication sharedApplication].applicationIconBadgeNumber+1];
        [GeTuiSdk setBadge:[UIApplication sharedApplication].applicationIconBadgeNumber];
    }
    #endif
    
    -(void)registerLocalNotificationInOldWay:(NSInteger)alertTime andTitle:(NSString*)title andMess:(NSString*)mes andUserInfo:(NSDictionary *)userInfo{
        
        UILocalNotification *notification = [[UILocalNotification alloc] init];
        NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:alertTime];
        notification.fireDate = fireDate;
        notification.timeZone = [NSTimeZone defaultTimeZone];
        notification.repeatInterval = kCFCalendarUnitEra;
        notification.alertBody = title;
        notification.applicationIconBadgeNumber = 1;
        notification.soundName = UILocalNotificationDefaultSoundName;
    //    NSDictionary *userDict = [NSDictionary dictionaryWithObject:mes forKey:@"key"];
        [userInfo setValue:TVMLocalPushKey forKey:@"identifier"];
        notification.userInfo = userInfo;
    
        [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:[UIApplication sharedApplication].applicationIconBadgeNumber+1];
        [GeTuiSdk setBadge:[UIApplication sharedApplication].applicationIconBadgeNumber];
    }
    
    

    主要代码就是上面那些,说下几个需要注意的地方。

    1.因为我需要当用户点击 状态栏的时候去跳转页面。就需要拿一个参数来区分是从icon点进来的还是从状态栏点进来的。
    因为我是给appdelegate写的分类,先绑定属性

    #pragma mark -- 绑定属性  用来判断是否是从状态栏点击进来的推送
    -(void)setIsResponseUserNotification:(BOOL)isResponseUserNotification{
        objc_setAssociatedObject(self, &isResponseUserNotificationKey, [NSNumber numberWithBool:isResponseUserNotification], OBJC_ASSOCIATION_ASSIGN);
    }
    -(BOOL)isResponseUserNotification{
      return  [objc_getAssociatedObject(self, &isResponseUserNotificationKey) boolValue];
    }
    

    对于 10.0以上系统点击状态栏

    //  iOS 10: 点击通知进入App时触发,在该方法内统计有效用户点击数 self.isResponseUserNotification = YES
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
        
        TVMLOG(@"didReceiveNotification:%@", response.notification.request.content.userInfo);
        if ([response.notification.request.identifier isEqual:@"TVMLocalPushKey"]) {
            [[TVMPushJumpManager shareInstance]jumpWithUserInfo:response.notification.request.content.userInfo];
        }
        self.isResponseUserNotification = YES;
        // [ GTSdk ]:将收到的APNs信息传给个推统计
        [GeTuiSdk handleRemoteNotification:response.notification.request.content.userInfo];
        completionHandler();
    }
    

    当9.0系统点击状态栏 当app处于 UIApplicationStateInactive self.isResponseUserNotification = YES;

    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        // 将收到的APNs信息传给个推统计
        [GeTuiSdk handleRemoteNotification:userInfo];
    
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive) {
             self.isResponseUserNotification = YES;
        }
        completionHandler(UIBackgroundFetchResultNewData);
    }
    

    然后在 applicationWillResignActive

    - (void)applicationWillResignActive:(UIApplication *)application {
        [[TVMTokenVerifyModel sharedToken] stopRefrershToken];
        self.isResponseUserNotification = NO;
    }
    
    

    最后因为是走的个推的透传消息,所以会走到这里。

    - (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId{
        // 当app不在前台时,接收到的推送消息offLine值均为YES
        // 判断app是否是点击通知栏消息进行唤醒或开启
        // 如果是点击icon图标使得app进入前台,则不做操作,并且同一条推送通知,此方法只执行一次
        if (self.isResponseUserNotification == YES && offLine == YES) {
            [[TVMPushJumpManager shareInstance]jumpWithUserInfo:dic];
        }
    }
    
    

    2.当在前台的时候,我们收到推送。点击推送
    对于10.0以上系统,我们需要 response.notification.request.identifier来区分。

    - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
        
        TVMLOG(@"didReceiveNotification:%@", response.notification.request.content.userInfo);
        if ([response.notification.request.identifier isEqual:@"TVMLocalPushKey"]) {
            [[TVMPushJumpManager shareInstance]jumpWithUserInfo:response.notification.request.content.userInfo];
        }
        self.isResponseUserNotification = YES;
        // [ GTSdk ]:将收到的APNs信息传给个推统计
        [GeTuiSdk handleRemoteNotification:response.notification.request.content.userInfo];
        completionHandler();
    }
    

    对于9.0以上系统,点击推送

    -(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
        
        if (application.applicationState != UIApplicationStateActive) {
          [[TVMPushJumpManager shareInstance]jumpWithUserInfo:notification.userInfo];
        }
    }
    

    再需要注意的就是对于 NotificationService拓展,这个需要注册bundid和新的描述文件。
    这个目前研究的不深,抽空仔细研究下。

    大体上需要注意的就这些。
    最后一个坑就是,由于手机时间引起的获取不到devicetoken,在后台收不到推送,因为前台走的是个推到透传,在后台走的apns,所以获取不到devicetoken就没办法注册apns,就会在后台收不到推送。
    把手机时间校准就可以收到,深坑啊。

    继续补充
    app在未启动状态下,icon角标的变化。个推目前是不支持+1的,记得以前极光可以的~。

    关于本地推送

    需要注意一些地方,比如说相互覆盖这一点
    在10.0以上系统,注意identifier这个

    + (instancetype)requestWithIdentifier:(NSString *)identifier content:(UNNotificationContent *)content trigger:(nullable UNNotificationTrigger *)trigger;
    

    想要找一群一起进步的人,请加入我

    image.png

    相关文章

      网友评论

          本文标题:『ios』个推集成适配 9.0起步

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