差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
im:ios:apns:deploy [2019/09/30 10:23] huanxinfudh [客户端如何申请DeviceToken] |
im:ios:apns:deploy [2022/03/01 08:10] jennifer.zeng [APNs推送] |
||
---|---|---|---|
行 1: | 行 1: | ||
====== APNs推送 ======= | ====== APNs推送 ======= | ||
+ | 更新时间:2022-01-15 | ||
+ | |||
+ | 新版文档见:[[ccim:ios:push|iOS 推送设置]]。 | ||
===== SDK的运行状态 ===== | ===== SDK的运行状态 ===== | ||
* 当 App 在前台可见的时候,SDK 处于前台活跃状态,此时是使用 SDK 长连接接收消息。 | * 当 App 在前台可见的时候,SDK 处于前台活跃状态,此时是使用 SDK 长连接接收消息。 | ||
| | ||
- | * 当 App 进入后台且在2分钟之内的时候,SDK 处于后台活跃状态,此时是使用 SDK 长连接接收消息(用户根据需要实现本地通知,否则将不会有本地通知提示弹出)。 | + | * 当 App 进入后台,短时间内 SDK 处于后台活跃状态,此时是使用 SDK 长连接接收消息(用户根据需要实现本地通知,否则将不会有本地通知提示弹出)。 |
| | ||
- | * 当 App 进入后台超过2分,被系统挂起,此时 SDK 处于不活跃状态,或者是主动把App进程杀死,此时如果有新消息,是通过苹果的 APNs 服务进行提醒的。当 App 再次启动,SDK 会去服务器拉取不活跃期间的消息。 | + | * 当 App 进入后台被系统挂起,此时 SDK 处于不活跃状态,或者是主动把App进程杀死,此时如果有新消息,是通过苹果的 APNs 服务进行提醒的。当 App 再次启动,SDK 会去服务器拉取不活跃期间的消息。 |
**注意:**''由于本地通知和 APNs 不好区分,调试时建议您将 App 进程杀死,确保所有的提醒都是来自于 APNs 推送。'' | **注意:**''由于本地通知和 APNs 不好区分,调试时建议您将 App 进程杀死,确保所有的提醒都是来自于 APNs 推送。'' | ||
行 27: | 行 30: | ||
首先,登录苹果的开发者中心。 | 首先,登录苹果的开发者中心。 | ||
创建App | 创建App | ||
- | + | {{:im:ios:apns:apns_setting_1.jpg?800|}} | |
- | {{:im:300iosclientintegration:apns_create1.jpg?800|}} | + | {{:im:ios:apns:apns_setting_2.jpg?800|}} |
+ | {{:im:ios:apns:apns_setting_3.jpg?800|}} | ||
为App命名,此处bundle id不能用通配符,否则无法收到推送。 | 为App命名,此处bundle id不能用通配符,否则无法收到推送。 | ||
- | {{:im:300iosclientintegration:apns_create2.jpg?800|}} | + | {{:im:ios:apns:apns_setting_4.jpg|}} |
打开推送功能 | 打开推送功能 | ||
- | {{:im:300iosclientintegration:apns_create3.jpg?800|}} | + | {{:im:ios:apns:apns_setting_5.jpg|}} |
- | {{:im:300iosclientintegration:apns_create4.jpg?800|}} | + | {{:im:ios:apns:apns_setting_6.jpg|}} |
创建推送证书 | 创建推送证书 | ||
- | {{:im:300iosclientintegration:apns_create5.jpg?800|}} | + | {{:im:ios:apns:apns_setting_7.jpg|}} |
- | 如果您是测试开发环境,选择development下的Apple Push Notification service SSL(如果是生产,则需要选择Production下的) | + | 如果您是测试开发环境,选择Services下的Apple Push Notification service SSL(Sandbox),如果是生产环境,则需要选择Services下的Apple Push Notification service SSL(Sandbox & Production) |
- | {{:im:300iosclientintegration:apns_create6.jpg?800|}} | + | {{:im:ios:apns:apns_setting_8.jpg|}} |
选择证书所属的App | 选择证书所属的App | ||
- | {{:im:300iosclientintegration:apns_create7.jpg?800|}} | + | {{:im:ios:apns:apns_setting_9.jpg|}} |
上传CSR文件 | 上传CSR文件 | ||
- | {{:im:300iosclientintegration:apns_create8.jpg?800|}} | + | {{:im:ios:apns:apns_setting_10.jpg|}} |
下面,我们来创建一个CSR文件,首先,选择"钥匙串访问" | 下面,我们来创建一个CSR文件,首先,选择"钥匙串访问" | ||
行 74: | 行 78: | ||
点击继续,会得到一个下载页面。 | 点击继续,会得到一个下载页面。 | ||
- | {{:im:300iosclientintegration:apns_create13.jpg?800|}} | + | {{:im:ios:apns:apns_setting_11.jpg|}} |
- | {{:im:300iosclientintegration:apns_create14.jpg?800|}} | + | {{:im:ios:apns:apns_setting_12.jpg|}} |
点击下载,就会下载一个aps_development.cer。(production的是aps.cer) | 点击下载,就会下载一个aps_development.cer。(production的是aps.cer) | ||
行 95: | 行 99: | ||
此处需要记住密码,后面需要用到。 | 此处需要记住密码,后面需要用到。 | ||
+ | ''注意:导出p12证书时,设置证书的密码长度不要超过20个字符,建议使用纯英文或者数字组合,不建议带特殊字符'' | ||
{{:im:300iosclientintegration:apns_create19.jpg?800|}} | {{:im:300iosclientintegration:apns_create19.jpg?800|}} | ||
行 125: | 行 130: | ||
为证书起名,并记住名称,后续有用。选择上传证书,将上一步中生成的P12文件上传,并设置导出时设置的密码。选择证书类型,此处是【开发环境】(如果之前用的是production,则此处应该选择生产)。填写应用包名,应为**bundle id**,点击上传,完成上传证书操作。 | 为证书起名,并记住名称,后续有用。选择上传证书,将上一步中生成的P12文件上传,并设置导出时设置的密码。选择证书类型,此处是【开发环境】(如果之前用的是production,则此处应该选择生产)。填写应用包名,应为**bundle id**,点击上传,完成上传证书操作。 | ||
+ | |||
+ | ''注意:证书的名称和密码的长度不要超过20个字符,建议使用纯英文或者数字组合,不建议带特殊字符'' | ||
{{:im:ios:apns:ios证书.png?nolink|}} | {{:im:ios:apns:ios证书.png?nolink|}} | ||
行 149: | 行 156: | ||
2、 将得到的deviceToken传到SDK | 2、 将得到的deviceToken传到SDK | ||
+ | ''如果是iOS13及以上的系统,请将SDK更新到v3.6.4或以上版本'' | ||
<code> | <code> | ||
- | iOS 13之前: | ||
// 将得到的deviceToken传给SDK | // 将得到的deviceToken传给SDK | ||
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken | ||
行 156: | 行 163: | ||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
[[EMClient sharedClient] bindDeviceToken:deviceToken]; | [[EMClient sharedClient] bindDeviceToken:deviceToken]; | ||
- | }); | ||
- | } | ||
- | |||
- | iOS 13: | ||
- | // 将得到的deviceToken传给SDK | ||
- | - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken | ||
- | { | ||
- | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
- | const unsigned *tokenBytes = [deviceToken bytes]; | ||
- | NSString *token = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x", | ||
- | ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]), | ||
- | ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]), | ||
- | ntohl(tokenBytes[6]), ntohl(tokenBytes[7])]; | ||
- | [[EMClient sharedClient] bindDeviceToken:token]; | ||
}); | }); | ||
} | } | ||
</code> | </code> | ||
- | **注:必须是真机,模拟器不支持APNs** | + | **注:必须是真机,模拟器不支持APNs。APNs 注册失败,一般是由于使用了通用证书或者是模拟器调试导致,请检查证书并用真机调试。此处是 iOS 系统报的错,如仍不能确定,请从网上查找相关资料。** |
==== 客户端如何配置推送证书 ==== | ==== 客户端如何配置推送证书 ==== | ||
行 187: | 行 180: | ||
</code> | </code> | ||
+ | |||
+ | ===== 使用在线推送通道 ===== | ||
+ | |||
+ | 与APNs离线推送使用苹果厂商推送通道不同,在线推送通道使用环信长连接接收推送,之后以本地通知的形式展示推送消息,可以有效提升推送到达率。 | ||
+ | 集成在线推送过程如下: | ||
+ | - 申请本地通知权限 | ||
+ | - 启用SDK在线推送 | ||
+ | - 处理Delegate | ||
+ | |||
+ | ==== 申请本地通知权限 ==== | ||
+ | 由于要使用本地通知展示推送消息,你需要在App中需要申请权限,过程如下: | ||
+ | <code> | ||
+ | UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; | ||
+ | [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) { | ||
+ | | ||
+ | }]; | ||
+ | </code> | ||
+ | |||
+ | ==== 启用SDK在线推送 ==== | ||
+ | 在启用APNs在线推送前,你需要完成IM SDK的初始化工作 | ||
+ | |||
+ | SDK初始化完成后,启用APNs在线推送过程如下: | ||
+ | <code> | ||
+ | [[EMLocalNotificationManager sharedManager] launchWithDelegate:self]; | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||
+ | ==== 处理Delegate ==== | ||
+ | 在启用在线通道过程中,SDK会重写**[UNUserNotificationCenter currentNotificationCenter]**的delegate,如果要处理其他本地通知,需要实现**EMLocalNotificationDelegate**,过程如下 | ||
+ | <code> | ||
+ | #pragma mark - EMLocalNotificationDelegate | ||
+ | - (void)emuserNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler | ||
+ | { | ||
+ | // // 这里处理其他本地通知 | ||
+ | completionHandler(UNNotificationPresentationOptionAlert); | ||
+ | } | ||
+ | - (void)emuserNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler | ||
+ | { | ||
+ | NSDictionary* userInfo = response.notification.request.content.userInfo; | ||
+ | // 这里处理其他本地通知 | ||
+ | completionHandler(); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ==== 进阶 ==== | ||
+ | iOS的本地通知管理模块**UNUserNotificationCenter**是单例,一个App | ||
+ | 中只能有一个实例,如果在启用SDK在线推送之后,App又重写了**[UNUserNotificationCenter currentNotificationCenter].delegate**,会把SDK中的delegate覆盖掉,此时需要在App实现的**UNUserNotificationCenterDelegate**中,调用SDK的相关处理,过程如下 | ||
+ | <code> | ||
+ | #pragma mark - UNUserNotificationCenterDelegate | ||
+ | |||
+ | - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler | ||
+ | { | ||
+ | // 处理其他通知 | ||
+ | ... | ||
+ | // 调用SDK推送在线通道处理 | ||
+ | [[EMLocalNotificationManager sharedManager] userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler]; | ||
+ | } | ||
+ | |||
+ | - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler | ||
+ | { | ||
+ | | ||
+ | // 处理其他通知 | ||
+ | ... | ||
+ | // 调用SDK推送在线通道处理 | ||
+ | [[EMLocalNotificationManager sharedManager] userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; | ||
+ | } | ||
+ | </code> | ||
===== 常见问题 ===== | ===== 常见问题 ===== | ||
==== 如何实现本地通知 ==== | ==== 如何实现本地通知 ==== |