IM消息后台推送

当应用在前台登录后,IM消息通过长连接到达应用。此时,当应用进入后台时,IM消息通过苹果的APNS通道到达。您必须完成以下步骤,才能够收到APNS推送:

  • 制作并上传推送证书,设置证书名
  • 申请DeviceToken
  • 设置并上传DeviceToken,设置对应的证书名
  • 设置处理APNS推送的回调Block
  • 仍然收不到Push?

制作并上传推送证书

iOS的推送依赖于Apple Push Notification Service,即APNS系统。因此要想获得消息推送能力,开发者需要上传iOS Push证书:

  • 您可以在开发者中心上传服务器推送证书,如下图所示:

    • 请注意这里的证书名称是非常重要的,你需要在后面的设置并上传DeviceToken章节中,设置给OpenIMSDK
    • 推荐你使用production作为生产环境的证书名,因为OpenIMSDK运行时默认使用production名称上传DeviceToken
    • 注意:请务必导出p12格式的文件(.cer文件无法用于推送,不要强制将.cer重命名为.p12),并设置非空的导入密码,并且在上传页面中正确填写导入密码。
    • 注意:如果希望上传沙箱证书,请务必将证书名称设置为sand开头

    上传推送证书

  • 关于APNS的更多信息,请参考:Apple的开发者文档

申请DeviceToken

  • **注意:**在iOS10 以上,你需要在Xcode中手动开启push,如图所示:

    image

  • 开发者首先需要在App中向系统申请DeviceToken。

    • 注意:如果你已经实现了申请DeviceToken的代码,则可以跳过这一步。

  • 你需要根据不同的iOS SDK版本及不同的iOS系统,通过不同的函数申请DeviceToken,一般可以在AppDelegatedidFinishLaunchingWithOptions函数中添加如下代码:

    /// 需要区分iOS SDK版本和iOS版本。
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)])
    {
       UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
       [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    
    } else
    #endif
    {
       /// 去除warning
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
       [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
        (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    #pragma clang diagnostic pop
    }
  • 对于iOS8及以上系统,您需要额外添加这个函数实现:

    /// iOS8下申请DeviceToken
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
    {
        if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerForRemoteNotifications)]) {
            [[UIApplication sharedApplication] registerForRemoteNotifications];
        }
    }
    #endif

设置并上传DeviceToken

  • 现在,当你的app获取到DeviceToken时,IMSDK会自动得到该DeviceToken,你无须手动传给IMSDK。

  • 注意点:

    • 你需要在application:didFinishLaunchingWithOptions:函数中手动设置当前打包证书及provision所对应的推送证书名
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    [[[YWAPI sharedInstance] getGlobalPushService] setXPushCertName:@"production1"];
    
    /// 其他初始化代码
    }
    • 请务必确保xcode打包所使用的证书及provision、你设置的证书名以及该证书名对应的推送证书这三者是匹配的。IMSDK的服务端会根据你设置的证书名,查找对应的推送证书进行推送。

    • 成功获取到DeviceToken,登录IM成功后,设备控制台会打印DeviceToken上传成功的Log,请确认是否有该日志

      如何查看设备日志?
      img

处理APNS消息

  • 现在你只需要在-[AppDelegate didFinishLoadingWithOptions:]函数中调用IYWPushServicesetHandlePushBlockV4:方法,在其中根据回调传入的参数,即可完成APNS消息的处理。

    • 注意:如果你使用快速集成文档进行集成,你会在SPKitExample.m中看到`exampleHandleAPNSPush`方法,请参考该方法在Demo中的调用时机。

  • 例如:

    /**
     *  您需要在-[AppDelegate application:didFinishLaunchingWithOptions:]中第一时间设置此回调
     *  在IMSDK截获到Push通知并需要您处理Push时,IMSDK会自动调用此回调
     */
    - (void)exampleHandleAPNSPush
    {
        __weak typeof(self) weakSelf = self;
    
        [[[YWAPI sharedInstance] getGlobalPushService] addHandlePushBlockV4:^(NSDictionary *aResult, BOOL *aShouldStop) {
            BOOL isLaunching = [aResult[YWPushHandleResultKeyIsLaunching] boolValue];
            UIApplicationState state = [aResult[YWPushHandleResultKeyApplicationState] integerValue];
            NSString *conversationId = aResult[YWPushHandleResultKeyConversationId];
            Class conversationClass = aResult[YWPushHandleResultKeyConversationClass];
    
    
            if (conversationId.length <= 0) {
                return;
            }
    
            if (conversationClass == NULL) {
                return;
            }
    
            if (isLaunching) {
                /// 用户划开Push导致app启动
    
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.3f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    if ([self exampleIsPreLogined]) {
                        /// 说明已经预登录成功
                        YWConversation *conversation = nil;
                        if (conversationClass == [YWP2PConversation class]) {
                            conversation = [YWP2PConversation fetchConversationByConversationId:conversationId creatIfNotExist:YES baseContext:weakSelf.ywIMKit.IMCore];
                        } else if (conversationClass == [YWTribeConversation class]) {
                            conversation = [YWTribeConversation fetchConversationByConversationId:conversationId creatIfNotExist:YES baseContext:weakSelf.ywIMKit.IMCore];
                        }
                        if (conversation) {
                            [weakSelf exampleOpenConversationViewControllerWithConversation:conversation fromNavigationController:[weakSelf conversationNavigationController]];
                        }
                    }
                });
    
            } else {
                /// app已经启动时处理Push
    
                if (state != UIApplicationStateActive) {
                    if ([self exampleIsPreLogined]) {
                        /// 说明已经预登录成功
                        YWConversation *conversation = nil;
                        if (conversationClass == [YWP2PConversation class]) {
                            conversation = [YWP2PConversation fetchConversationByConversationId:conversationId creatIfNotExist:YES baseContext:weakSelf.ywIMKit.IMCore];
                        } else if (conversationClass == [YWTribeConversation class]) {
                            conversation = [YWTribeConversation fetchConversationByConversationId:conversationId creatIfNotExist:YES baseContext:weakSelf.ywIMKit.IMCore];
                        }
                        if (conversation) {
                            [weakSelf exampleOpenConversationViewControllerWithConversation:conversation fromNavigationController:[weakSelf conversationNavigationController]];
                        }
                    }
                } else {
                    /// 应用处于前台
                    /// 建议不做处理,等待IM连接建立后,收取离线消息。
                }
            }
        } forKey:self.description ofPriority:YWBlockPriorityDeveloper];
    }

仍然收不到Push?

请按照如下CheckList依次检查每一步是否正确:

  • 已经在百川控制台上传了服务器推送证书,并正确填写了导入密码,并且在该页面测试了可以正常下发push
  • 你的didFinishLaunchingWithOptions函数中调用setXPushCertName:接口设置了证书名
  • 客户端打包所用的证书及provision、setXPushCertName:设置的证书名、在百川后台上传证书时设置的证书名、以及所上传的推送证书,这四项都是匹配的
  • App向系统申请DeviceToken并成功获取,iOS10以上在XCode工程设置界面开启了push
  • IMSDK登录成功,并在设备控制台打印了上传DeviceToken成功的日志
  • 在前台时,IMSDK能够收到在线消息
  • 确认没有在其他端(例如Android,H5)登录该帐号收走消息

如何调试苹果的系统推送

目前OpenIM已经支持使用沙箱环境测试推送:

  • 在上传证书页面,上传沙箱环境的推送证书,命名必须以sand开头,例如sandbox
  • 使用该沙箱证书对应的开发证书进行打包
  • didFinishLaunchingWithOptions中调用setXPushCertName:设置正确的证书名
  • 这时运行后,再收到推送,即可进行调试

FAQ

两个应用直接可以推送吗?跨应用推送

返回
顶部