APNs 推送


前期准备

[[NIMSDK sharedSDK] registerWithAppID:您的APPKEY
                              cerName:您的推送证书名];
- (void)registerAPNs
{
    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerForRemoteNotifications)])
    {
        UIUserNotificationType types = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound |      UIRemoteNotificationTypeAlert;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types
        categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    }
    else
    {
        UIRemoteNotificationType types = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound |        UIRemoteNotificationTypeBadge;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
    }
}
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    [[NIMSDK sharedSDK] updateApnsToken:deviceToken];
}

推送时机

开发者在 发送消息自定义系统通知 时,可以指定是否同时进行推送服务。为了节省不必要的流量开销,只有当接收者的应用切换到后台时,云信推送服务才会开启;如果应用在前台,则不会有推送通知。如果有应用前台通信需求,建议开发者使用 自定义系统通知 ,并监听回调:

- (void)onReceiveCustomSystemNotification:(NIMCustomSystemNotification *)notification;

属性设置

NIM SDK 提供全局 APNS 属性设置,用于设置免打扰时间和推送样式,详细内容可以参考 NIMPushNotificationSetting

NIMPushNotificationSetting *setting =  [[[NIMSDK sharedSDK] apnsManager] currentSetting];
[[[NIMSDK sharedSDK] apnsManager] updateApnsSetting:setting
completion:^(NSError *error) {}];

APNS 多端设置 NIMPushNotificationMultiportConfig

- (NIMPushNotificationMultiportConfig *)currentConfig;
- (void)updateConfig:(NIMPushNotificationMultiportConfig *)config
          completion:(NIMApnsHandler)completion;

当桌面端在线时,可以通过设置 shouldPushNotificationWhenPCOnline 字段,控制是否需要发推送给手机端。

消息的推送设置

设置 NIMMessageapnsPayload 可以自定义推送参数。

用户在发送消息的时候,设置 NIMMessageapnsContent 属性进行消息推送内容设置。如果不设置 apnsContent 属性,将使用云信内置文案。

属性原型

@interface NIMMessage : NSObject
/**
 *  消息推送文案,长度限制200字节
 */
@property (nullable,nonatomic,copy)                  NSString *apnsContent;
@end

示例代码:

NIMAudioObject *audioObject = [[NIMAudioObject alloc] initWithSourcePath:filePath];
NIMMessage *message = [[NIMMessage alloc] init];
message.messageObject = audioObject;
message.apnsContent = @"发来了一段语音";    //对方收到的推送文案

此时,对方的手机将会收到一条苹果推送,内容形式为 "昵称:"+"推送文案"。如果只需要推送文案的话,也可以将昵称部分隐藏

示例代码:

NIMMessage *message = [[NIMMessage alloc] init];
message.text = @"消息示例";
message.apnsContent = @"推送消息示例";    //对方收到的推送文案 
NIMMessageSetting *setting = [[NIMMessageSetting alloc] init];
setting.apnsWithPrefix = NO;
message.setting = setting;

如果本条消息不需要苹果推送,还可以将推送关闭

示例代码

NIMMessage *message = [[NIMMessage alloc] init];
message.text = @"不带推送的消息示例";
NIMMessageSetting *setting = [[NIMMessageSetting alloc] init];
setting.apnsEnabled = NO;
message.setting = setting;

默认情况下,消息的推送会让程序未读数加 1 。 具体表现为:如果程序在后台,则应用 icon 的 badge 上累加;当程序进入前台时,此消息被计入 SDK 的未读数,所在会话的 unreadCount 将会累加。

在发送时,可以设置将消息不计入未读数。示例代码

NIMMessage *message = [[NIMMessage alloc] init];
message.text = @"没有未读数的消息示例";
NIMMessageSetting *setting = [[NIMMessageSetting alloc] init];
setting.shouldBeCounted = NO;
message.setting = setting;

苹果推送所附带的未读数是通过设置推送 payload 里的 badge 参数。在云信 服务中,不支持直接设置 badge ,服务器会维护对每个用户维护一个当前未读数,当服务器收到一条未读消息后,会自动在未读数上累加后填入推送的 badge 字段推送给接收端。

开发者应该在程序每次推到后台时,统计本地所有未读,并设置 badge , 保证程序在前后台未读数一致

示例:

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSInteger count = [[[NIMSDK sharedSDK] conversationManager] allUnreadCount];
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:count];
}

如果应用本身除了云信未读之外还有其他未读的话,程序上的 icon 值应为 云信未读数 + 其他未读数 之和,但是由于云信服务器默认维护的未读数只有消息的未读数,这样会导致新来的消息推送未读数将不计入应用的其他未读。

这种情况下,需要客户端提交服务器应该管理的未读数。

原型

@protocol NIMApnsManager <NSObject>
/**
 *  注册获取 badge 数量的回调函数
 *
 *  @param handler 获取 badge 回调
 */
- (void)registerBadgeCountHandler:(NIMBadgeHandler)handler;
@end

在 NIMBadgeHandler 回调中,返回当前的未读数即可。SDK 会在合适的时机调用这个 block 。

消息推送的声音设置支持自定义,类似于推送的 payload , 开发者只需要将设置 key 为 sound 并以音频名为字符串 key , 填入消息的 apnsPayload 字段即可。需要注意推送音频的具体格式。具体请参考苹果官方文档

示例

NIMMessage *message = [[NIMMessage alloc] init];
message.text = @"消息示例";
message.apnsContent = @"发来了一条信息";
message.apnsPayload = @{@"sound":@"message.wav"};

推送可以在 payload 里附带其他信息,比如推送的消息 Id , 所在的会话等等,方便接收端收到推送后直接跳转。同样只需要在 apnsPayload 中设置即可。

示例

NIMMessage *message  = [[NIMMessage alloc] init];
message.text = @"消息示例";
message.apnsContent = @"发来了一条信息";
message.apnsPayload = @{@"sound":@"message.wav",@"messageId":message.messageId,@"balabala":@"pilipala"};

payload 结构

{
    aps =     {
        alert = "xxxxx";
        badge = 85;
        sound = default;
    };
    nim = 1;
}

其中 aps 为推送 payload 字段,包含了预定义的字段和自定义字段。 nim = 1 表示此条推送来自于云信推送,客户端可以根据这个键值对判断推送来源。

消息的成员推送选项

用户在发消息的时候,可以通过配置 NIMMessage 里的 apnsMemberOption 字段实现更为复杂的推送逻辑,目前这个字段只能在群会话中生效。

系统通知的推送设置

自定义系统通知也可以附带推送,字段结构流程与消息相同。

推送内容:

@interface NIMCustomSystemNotification : NSObject
/**
 *  apns推送文案
 *  @discussion 默认为nil,用户可以设置当前通知的推送文案
 */
@property (nullable,nonatomic,copy)                  NSString *apnsContent;
@end

推送 payload

@interface NIMCustomSystemNotification : NSObject
/**
 *  apns推送Payload
 *  @discussion 可以通过这个字段定义自定义通知的推送Payload,支持字段参考苹果技术文档,最多支持2K
 */
@property (nullable,nonatomic,copy)                  NSDictionary *apnsPayload;
@end

PushKit

PushKit 作为苹果公司在 iOS8 系统及以上引入的新类型推送,也被称作 voip push 。顾名思义,这种推送可以帮助我们提升 voip 应用的体验,优化 voip 应用的开发实现,降低 voip 应用的电量消耗。

基于这种类型的推送,开发者不必在后台设法维护一套长连接来保证接通率,客户端在收到推送的时候,会自动后台唤起应用,可以在此时完成云信相关的业务注册,展开正常的 voip 业务。开发者甚至可以在 PushKit 基础上, 借助 CallKit 搭建出一套呼叫界面,让应用拥有媲美原生来电通话的用户体验。

目前通过在云信后台配置 PushKit 证书,点对点电话呼叫接口推送将会使用 PushKit 。PushKit 证书配置与 APNS 证书配置雷同,这里不再展开。

在客户端实现中,需要将接口

- (void)registerWithAppID:(NSString *)appKey
                  cerName:(nullable NSString *)cerName

变更为

- (void)registerWithOption:(NIMSDKOption *)option

注册 PushKit 推送

PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];

在 PKPushRegistryDelegate 协议回调中,调用云信上传 PushKit Token 接口:

- (void)updatePushKitToken:(NSData *)token
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type
{
    if ([type isEqualToString:PKPushTypeVoIP])
    {
        [[NIMSDK sharedSDK] updatePushKitToken:credentials.token];
    }
}

推送问题排查方案

请参考云信IOS推送收不到问题排查方案