diff --git a/agora_chat_en_draft/android/1_overview.md b/agora_chat_en_draft/android/1_overview.md new file mode 100644 index 0000000..867ea1e --- /dev/null +++ b/agora_chat_en_draft/android/1_overview.md @@ -0,0 +1,38 @@ +# 离线推送概述 + +即时通讯 IM 支持集成 FCM 消息推送服务,为 Android 开发者提供低延时、高送达、高并发、不侵犯用户个人数据的离线消息推送服务。 + +客户端断开连接或应用进程被关闭等原因导致用户离线时,即时通讯 IM 会通过 FCM 消息推送服务向该离线用户的设备推送消息通知。当用户再次上线时,服务器会将离线期间的消息发送给用户(这里角标表示的是离线消息数,并不是实际的未读消息数)。例如,当你离线时,有用户向你发送了消息,你的手机的通知中心会弹出消息通知,当你再次打开 app 并登录成功,即时通讯 IM SDK 会主动拉取你不在线时的消息。 + +若应用在后台运行且用户仍为在线状态,即时通讯 IM 不会向用户推送消息通知。多设备登录时,可在声网控制台的 **Push Certificate** 页面配置推送在所有设备离线或任一设备离线时发送推送消息,该配置对所有推送通道生效。 + +
1. 应用在后台运行或手机锁屏等情况,若客户端未断开与声网服务器的连接,则即时通讯 IM 不会收到离线推送通知。
2. 多端登录时若有设备被踢下线,即使接入了 IM 离线推送,也收不到离线推送消息。
+ +除了满足用户离线条件外,要使用 FCM 离线推送,用户还需声网控制台配置 FCM 推送证书信息,例如 **Private Key** 和 **Certificate Name**,并调用客户端 SDK 提供的 API 向声网服务器上传 device token。 + +要体验离线推送功能,请点击[这里](https://download.agora.io/sdk/release/agorachatdemo_android_1.1.0.apk)下载即时推送 IM 的 demo。 + +## 推送流程 + +![](push_fcm_flow.png) + +消息推送流程如下: + +1. 用户 B 初始化 FCM 推送 SDK,检查是否使用了 FCM 推送。 +2. 用户 B 根据配置的 FCM 推送 SDK 从 FCM 推送服务器获取 device token。 +3. FCM 推送服务器向用户 B 返回 device token。 +4. 用户 B 向声网即时通讯服务器上传推送证书名称和 device token。 +5. 用户 A 向 用户 B 发送消息。 +6. 声网即时通讯服务器检查用户 B 是否在线。若在线,声网即时通讯服务器直接将消息发送给用户 B。 +7. 若用户 B 离线,声网即时通讯服务器判断该用户是否使用了 FCM 推送。 +8. 声网即时通讯服务器将消息发送给 FCM 推送服务器。 +9. FCM 推送服务器将消息发送给用户 B。 + +
device token 是 FCM 推送提供的推送 token,即初次启动你的应用时,FCM SDK 为客户端应用实例生成的注册令牌 (registration token)。该 token 用于标识每台设备上的每个应用,FCM 通过该 token 明确消息是发送给哪个设备的,然后将消息转发给设备,设备再通知应用程序。你可以调用 FirebaseMessaging.getInstance().getToken() 方法获得 token。另外,如果退出即时通讯 IM 登录时不解绑 device token(调用 `logout` 方法时对 `unbindToken` 参数传 `false` 时不解绑 device token,传 `true` 表示解绑 token),用户在推送证书有效期和 token 有效期内仍会接收到离线推送通知。
+ +## 前提条件 + +使用 FCM 推送前,确保满足以下条件: + +- 已开启即时通讯 IM ,详见[开启和配置即时通讯服务](./enable_agora_chat)。 +- 了解即时通讯 IM 套餐包中的 API 调用频率限制,详见[使用限制](./agora_chat_limitation)。 \ No newline at end of file diff --git a/agora_chat_en_draft/android/2_integration_test.md b/agora_chat_en_draft/android/2_integration_test.md new file mode 100644 index 0000000..f99a6b4 --- /dev/null +++ b/agora_chat_en_draft/android/2_integration_test.md @@ -0,0 +1,254 @@ +# 在即时通讯 IM 中集成 FCM 并测试推送 + +本页介绍如何在即时通讯 IM 中集成 FCM 并测试推送是否成功集成。 + +## 集成 FCM 推送 + +Note: Currently, the official Chat website shows the latest configuration on the Firebase Console and Agora Console. +Therefore, you can ignore this part enclosed by "///////////////" during translation. +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +按以下步骤在即时通讯 IM 中集成 FCM: + +1. 在 [Firebase 控制台](https://console.firebase.google.com/)创建 Android 项目。 +2. 在[声网控制台](https://console.agora.io/)上传 FCM 推送证书。 +3. 在客户端集成 FCM。 + +
对于使用 Android 系统的设备,若同时开启了 FCM 和其他厂商的推送服务,优先使用 FCM 推送服务。
+ + +### 在 Firebase 控制台创建 Android 项目 + +1. 登录 [Firebase 控制台](https://console.firebase.google.com/),[添加项目](https://firebase.google.com/docs/android/setup/#create-firebase-project)。 + +2. 在项目中[注册应用](https://firebase.google.com/docs/android/setup/#register-app)。 + + 在 **Add Firebase to your Android app** 页面中的 **Download and then add config file** 步骤中,点击 **Download google-services.json**,将该文件放入你的 Android 应用模块的根目录。 + + [img](push_fcm_download_googleservice.png) + +3. 查询 Sender ID。在 **Project settings** 页面,选择 **Cloud Messaging** 页签,查看 **Server ID**。在声网控制台上传 FCM 证书时,需要将证书名称设置为 FCM 的发送者 ID。 + + [img](push_fcm_senderid.png) + +4. 在 **Project settings** 页面,选择 **Service accounts** 页签,点击 **Generate new private key** 按钮生成密钥(JSON 文件)。请保存该文件,使用 V1 证书时需在声网控制台上传该文件。 + + [img](push_fcm_private_key.png) + +### 在声网控制台上传 FCM 推送证书 + +登录即时通讯 IM SDK 成功后,可在声网控制台上传 FCM 推送证书。 + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Certificate**。 +5. 在 **Push Certificate** 页面,单击 **Add Push Certificate**。在弹出的对话框中,选择 **Google** 页签,配置字段,单击**保存**。 + +[img](push_fcm_add_certificate.png) + +| 参数 | 类型 | 是否必需 | 描述 | +| :--------- | :----- | :------- | :----------------------- | +| **Certificate Type** | | 否 | 选择使用旧版证书还是 V1 证书。| +| **Private Key** | file | 是 | 点击 **Upload** 上传推送证书文件(.json)。你需要在 Firebase 控制台的 **Project settings** > **Service accounts** 页面点击 **Generate new private key** 生成推送证书文件(.json)。 | +| **Push Key** | String | 是 | FCM 的服务器密钥(Server Key)。你需在 Firebase 控制台的 **Project settings** > **Cloud Messaging** 页面,在 **Cloud Messaging API (Legacy)** 区域中获取服务器密钥。**该参数仅对旧版本证书有效。**| +| **Certificate Name** | String | 是 | 配置为 FCM 的发送者 ID。
证书名称是声网即时通讯服务器用于判断目标设备使用哪种推送通道的唯一条件,因此必须确保你[在即时通讯 IM 中集成 FCM 时设置的 Sender ID](#initialization)与这里设置的一致。 | +| **Sound** | String | 否 | 接收方收到推送通知时的铃声标记。| +| **Push Priority** | | 否 | 消息传递优先级,详见 [FCM 官网](https://firebase.google.cn/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message)。 | +| **Push Msg Type** | | 否 | 通过 FCM 向客户端发送的消息的类型,详见 [FCM 消息简介](https://firebase.google.cn/docs/cloud-messaging/concept-options#notifications_and_data_messages) 。| + +#### **旧版证书无缝切换至 V1 证书** + +旧版 HTTP 或 XMPP API 于 2024 年 6 月 20 日停用,请尽快切换到最新的 FCM API(HTTP v1)版本证书。详见 [FCM 控制台](https://console.firebase.google.com)。请确保切换过程中上传的 V1 证书可用,因为执行转换证书后,旧证书会被删除,若此时新证书不可用会导致推送失败。 + +你可以参考以下步骤从旧版证书无缝切换到 V1 新证书: + +1. 在 **Push Certificate** 页面的旧版证书的 **Action** 栏中点击 **Edit**。 + +![image](push_fcm_oldcertificate_edit.png) + +2. 在 **Edit Push Certificate** 窗口的 **Google** 页签,将**Certificate Type**切换为 **V1**。 + +![image](push_fcm_oldcertificate_switch.png) + +3. 点击 **Upload** 上传本地保存的 V1 证书文件(.json)。 + +![fcmapp](push_fcm_newcertificate_upload.png) + +4. 点击 **OK** 完成切换。 + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +### 在客户端集成 FCM + +1. 在你的 app 项目的 build.gradle 文件中,配置 FCM 库的依赖: + +```gradle +plugins { + id 'com.android.application' + // Add the Google services Gradle plugin + id 'com.google.gms.google-services' +} + +dependencies { + // ... + // 导入 Firebase BoM。 + implementation platform('com.google.firebase:firebase-bom:28.4.1') + // 声明 FCM 的依赖。 + // 使用 BoM 时,不要在 Firebase 库依赖中指定版本。 + implementation 'com.google.firebase:firebase-messaging' +} +``` + +在你的根级(项目级)Gradle 文件 (/build.gradle): + +```gradle +plugins { + // ... + + // Add the dependency for the Google services Gradle plugin + id 'com.google.gms.google-services' version '4.3.15' apply false + +} +``` + +对于 Gradle 5.0 及以上版本,BoM 自动开启,而对于 Gradle 5.0 之前的版本,你需要开启 BoM 特性。详见[Firebase Android BoM](https://firebase.google.cn/docs/android/learn-more#bom)和[Firebase Android SDK Release Notes](https://firebase.google.cn/support/release-notes/android)。 + +2. 将你的项目与 gradle 文件同步,扩展 `FirebaseMessagingService`,并将其在项目的 `AndroidManifest.xml` 文件中注册。 + +```java +public class FCMMSGService extends FirebaseMessagingService { + private static final String TAG = "FCMMSGService"; + + @Override + public void onMessageReceived(RemoteMessage remoteMessage) { + super.onMessageReceived(remoteMessage); + if (remoteMessage.getData().size() > 0) { + String message = remoteMessage.getData().get("alert"); + Log.d(TAG, "onMessageReceived: " + message); + } + } + + @Override + public void onNewToken(@NonNull String token) { + super.onNewToken(token); + Log.d(TAG, "onNewToken: " + token); + ChatClient.getInstance().sendFCMTokenToServer(token); + } +} +``` + +```xml + + + + + +``` + +3. 初始化即时通讯 IM SDK 并开启 FCM。 + +```java +ChatOptions options = new ChatOptions(); +... +PushConfig.Builder builder = new PushConfig.Builder(this); +// 替换为你的 FCM 的 Sender ID。 +builder.enableFCM("Your FCM sender id"); +// 在 ChatOptions 类中配置推送设置。 +options.setPushConfig(builder.build()); +// 初始化即时通讯 IM SDK。 +ChatClient.getInstance().init(this, options); +// 设置推送监听。 +PushHelper.getInstance().setPushListener(new PushListener() { + @Override + public void onError(PushType pushType, long errorCode) { + EMLog.e("PushClient", "Push client occur a error: " + pushType + " - " + errorCode); + } + @Override + public boolean isSupportPush(PushType pushType, PushConfig pushConfig) { + // 设置是否开启 FCM。 + if(pushType == PushType.FCM) { + return GoogleApiAvailabilityLight.getInstance().isGooglePlayServicesAvailable(MainActivity.this) + == ConnectionResult.SUCCESS; + } + return super.isSupportPush(pushType, pushConfig); + } +}); +``` + +4. 将 FCM 的 device token 传递给服务器。 + +在应用初始化时,FCM SDK 会为用户的设备上的客户端应用生成唯一的注册 token。由于 FCM 使用该 token 确定要将推送消息发送给哪个设备,因此,声网服务器需要获得客户端应用的注册 token 才能将通知请求发送给 FCM,然后 FCM 验证注册 token,将通知消息发送给 Android 设备。建议该段代码放在成功登录即时通讯 IM 后的主页面。 + +```java +// 检查是否启用了 FCM。 +if(GoogleApiAvailabilityLight.getInstance().isGooglePlayServicesAvailable(MainActivity.this) != ConnectionResult.SUCCESS) { + return; +} +FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (!task.isSuccessful()) { + EMLog.d("PushClient", "Fetching FCM registration token failed:"+task.getException()); + return; + } + // 获取 FCM 的注册 token,即 device token。 + String token = task.getResult(); + EMLog.d("FCM", token); + ChatClient.getInstance().sendFCMTokenToServer(token); + } +}); +``` + +5. 监控 device token 生成。 + +FCM SDK 成功生成注册 token(device token)后,会传递给 `onNewToken` 回调。 + +重写 `FirebaseMessagingService` 中的 `onNewToken` 回调。device token 生成后,该回调会及时将新 token 更新到即时通讯 IM SDK。 + +```java +@Override +public void onNewToken(@NonNull String token) { + Log.i("MessagingService", "onNewToken: " + token); + // 若要向该应用发送消息或在服务器端管理应用订阅,需向你的 App Server 发送 FCM 注册 token。 + if(ChatClient.getInstance().isSdkInited()) { + ChatClient.getInstance().sendFCMTokenToServer(token); + } +} +``` + +## 测试 FCM 推送 + +在即时通讯 IM 中集成并启用 FCM 后,可测试推送是否成功集成。 + +### 前提条件 + +准备一台在海外正式发售的 Android 设备用于接收推送通知,确保该设备满足以下条件: +- 使用国外 IP 地址与即时通讯 IM 建立连接。 +- 支持 Google GMS 服务(Google Mobile Services)。 +- 可以正常访问 Google 网络服务,否则该设备无法从 FCM 服务接收推送通知。 + +为了确保测试效果可靠,请避免使用模拟器进行测试。 + +### 测试步骤 + +1. 在设备上登录应用,并确认 device token 绑定成功。 + 可以查看日志或调用[获取用户详情的 RESTful 接口](https://docs.agora.io/en/agora-chat/restful-api/user-system-registration#querying-a-user)确认 device token 是否绑定成功。成功后在 `entities` 字段下会有 `pushInfo` 字段,且 `pushInfo` 下会有 `device_Id`、`device_token`、`notifier_name` 等相关信息 +2. 开启应用通知栏权限。 +3. 杀掉应用进程。 +4. 在声网控制台发送测试消息。 + 在左侧导航栏中选择 **Operation Management** > **User**。在 Users 页面中,在对应用户 ID 的 **Action** 栏中选择 **Send Admin Message**。在弹出的对话框中选择消息类型,输入消息内容,然后点击 **Send**。 + +
在 **Push Certificate** 页面中证书列表中,在每个证书的 **Action** 一栏中,点击 **More**,会出现 **Test**,这里是直接调用第三方接口推送,而 **Users** 页面中的消息发送测试是先调用即时通讯 IM 的发消息的接口,满足条件后(即用户离线、推送证书有效且绑定了 device token)再调第三方的接口进行推送。
+ +5. 查看设备是否收到推送通知。 + +### 故障排除 + +1. 检查在即时通讯 IM 中是否正确集成或启用了 FCM 推送。 + 在左侧导航栏中选择 **Operation Management > User**。在用户管理页面中,在对应用户 ID 的 **Action** 栏中选择 **Push Certificate**。在弹出框中查看是否正确显示了证书名称和 device token。 +2. 检查是否在声网控制台上传了正确的 FCM 证书。 +3. 检查是否在聊天室中推送消息。聊天室不支持离线消息推送。 +4. 检查设备是否为国行手机的 ROM。一些品牌的国产手机不支持 GMS 服务,需替换为海外发售的设备。 +5. 检查发送消息时是否设置了只发在线(deliverOnlineOnly = true)。只发在线的消息不推送。 \ No newline at end of file diff --git a/agora_chat_en_draft/android/3_parsing.md b/agora_chat_en_draft/android/3_parsing.md new file mode 100644 index 0000000..558abb5 --- /dev/null +++ b/agora_chat_en_draft/android/3_parsing.md @@ -0,0 +1,70 @@ +# 解析 FCM 推送字段 + +收到推送通知后,你需要解析数据。 + +重写 `FirebaseMessagingService.onMessageReceived` 方法可以在 `RemoteMessage` 对象中获取自定义扩展字段,示例代码如下: + +```java +public class FCMMSGService extends FirebaseMessagingService { + @Override + public void onMessageReceived(RemoteMessage remoteMessage) { + super.onMessageReceived(remoteMessage); + if (remoteMessage.getData().size() > 0) { + String f = remoteMessage.getData().get("f"); + String t = remoteMessage.getData().get("t"); + String m = remoteMessage.getData().get("m"); + String g = remoteMessage.getData().get("g"); + Object e = remoteMessage.getData().get("e"); + } + } + + @Override + public void handleIntent(@NonNull Intent intent) { + super.handleIntent(intent); + Bundle bundle = intent.getExtras(); + if (bundle != null) { + Map map = new HashMap<>(); + for (String key : bundle.keySet()) { + if (!TextUtils.isEmpty(key)) { + Object content = bundle.get(key); + map.put(key, content); + } + } + Log.i(TAG, "handleIntent: " + map); + } + } +} +``` + +| 参数 | 描述 | +| ------- | -------------- | +| `f` | 推送通知的发送方的用户 ID。 | +| `t` | 推送通知的接收方的用户 ID。 | +| `m` | 消息 ID。消息唯一标识符。 | +| `g` | 群组 ID,仅当消息为群组消息时,该字段存在。 | +| `e` | 用户自定义扩展字段。 | + +其中 `e` 为完全用户自定义扩展,数据来源为消息扩展的 `em_push_ext.custom`,数据结构如下: + +```json +{ + "em_push_ext": { + "custom": { + "key1": "value1", + "key2": "value2" + } + } +} +``` + +`RemoteMessage` 对象中的扩展信息的数据结构如下: + +```java +{ + "t":"receiver", + "f":"fromUsername", + "m":"msg_id", + "g":"group_id", + "e":{} +} +``` \ No newline at end of file diff --git a/agora_chat_en_draft/android/4_push_display.md b/agora_chat_en_draft/android/4_push_display.md new file mode 100644 index 0000000..6bc00f7 --- /dev/null +++ b/agora_chat_en_draft/android/4_push_display.md @@ -0,0 +1,178 @@ +# 设置推送通知的显示内容 + +通知收到后,通知栏中显示的推送标题和内容可通过以下方式设置,配置的优先级为由低到高: + +1. 设置推送通知的显示属性; +2. 使用默认推送模板; +3. 使用消息扩展字段; +4. 使用自定义推送模板。 + +## 设置推送通知的显示属性 + +你可以分别调用 `updatePushNickname` 和 `updatePushDisplayStyle` 方法设置推送通知中显示的昵称(`nickname`)和通知显示样式(`DisplayStyle`),确定通知栏中的推送标题和推送内容。 + +```java +// 需要异步处理。 +ChatClient.getInstance().pushManager().updatePushNickname("nickname"); +``` + +```java +PushManager.DisplayStyle displayStyle = PushManager.DisplayStyle.SimpleBanner; +// 需要异步处理。 +ChatClient.getInstance().pushManager().updatePushDisplayStyle(displayStyle); +``` + +你可以调用 `getPushConfigsFromServer` 方法获取推送通知中的显示属性,如以下代码示例所示: + +```java +PushConfigs pushConfigs = ChatClient.getInstance().pushManager().getPushConfigsFromServer(); +// 获取推送显示昵称。 +String nickname = pushConfigs.getDisplayNickname(); +// 获取推送通知的显示样式。 +PushManager.DisplayStyle style = pushConfigs.getDisplayStyle(); +``` + +若要在通知栏中显示消息内容,需要设置通知显示样式 `DisplayStyle`。该参数有如下两种设置: + +- (默认)`SimpleBanner`:不论 `nickname` 是否设置,对于推送任何类型的消息,通知栏采用默认显示设置,即推送标题为“您有一条新消息”,推送内容为“请点击查看”。 +- `MessageSummary`:显示消息内容。设置的昵称只在 `DisplayStyle` 为 `MessageSummary` 时生效,在 `SimpleBanner` 时不生效。 + +下表以单聊文本消息为例介绍这显示属性的设置。 + +
对于群聊,下表中的“消息发送方的推送昵称”和“消息发送方的 IM 用户 ID”显示为“群组 ID”。
+ +| 参数设置 | 推送显示 | 图片 | +| :--------- | :----- |:------------- | +|
  • `DisplayStyle`:(默认)`SimpleBanner`
  • `nickname`:设置或不设置
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“请点击查看”
| push_displayattribute_1.png | +|
  • `DisplayStyle`:`MessageSummary`
  • `nickname`:设置具体值
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“消息发送方的推送昵称:消息内容”
| push_displayattribute_2.png | +|
  • `DisplayStyle`:`MessageSummary`
  • `nickname`:不设置
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“消息发送方的 IM 用户 ID: 消息内容”
| push_displayattribute_3.png | + +## 使用默认推送模板 + +默认推送模板主要用于服务器提供的默认配置不满足你的需求时,可使你设置全局范围的推送标题和推送内容。例如,服务器提供的默认设置为中文和英文的推送标题和内容,你若需要使用韩语或日语的推送标题和内容,则可以设置对应语言的推送模板。 + +要使用默认模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建默认推送模板,模板名称为 `default`。设置完毕,消息推送时自动使用默认模板,创建消息时无需传入模板名称。 + +按照以下步骤在声网控制台创建默认推送模板: + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Template**,单击 **Add Push Template**,在弹出的对话框中配置字段,如下图所示。 + +![image](\agora_doc_source\en\markdown\agora-chat\images\push\push_add_template.png) + +5. 将 **Template Name** 设置为 **default**,然后设置 **Title** 和 **Content** 参数,点击 **OK**。 + +| 参数 | 类型 | 描述 | 是否必须 | +| :--------- | :----- | :----- | :----- | +| **Template Name** | String | 推送模板名称,默认模板为 **default**。 | Yes | +| **Title** | Array | 推送标题。可通过以下方式设置:
  • 输入固定的推送标题。
  • 使用内置变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入该参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。 | Yes | +| **Content** | Array | 推送内容。可通过以下方式设置:
  • 输入固定的推送内容。
  • 使用变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。| Yes | + +## 使用消息扩展字段 + +创建推送消息时,你可以设置消息扩展字段自定义要显示的推送标题 `em_push_title` 和推送内容 `em_push_content`。 + +```java +// 本示例以文本消息为例,图片和文件等消息类型的设置方法相同。 +ChatMessage message = ChatMessage.createSendMessage(ChatMessage.Type.TXT); +// 设置自定义推送显示。 +JSONObject extObject = new JSONObject(); +try { + extObject.put("em_push_title", "custom push title"); // 自定义推送消息标题。该字段为内置字段,字段名不可修改。 + extObject.put("em_push_content", "custom push content"); // 自定义推送消息内容。该字段为内置字段,字段名不可修改。 +} catch (JSONException e) { + e.printStackTrace(); +} +// 将推送扩展设置到消息中。该字段为内置的推送扩展字段。 +message.setAttribute("em_apns_ext", extObject); +``` + +自定义显示字段的数据结构如下: + +```java +{ + "em_apns_ext": { + "em_push_title": "custom push title", + "em_push_content": "custom push content" + } +} +``` + +## 使用自定义推送模板 + +使用自定义推送模板的步骤如下: + +1. 若使用自定义推送模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建自定义推送模板。**Add Push Template** 对话框中参数的描述,详见[使用默认推送模板](#使用默认推送模板)。使用自定义模板时,**Title** 和 **Content** 参数无论通过哪种方式设置,创建消息时均需通过扩展字段传入。 + +2. 创建消息时需通过使用扩展字段传入模板名称、推送标题和推送内容,通知栏中的推送标题和内容分别使用模板中的格式。 + +```java +// 下面以文本消息为例,其他类型的消息设置方法相同。 +ChatMessage message = ChatMessage.createSendMessage(ChatMessage.Type.TXT); +TextMessageBody txtBody = new TextMessageBody("message content"); +// 设置推送通知接收方。单聊为接收方的用户 ID,群聊为群组 ID。 +message.setTo("receiver"); +// 使用推送模板。 +JSONObject pushObject = new JSONObject(); +JSONArray titleArgs = new JSONArray(); +JSONArray contentArgs = new JSONArray(); +try { + // 设置推送模板名称。 + pushObject.put("name", "test6"); + // 设置模板中推送标题的 value 数组。如果模板中指定的推送标题为占位数据,则在这里可自定义标题;若指定的标题为固定值,则使用该模板时标题为固定值。 + titleArgs.put("test1"); + //... + pushObject.put("title_args", titleArgs); + // 设置模板中的推送内容的 value 数组。如果模板中指定的模板内容为占位数据,则在这里可自定义内容;若指定的内容为固定值,则使用该模板时内容为固定值。 + contentArgs.put("$fromNickname"); + contentArgs.put("$msg"); + //... + pushObject.put("content_args", contentArgs); +} catch (JSONException e) { + e.printStackTrace(); +} +// 将推送模板添加到消息中。 +message.setAttribute("em_push_template", pushObject); +// 设置消息状态回调。 +message.setMessageStatusCallback(new CallBack() {...}); +// 发送消息。 +ChatClient.getInstance().chatManager().sendMessage(message); +``` + +推送模板的 JSON 结构如下: + +```json +"em_push_template":{ + "name":"test6", + "title_args":[ + "test1" + ], + "content_args":[ + "{$fromNickname}", + "{$msg}" + ] +} +``` + +消息接收方可以调用 `setPushTemplate` 方法传入推送模板名称,选择要使用的模板。 + +
若发送方在发送消息时使用了推送模板,则推送通知栏中的显示内容以发送方的推送模板为准。
+```java +ChatClient.getInstance().pushManager().setPushTemplate("Template Name", new CallBack() { + @Override + public void onSuccess() { + + } + + @Override + public void onError(int code, String error) { + + } +}); +``` + + + + diff --git a/agora_chat_en_draft/android/5_dnd_notificationmode.md b/agora_chat_en_draft/android/5_dnd_notificationmode.md new file mode 100644 index 0000000..c17aa0f --- /dev/null +++ b/agora_chat_en_draft/android/5_dnd_notificationmode.md @@ -0,0 +1,148 @@ +# 设置推送通知方式和免打扰模式 + +为优化用户在处理大量推送通知时的体验,即时通讯 IM 在 app 和会话层面提供了推送通知方式和免打扰模式的细粒度选项。 + +**推送通知方式** + +推送通知方式参数的说明如下表所示: + +| 参数 | 描述 | App | 单聊和群聊会话 | +| :------- | :----- | :----- | :----- | +| `ALL` | 接收所有离线消息的推送通知。 | ✓ | ✓ | +| `MENTION_ONLY` | 仅接收提及消息的推送通知。
该参数推荐在群聊中使用。若提及一个或多个用户,需在创建消息时对 `ext` 字段传 "em_at_list":["user1", "user2" ...];若提及所有人,对该字段传 "em_at_list":"all"。 | ✓ | ✓ | +| `NONE` | 不接收离线消息的推送通知。 | ✓ | ✓ | + +会话级别的推送通知方式设置优先于 app 级别的设置,未设置推送通知方式的会话默认采用 app 的设置。 + +例如,假设 app 的推送方式设置为 `MENTION_ONLY`,而指定会话的推送方式设置为 `ALL`。你会收到来自该会话的所有推送通知,而对于其他会话来说,你只会收到提及你的消息的推送通知。 + +**免打扰模式** + +在你完成 SDK 初始化和成功登录 app 后,可以对 app 以及各类型的会话开启离线推送功能以及通过设置免打扰模式关闭推送。 + +你可以在 app 级别指定免打扰时间段和免打扰时长,即时通讯 IM 在这两个时间段内不发送离线推送通知。若既设置了免打扰时间段,又设置了免打扰时长,免打扰模式的生效时间为这两个时间段的累加。 + +免打扰时间参数的说明如下表所示: + +| 参数 | 描述 | App | 单聊和群聊会话 | +| :--------| :----- | :------------------- | :----- | +| `SILENT_MODE_INTERVAL` | 每天定时触发离线推送免打扰的时间段,采用 24 小时制,精确到分钟,格式为 H:M-H:M,例如 8:30-10:0,开始时间和结束时间中的小时数和分钟数的取值范围分别为 [0,23] 和 [0,59]。免打扰时间段的设置说明如下:
  • 开始时间和结束时间设置后,免打扰模式每天定时触发。例如,若该时间段设置为 `8:0`-`10:0`,免打扰模式在每天的 8:00-10:00 内生效。若你在 11:00 设置开始时间为 8:0,结束时间为 12:0,则免打扰模式在当天的 11:00-12:00 生效,以后每天均在 8:00-12:00 生效。
  • 若开始时间和结束时间相同,免打扰模式则全天生效。不过,若设置为 `0:0-0:0`,则关闭免打扰模式。
  • 若结束时间早于开始时间,则免打扰模式在每天的开始时间到次日的结束时间内生效。例如,开始时间为 `10:0`,结束时间为 `8:0`,则免打扰模式的在当天的 10:00 到次日的 8:00 生效。
  • 目前仅支持在每天的一个指定时间段内开启免打扰模式,不支持多个免打扰时间段,新的设置会覆盖之前的设置。
  • 若该参数和 `SILENT_MODE_DURATION` 均设置,免打扰模式当日在这两个时间段均生效,例如,例如,上午 8:00 将 `SILENT_MODE_INTERVAL` 设置为 8:0-10:0,`SILENT_MODE_DURATION` 设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。
| ✓ | ✗ | +| `SILENT_MODE_DURATION`| 免打扰时长,单位为分钟。免打扰时长的取值范围为 [0,10080],`0` 表示该参数无效,`10080` 表示免打扰模式持续 7 天。
与免打扰时间段的设置每天生效不同,该参数为一次有效。设置后立即生效,例如,上午 8:00 将 app 层级的 `SILENT_MODE_DURATION` 设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 处于免打扰模式。
- 若该参数和 `SILENT_MODE_INTERVAL` 均设置,免打扰模式当日在这两个时间段均生效,例如,上午 8:00 将 app 级的 `SILENT_MODE_INTERVAL` 设置为 8:00-10:00,免打扰时长设置为 240 分钟(4 个小时),则 app 在当前 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。 | ✓ | ✓ | + +若在免打扰时段或时长生效期间需要对指定用户推送消息,需设置[强制推送](./7_push_extension#强制推送)。 + +**推送通知方式与免打扰时间设置之间的关系** + +对于 app 和 app 中的所有会话,免打扰模式的设置优先于推送通知方式的设置。例如,假设在 app 级别指定了免打扰时间段,并将指定会话的推送通知方式设置为 `ALL`。App 在指定的时间段内进入免打扰模式,你不会收到任何推送通知。 + +或者,假设为会话指定了免打扰时间段,而 app 没有任何免打扰设置并且其推送通知方式设置为 `ALL`。在指定的免打扰时间段内,你不会收到来自该会话的任何推送通知,而所有其他会话的推送保持不变。 + +## 设置 app 的推送通知 + +你可以调用 `setSilentModeForAll` 方法设置 app 级别的推送通知,并通过指定 `SilentModeParam` 字段设置推送通知方式和免打扰模式,如下代码示例所示: + +```java +//设置推送通知方式为 `MENTION_ONLY`。 +SilentModeParam param = new SilentModeParam(SilentModeParam.SilentModeParamType.REMIND_TYPE) + .setRemindType(PushManager.PushRemindType.MENTION_ONLY); +//设置离线推送免打扰时长为 15 分钟。 +SilentModeParam param = new SilentModeParam(SilentModeParam.SilentModeParamType.SILENT_MODE_DURATION) + .setSilentModeDuration(15); +//设置离线推送的免打扰时间段为 8:30 至 15:00。 +SilentModeParam param = new SilentModeParam(SilentModeParam.SilentModeParamType.SILENT_MODE_INTERVAL) + .setSilentModeInterval(new SilentModeTime(8, 30), new SilentModeTime(15, 0)); +//设置 app 的离线推送通知。 +ChatClient.getInstance().pushManager().setSilentModeForAll(param, new ValueCallBack(){}); +``` + +## 获取 app 的推送通知设置 + +你可以调用 `getSilentModeForAll` 方法获取 app 级别的推送通知设置,如以下代码示例所示: + +```java +ChatClient.getInstance().pushManager().getSilentModeForAll(new ValueCallBack(){ + @Override + public void onSuccess(SilentModeResult result) { + // 获取 app 的推送通知方式的设置。 + PushManager.PushRemindType remindType = result.getRemindType(); + // 获取 app 的离线推送免打扰过期的 Unix 时间戳。 + long timestamp = result.getExpireTimestamp(); + // 获取 app 的离线推送免打扰时间段的开始时间。 + SilentModeTime startTime = result.getSilentModeStartTime(); + startTime.getHour(); // 免打扰时间段的开始时间中的小时数。 + startTime.getMinute(); // 免打扰时间段的开始时间中的分钟数。 + // 获取 app 的离线推送免打扰时间段的结束时间。 + SilentModeTime endTime = result.getSilentModeEndTime(); + endTime.getHour(); // 免打扰时间段的结束时间中的小时数。 + endTime.getMinute(); // 免打扰时间段的结束时间中的分钟数。 + } + @Override + public void onError(int error, String errorMsg) {} +}); +``` + +## 设置单个会话的推送通知 + +你可以调用 `setSilentModeForConversation` 方法设置指定会话的推送通知,并通过指定 `SilentModeParam` 字段设置推送通知方式和免打扰模式,如以下代码示例所示: + +```java +//设置推送通知方式为 `MENTION_ONLY`。 +SilentModeParam param = new SilentModeParam(SilentModeParam.SilentModeParamType.REMIND_TYPE) + .setRemindType(PushManager.PushRemindType.MENTION_ONLY); + +//设置离线推送免打扰时长为 15 分钟。 +SilentModeParam param = new SilentModeParam(SilentModeParam.SilentModeParamType.SILENT_MODE_DURATION) + .setSilentDuration(15); +//设置会话的离线推送免打扰模式。目前,暂不支持设置会话免打扰时间段。 +ChatClient.getInstance().pushManager().setSilentModeForConversation(conversationId, conversationType, param, new ValueCallBack(){}); +``` + +## 获取单个会话的推送通知设置 + +你可以调用 `getSilentModeForConversation` 方法获取指定会话的推送通知设置,如以下代码示例所示: + +```java +ChatClient.getInstance().pushManager().getSilentModeForConversation(conversationId, conversationType, new ValueCallBack(){ + @Override + public void onSuccess(SilentModeResult result) { + // 获取指定会话是否设置了推送通知方式。 + boolean enable = result.isConversationRemindTypeEnabled(); + // 检查会话是否设置了推送通知方式。 + if(enable){ + //获取会话的推送通知方式。 + PushManager.PushRemindType remindType = result.getRemindType(); + } + // 获取会话的离线推送免打扰过期 Unix 时间戳。 + long timestamp = result.getExpireTimestamp(); + } + @Override + public void onError(int error, String errorMsg) {} +}); +``` + +## 获取多个会话的推送通知设置 + +1. 你可以在每次调用中最多获取 20 个会话的推送通知设置。 + +2. 如果会话使用了 app 设置或其推送通知设置已过期,则返回的字典不包含此会话。 + +你可以调用 `getSilentModeForConversations` 方法获取多个会话的推送通知设置,如以下示例代码所示: + +```java +ChatClient.getInstance().pushManager().getSilentModeForConversations(conversationList, new ValueCallBack>(){ + @Override + public void onSuccess(Map value) {} + @Override + public void onError(int error, String errorMsg) {} +}); +``` + +## 清除单个会话的推送通知方式的设置 + +你可以调用 `clearRemindTypeForConversation` 方法清除指定会话的推送通知方式的设置。清除后,默认情况下,该会话会使用 app 的设置。 + +以下代码示例显示了如何清除会话的推送通知方式: + +```java +ChatClient.getInstance().pushManager().clearRemindTypeForConversation(conversationId, conversationType, new CallBack(){}); +``` \ No newline at end of file diff --git a/agora_chat_en_draft/android/6_push_translation.md b/agora_chat_en_draft/android/6_push_translation.md new file mode 100644 index 0000000..b8fbf1a --- /dev/null +++ b/agora_chat_en_draft/android/6_push_translation.md @@ -0,0 +1,15 @@ +# 设置推送翻译 + +推送通知与翻译功能协同工作。如果用户启用[自动翻译](./agora_chat_translation_android)功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 + +作为接收方,你可以设置你在离线时希望接收的推送通知的首选语言。如果翻译后消息的语言匹配你的设置,则翻译后消息显示在推送通知栏;否则,将显示原始消息。 + +以下示例代码显示如何设置和获取推送通知的首选语言: + +```java +// 设置离线推送的首选语言。 +ChatClient.getInstance().pushManager().setPreferredNotificationLanguage("en", new CallBack(){}); + +// 获取设置的离线推送的首选语言。 +ChatClient.getInstance().pushManager().getPreferredNotificationLanguage(new ValueCallBack(){}); +``` \ No newline at end of file diff --git a/agora_chat_en_draft/android/7_push_extension.md b/agora_chat_en_draft/android/7_push_extension.md new file mode 100644 index 0000000..d3f4291 --- /dev/null +++ b/agora_chat_en_draft/android/7_push_extension.md @@ -0,0 +1,68 @@ +# 设置推送扩展功能 + +你可以利用扩展字段实现自定义推送设置,本文以强制推送和发送静默消息为例介绍如何实现推送扩展功能。 + +## 设置自定义推送字段 + +创建推送消息时,可以在消息中添加自定义字段,满足个性化业务需求。 + +```java +// 本示例以文本消息为例,图片和文件等消息类型的设置方法相同。 +ChatMessage message = ChatMessage.createSendMessage(ChatMessage.Type.TXT); +// 设置自定义推送扩展。 +JSONObject emPushExt = new JSONObject() { + { + put("custom", new JSONObject() { + { + put("key1", "value1"); + put("key2", "value2"); + } + }); + } +}; +// 将推送扩展设置到消息中。 +message.setAttribute("em_push_ext", emPushExt); +``` + +自定义字段的数据结构如下: + +```json +{ + "em_push_ext": { + "custom": { + "key1": "value1", + "key2": "value2" + } + } +} +``` + +| 参数 | 描述 | +| :--------------- | :----------------- | +| `em_push_ext` | Agora 消息推送扩展固定值,不可修改。 | +| `custom` | 消息扩展,使用扩展的方式向推送中添加自定义字段,该值为固定值。 | +| `key1`/`key2` | 自定义消息推送扩展的具体内容。 | + +## 强制推送 + +设置强制推送后,用户发送消息时会忽略接收方的免打扰设置,不论是否处于免打扰时间段都会正常向接收方推送消息。 + +```java +// 本示例以文本消息为例,图片和文件等消息类型的设置方法相同。 +ChatMessage message = ChatMessage.createSendMessage(ChatMessage.Type.TXT); +// 设置是否为强制推送,该字段为内置扩展字段,取值如下:`true`:强制推送;(默认)`false`:非强制推送。 +message.setAttribute("em_force_notification", true); +``` + +## 发送静默消息 + +发送静默消息指发送方在发送消息时设置不推送消息,即用户离线时,即时通讯 IM 服务不会通过 FCM 推送服务向该用户的设备推送消息通知。因此,用户不会收到消息推送通知。当用户再次上线时,会收到离线期间的所有消息。 + +发送静默消息和免打扰模式下均为不推送消息,区别在于发送静默消息为发送方在发送消息时设置,而免打扰模式为接收方设置在指定时间段内不接收推送通知。 + +```java +// 本示例以文本消息为例,图片和文件等消息类型的设置方法相同。 +ChatMessage message = ChatMessage.createSendMessage(ChatMessage.Type.TXT); +// 设置是否发送静默消息。该字段为内置扩展字段,取值如下:`true`:发送静默消息;(默认)`false`:推送该消息。 +message.setAttribute("em_ignore_notification", true); +``` \ No newline at end of file diff --git a/agora_chat_en_draft/flutter/1_overview.md b/agora_chat_en_draft/flutter/1_overview.md new file mode 100644 index 0000000..599e27f --- /dev/null +++ b/agora_chat_en_draft/flutter/1_overview.md @@ -0,0 +1,36 @@ +# 离线推送概述 + +即时通讯 IM 支持集成 FCM 消息推送服务,为 flutter 开发者提供低延时、高送达、高并发、不侵犯用户个人数据的离线消息推送服务。 + +客户端断开连接或应用进程被关闭等原因导致用户离线时,即时通讯 IM 会通过 FCM 消息推送服务向该离线用户的设备推送消息通知。当用户再次上线时,服务器会将离线期间的消息发送给用户(这里角标表示的是离线消息数,并不是实际的未读消息数)。例如,当你离线时,有用户向你发送了消息,你的手机的通知中心会弹出消息通知,当你再次打开 app 并登录成功,即时通讯 IM SDK 会主动拉取你不在线时的消息。 + +若应用在后台运行且用户仍为在线状态,即时通讯 IM 不会向用户推送消息通知。多设备登录时,可在声网控制台的 **Push Certificate** 页面配置推送在所有设备离线或任一设备离线时发送推送消息,该配置对所有推送通道生效。 + +
1. 应用在后台运行或手机锁屏等情况,若客户端未断开与声网服务器的连接,则即时通讯 IM 不会收到离线推送通知。
2. 多端登录时若有设备被踢下线,即使接入了 IM 离线推送,也收不到离线推送消息。
+ +除了满足用户离线条件外,要使用 FCM 离线推送,用户还需声网控制台配置 FCM 推送证书信息,例如 **Private Key** 和 **Certificate Name**,并调用客户端 SDK 提供的 `updateFCMPushToken` 向声网服务器上传 device token。 + +## 推送流程 + +![](push_fcm_flow.png) + +消息推送流程如下: + +1. 用户 B 初始化 FCM 推送 SDK,检查是否使用了 FCM 推送。 +2. 用户 B 根据配置的 FCM 推送 SDK 从 FCM 推送服务器获取 device token。 +3. FCM 推送服务器向用户 B 返回 device token。 +4. 用户 B 向声网即时通讯服务器上传推送证书名称和 device token。 +5. 用户 A 向 用户 B 发送消息。 +6. 声网即时通讯服务器检查用户 B 是否在线。若在线,声网即时通讯服务器直接将消息发送给用户 B。 +7. 若用户 B 离线,声网即时通讯服务器判断该用户是否使用了 FCM 推送。 +8. 声网即时通讯服务器将消息发送给 FCM 推送服务器。 +9. FCM 推送服务器将消息发送给用户 B。 + +
device token 是 FCM 推送提供的推送 token,即初次启动你的应用时,FCM SDK 为客户端应用实例生成的注册令牌 (registration token)。该 token 用于标识每台设备上的每个应用,FCM 通过该 token 明确消息是发送给哪个设备的,然后将消息转发给设备,设备再通知应用程序。你可以调用 `await FirebaseMessaging.instance.getToken()` 方法获得 token。另外,如果退出即时通讯 IM 登录时不解绑 device token(调用 `logout` 方法时对 `unbindToken` 参数传 `false` 时不解绑 device token,传 `true` 表示解绑 token),用户在推送证书有效期和 token 有效期内仍会接收到离线推送通知。
+ +## 前提条件 + +使用 FCM 推送前,确保满足以下条件: + +- 已开启即时通讯 IM ,详见[开启和配置即时通讯服务](./enable_agora_chat)。 +- 了解即时通讯 IM 套餐包中的 API 调用频率限制,详见[使用限制](./agora_chat_limitation)。 \ No newline at end of file diff --git a/agora_chat_en_draft/flutter/2_integration_test.md b/agora_chat_en_draft/flutter/2_integration_test.md new file mode 100644 index 0000000..e54a1ec --- /dev/null +++ b/agora_chat_en_draft/flutter/2_integration_test.md @@ -0,0 +1,169 @@ +# 在即时通讯 IM 中集成 FCM 并测试推送 + +本页介绍如何在即时通讯 IM 中集成 FCM 并测试推送是否成功集成。 + +## 集成 FCM 推送 + +Note: Currently, the official Chat website shows the latest configuration on the Firebase Console and Agora Console. +Therefore, you can ignore this part enclosed by "///////////////" during translation. +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +按以下步骤在即时通讯 IM 中集成 FCM: + +1. 在 [Firebase 控制台](https://console.firebase.google.com/)创建 Android 项目。 +2. 在[声网控制台](https://console.agora.io/)上传 FCM 推送证书。 +3. 在客户端集成 FCM。 + +
对于使用 Android 系统的设备,若同时开启了 FCM 和其他厂商的推送服务,优先使用 FCM 推送服务。
+ +### 在 Firebase 控制台创建项目 + +1. 登录 [Firebase 控制台](https://console.firebase.google.com/),在 Firebase 控制台 添加项目,点击**Add project**, 并根据需求创建项目; + +2. 创建成功后,Add App, 选择 flutter 平台; + +3. 根据 firebase 提示,安装 `Firebase CLI`并登录 Firebase ,创建 flutter 项目; + +4. 安装 FlutterFire CLI, `dart pub global activate flutterfire_cli`; + +5. 在需要添加FCM的 flutter 项目根目录执行 `flutterfire configure --project=your project name`; + +6. 查询 Sender ID。在 Project settings 页面,选择 Cloud Messaging 页签,查看 Server ID。在声网控制台上传 FCM 证书时,需要将证书名称设置为 FCM 的发送者 ID; + + [img](push_fcm_senderid.png) + +7. 在 **Project settings** 页面,选择 **Service accounts** 页签,点击 **Generate new private key** 按钮生成密钥(JSON 文件)。请保存该文件,使用 V1 证书时需在声网控制台上传该文件; + + [img](push_fcm_private_key.png) + +### 在声网控制台上传 FCM 推送证书 + +登录即时通讯 IM SDK 成功后,可在声网控制台上传 FCM 推送证书。 + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Certificate**。 +5. 在 **Push Certificate** 页面,单击 **Add Push Certificate**。在弹出的对话框中,选择 **Google** 页签,配置字段,单击**保存**。 + +[img](push_fcm_add_certificate.png) + +| 参数 | 类型 | 是否必需 | 描述 | +| :--------- | :----- | :------- | :----------------------- | +| **Certificate Type** | | 否 | 选择使用旧版证书还是 V1 证书。
  • **V1**: 你需要配置 **Private Key**。推荐使用 V1 证书。
  • **Old Version**:你需要配置 **Push Key**。老版本证书即将被弃用。
| +| **Private Key** | file | 是 | 点击 **Upload** 上传推送证书文件(.json)。你需要在 Firebase 控制台的 **Project settings** > **Service accounts** 页面点击 **Generate new private key** 生成的推送证书文件(.json)。 | +| **Push Key** | String | 是 | FCM 的服务器密钥(Server Key)。 你需在 Firebase 控制台的 **Project settings** > **Cloud Messaging** 页面,在 **Cloud Messaging API (Legacy)** 区域中获取服务器密钥。| +| **Certificate Name** | String | 是 | 配置为 FCM 的发送者 ID。你可以在 FCM 控制台的 **Project settings** > **Cloud Messaging** 页面查看 **Sender ID** 参数的值。
证书名称是声网即时通讯服务器用于判断目标设备使用哪种推送通道的唯一条件,因此必须确保你[在即时通讯 IM 中集成 FCM 时设置的 Sender ID](#initialization)与这里设置的一致。 | +| **Sound** | String | 否 | 接收方收到推送通知时的铃声标记。| +| **Push Priority** | | 否 | 消息传递优先级,详见 [FCM 官网](https://firebase.google.cn/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message)。 | +| **Push Msg Type** | | 否 | 通过 FCM 向客户端发送的消息的类型,详见 [FCM 消息简介](https://firebase.google.cn/docs/cloud-messaging/concept-options#notifications_and_data_messages) 。
  • **Data**:数据消息,由客户端应用处理。
  • **Notification**:通知消息,由 FCM SDK 自动处理。
  • **Both**:可以通过 FCM 客户端发送通知消息和数据消息。
| + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +### 在客户端配置 FCM + +1. 安装 `firebase_core`:在项目根目录执行 `flutter pub add firebase_core`。 +2. 安装 `firebase_messaging`:在项目根目录执行 `flutter pub add firebase_messaging`。 + +**针对 Android 平台** + +在你 flutter 项目的 `Android/build.gradle` 文件中,查看 `google-services` 版本,确保版本为 4.3.14 或以上。 + +```gradle + +dependencies { + // START: FlutterFire Configuration + classpath 'com.google.gms:google-services:4.3.15' + // END: FlutterFire Configuration +} + +``` + +**针对 iOS 平台** + +您必须先在 Xcode 项目中启用推送通知和后台模式,您的应用才能开始接收消息。 + +1. 打开 Xcode 项目工作区 (ios/Runner.xcworkspace)。 +2. [启用推送通知](https://help.apple.com/xcode/mac/current/#/devdfd3d04a1)。 +3. 启用后台提取和远程通知[后台执行模式](https://developer.apple.com/documentation/xcode/configuring-background-execution-modes)。 + + +#### SDK 集成 + +1. 初始化即时通讯 IM SDK 并开启 FCM。 + +```dart +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + // 替换为你的 Appkey。 + var options = ChatOptions(appKey: "Your Appkey", autoLogin: false); + // 替换为你的 FCM 的 Sender ID。 + options.enableFCM("Your FCM sender id"); + // 初始化即时通讯 IM SDK。 + await ChatClient.getInstance.init(options); + // 初始化 FCM SDK。 + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + runApp(const MyApp()); +} +``` + +2. 将 FCM 的 device token 传递给服务器。 + +在应用初始化时,FCM SDK 会为用户的设备上的客户端应用生成唯一的注册 token。由于 FCM 使用该 token 确定要将推送消息发送给哪个设备,因此,声网服务器需要获得客户端应用的注册 token 才能将通知请求发送给 FCM,然后 FCM 验证注册 token,将通知消息发送给设备。 + + +```dart +// 请求推送权限 +await FirebaseMessaging.instance.requestPermission(); + +FirebaseMessaging.instance.onTokenRefresh.listen((event) async { + debugPrint('onTokenRefresh: $event'); + await ChatClient.getInstance.pushManager.updateFCMPushToken(event); +}); + +// 获取token 并上传到即使通讯。 +final fcmToken = await FirebaseMessaging.instance.getToken(); +if (fcmToken != null) { + debugPrint('fcmToken: $fcmToken'); + await ChatClient.getInstance.pushManager.updateFCMPushToken(fcmToken); +} else { + debugPrint('fcmToken is null'); +} +``` + +## 测试 FCM 推送 + +在即时通讯 IM 中集成并启用 FCM 后,可测试推送是否成功集成。 + +### 前提条件 + +准备一台在海外正式发售的 Android 设备用于接收推送通知,确保该设备满足以下条件: +- 使用国外 IP 地址与即时通讯 IM 建立连接。 +- 支持 Google GMS 服务(Google Mobile Services)。 +- 可以正常访问 Google 网络服务,否则该设备无法从 FCM 服务接收推送通知。 + +为了确保测试效果可靠,请避免使用模拟器进行测试。 + +### 测试步骤 + +1. 在设备上登录应用,并确认 device token 绑定成功。 + 可以查看日志或调用[获取用户详情的 RESTful 接口](https://docs.agora.io/en/agora-chat/restful-api/user-system-registration#querying-a-user)确认 device token 是否绑定成功。 +2. 开启应用通知栏权限。 +3. 杀掉应用进程。 +4. 在声网控制台发送测试消息。 + 在左侧导航栏中选择 **Operation Management** > **User**。在 Users 页面中,在对应用户 ID 的 **Action** 栏中选择 **Send Admin Message**。在弹出的对话框中选择消息类型,输入消息内容,然后点击 **Send**。 + +
在 **Push Certificate** 页面中证书列表中,在每个证书的 **Action** 一栏中,点击 **More**,会出现 **Test**,这里是直接调用第三方接口推送,而 **Users** 页面中的消息发送测试是先调用即时通讯 IM 的发消息的接口,满足条件后(即用户离线、推送证书有效且绑定了 device token)再调第三方的接口进行推送。
+ +5. 查看设备是否收到推送通知。 + +### 故障排除 + +1. 检查在即时通讯 IM 中是否正确集成或启用了 FCM 推送。 + 在左侧导航栏中选择 **Operation Management > User**。在用户管理页面中,在对应用户 ID 的 **Action** 栏中选择 **Push Certificate**。在弹出框中查看是否正确显示了证书名称和 device token。 +2. 检查是否在声网控制台上传了正确的 FCM 证书。 +3. 检查是否在聊天室中推送消息。聊天室不支持离线消息推送。 +4. 检查设备是否为国行手机的 ROM。一些品牌的国产手机不支持 GMS 服务,需替换为海外发售的设备。 +5. 检查发送消息时是否设置了只发在线(deliverOnlineOnly = true)。只发在线的消息不推送。 \ No newline at end of file diff --git a/agora_chat_en_draft/flutter/3_parsing.md b/agora_chat_en_draft/flutter/3_parsing.md new file mode 100644 index 0000000..3772a17 --- /dev/null +++ b/agora_chat_en_draft/flutter/3_parsing.md @@ -0,0 +1,51 @@ +# 解析 FCM 推送字段 + +收到推送通知后,你需要解析数据。 + +通过 `FirebaseMessaging.instance.getInitialMessage` 方法可以获取 app 打开时的自定义扩展字段,示例代码如下: + +```dart +FirebaseMessaging.instance.getInitialMessage().then((message) { + Map? data = message?.data; + if (data != null) { + String f = data['f'] ?? ''; + String t = data['t'] ?? ''; + String m = data['m'] ?? ''; + String g = data['g'] ?? ''; + Object e = data['e'] ?? ''; + } +}); +``` + +| 参数 | 描述 | +| ------- | -------------- | +| `f` | 推送通知的发送方的用户 ID。 | +| `t` | 推送通知的接收方的用户 ID。 | +| `m` | 消息 ID。消息唯一标识符。 | +| `g` | 群组 ID,仅当消息为群组消息时,该字段存在。 | +| `e` | 用户自定义扩展字段。 | + +其中 `e` 为完全用户自定义扩展,数据来源为消息扩展的 `em_push_ext.custom`,数据结构如下: + +```json +{ + "em_push_ext": { + "custom": { + "key1": "value1", + "key2": "value2" + } + } +} +``` + +`RemoteMessage.data` 对象中的扩展信息的数据结构如下: + +```dart +{ + "t":"receiver", + "f":"fromUsername", + "m":"msg_id", + "g":"group_id", + "e":{} +} +``` \ No newline at end of file diff --git a/agora_chat_en_draft/flutter/4_push_display.md b/agora_chat_en_draft/flutter/4_push_display.md new file mode 100644 index 0000000..212f193 --- /dev/null +++ b/agora_chat_en_draft/flutter/4_push_display.md @@ -0,0 +1,163 @@ +# 设置推送通知的显示内容 + +通知收到后,通知栏中显示的推送标题和内容可通过以下方式设置,配置的优先级为由低到高: + +1. 设置推送通知的显示属性; +2. 使用默认推送模板; +3. 使用消息扩展字段; +4. 使用自定义推送模板。 + +## 设置推送通知的显示属性 + +你可以分别调用 `updatePushNickname` 和 `updatePushDisplayStyle` 方法设置推送通知中显示的昵称(`nickname`)和通知显示样式(`DisplayStyle`),确定通知栏中的推送标题和推送内容。 + +```dart +try { + ChatClient.getInstance.pushManager.updatePushNickname('nickname'); +} on ChatError catch (e) {} +``` + +```dart +try { + ChatClient.getInstance.pushManager.updatePushDisplayStyle(DisplayStyle.Simple); +} on ChatError catch (e) {} +``` + +你可以调用 `getPushConfigsFromServer` 方法获取推送通知中的显示属性,如以下代码示例所示: + +```dart +try { + ChatPushConfigs configs = await ChatClient.getInstance.pushManager.fetchPushConfigsFromServer(); + // 获取推送显示昵称。 + String? pushNickname = configs.displayName; + // 获取推送通知的显示样式。 + DisplayStyle pushDisplayStyle = configs.displayStyle; +} on ChatError catch (e) {} +``` + +若要在通知栏中显示消息内容,需要设置通知显示样式 `DisplayStyle`。该参数有如下两种设置: + +- (默认)`Simple`:不论 `nickname` 是否设置,对于推送任何类型的消息,通知栏采用默认显示设置,即推送标题为“您有一条新消息”,推送内容为“请点击查看”。 +- `Summary`:显示消息内容。设置的昵称只在 `DisplayStyle` 为 `Summary` 时生效,在 `Simple` 时不生效。 + +下表以单聊文本消息为例介绍这显示属性的设置。 + +
对于群聊,下表中的“消息发送方的推送昵称”和“消息发送方的 IM 用户 ID”显示为“群组 ID”。
+ +| 参数设置 | 推送显示 | 图片 | +| :--------- | :----- |:------------- | +|
  • `DisplayStyle`:(默认)`Simple`
  • `nickname`:设置或不设置
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“请点击查看”
| push_displayattribute_1.png | +|
  • `DisplayStyle`:`Summary`
  • `nickname`:设置具体值
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“消息发送方的推送昵称:消息内容”
| push_displayattribute_2.png | +|
  • `DisplayStyle`:`Summary`
  • `nickname`:不设置
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“消息发送方的 IM 用户 ID: 消息内容”
| push_displayattribute_3.png | + +## 使用默认推送模板 + +默认推送模板主要用于服务器提供的默认配置不满足你的需求时,可使你设置全局范围的推送标题和推送内容。例如,服务器提供的默认设置为中文和英文的推送标题和内容,你若需要使用韩语或日语的推送标题和内容,则可以设置对应语言的推送模板。 + +要使用默认模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建默认推送模板,模板名称为 `default`。设置完毕,消息推送时自动使用默认模板,创建消息时无需传入模板名称。 + +按照以下步骤在声网控制台创建默认推送模板: + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Template**,单击 **Add Push Template**,在弹出的对话框中配置字段,如下图所示。 + +![image](\agora_doc_source\en\markdown\agora-chat\images\push\push_add_template.png) + +5. 将 **Template Name** 设置为 **default**,然后设置 **Title** 和 **Content** 参数,点击 **OK**。 + +| 参数 | 类型 | 描述 | 是否必须 | +| :--------- | :----- | :----- | :----- | +| **Template Name** | String | 推送模板名称,默认模板为 **default**。 | Yes | +| **Title** | Array | 推送标题。可通过以下方式设置:
  • 输入固定的推送标题。
  • 使用内置变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入该参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。 | Yes | +| **Content** | Array | 推送内容。可通过以下方式设置:
  • 输入固定的推送内容。
  • 使用变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。| Yes | + +## 使用消息扩展字段 + +创建推送消息时,你可以设置消息扩展字段自定义要显示的推送标题 `em_push_title` 和推送内容 `em_push_content`。 + +```dart +ChatMessage msg = ChatMessage.createTxtSendMessage( + targetId: 'receiveId', + content: 'content', +); +msg.attributes = { + // 将推送扩展设置到消息中。该字段为内置的推送扩展字段。 + 'em_push_ext': { + // 自定义推送消息标题。该字段为内置内置字段,字段名不可修改。 + 'em_push_title': 'custom push title', + // 自定义推送消息内容。该字段为内置内置字段,字段名不可修改。 + 'em_push_content': 'custom push content' + } +}; + +try { + await ChatClient.getInstance.chatManager.sendMessage(msg); +} on ChatError catch (e) {} +``` + +自定义显示字段的数据结构如下: + +```dart +{ + "em_apns_ext": { + "em_push_title": "custom push title", + "em_push_content": "custom push content" + } +} +``` + +## 使用自定义推送模板 + +使用自定义推送模板的步骤如下: + +1. 若使用自定义推送模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建自定义推送模板。**Add Push Template** 对话框中参数的描述,详见[使用默认推送模板](#使用默认推送模板)。使用自定义模板时,**Title** 和 **Content** 参数无论通过哪种方式设置,创建消息时均需通过扩展字段传入。 + +2. 创建消息时需通过使用扩展字段传入模板名称、推送标题和推送内容,通知栏中的推送标题和内容分别使用模板中的格式。 + +```dart +ChatMessage msg = ChatMessage.createTxtSendMessage( + targetId: 'receiveId', + content: 'content', +); +msg.attributes = { + // 将推送模板添加到消息中。 + 'em_push_template': { + // 设置推送模板名称。 + 'name': 'templateName', + // 设置推送标题变量。如果模板中指定的推送标题为占位数据,则在这里可自定义标题;若指定的标题为固定值,则使用该模板时标题为固定值。 + 'title_args': ['titleValue1'], + // 设置推送内容变量。如果模板中指定的推送内容为占位数据,则在这里可自定义推送内容;若指定的推送内容为固定值,则使用该模板时推送内容为固定值。 + 'content_args': ['contentValue1'], + } +}; + +try { + await ChatClient.getInstance.chatManager.sendMessage(msg); +} on ChatError catch (e) {} +``` + +推送模板的 JSON 结构如下: + +```json +"em_push_template":{ + "name":"templateName", + "title_args":[ + "titleValue1" + ], + "content_args":[ + "{$contentValue1}", + ] +} +``` + +消息接收方可以调用 `setPushTemplate` 方法传入推送模板名称,选择要使用的模板。 + +
若发送方在发送消息时使用了推送模板,则推送通知栏中的显示内容以发送方的推送模板为准。
+ +```dart +try { + await ChatClient.getInstance.pushManager.setPushTemplate('Template Name'); +} on ChatError catch (e) {} +``` \ No newline at end of file diff --git a/agora_chat_en_draft/flutter/5_dnd_notificationmode.md b/agora_chat_en_draft/flutter/5_dnd_notificationmode.md new file mode 100644 index 0000000..fa04d0f --- /dev/null +++ b/agora_chat_en_draft/flutter/5_dnd_notificationmode.md @@ -0,0 +1,159 @@ +# 设置推送通知方式和免打扰模式 + +为优化用户在处理大量推送通知时的体验,即时通讯 IM 在 app 和会话层面提供了推送通知方式和免打扰模式的细粒度选项。 + +**推送通知方式** + +推送通知方式参数的说明如下表所示: + +| 参数 | 描述 | App | 单聊和群聊会话 | +| :------- | :----- | :----- | :----- | +| `ALL` | 接收所有离线消息的推送通知。 | ✓ | ✓ | +| `MENTION_ONLY` | 仅接收提及消息的推送通知。
该参数推荐在群聊中使用。若提及一个或多个用户,需在创建消息时对 `ext` 字段传 "em_at_list":["user1", "user2" ...];若提及所有人,对该字段传 "em_at_list":"all"。 | ✓ | ✓ | +| `NONE` | 不接收离线消息的推送通知。 | ✓ | ✓ | + +会话级别的推送通知方式设置优先于 app 级别的设置,未设置推送通知方式的会话默认采用 app 的设置。 + +例如,假设 app 的推送方式设置为 `MENTION_ONLY`,而指定会话的推送方式设置为 `ALL`。你会收到来自该会话的所有推送通知,而对于其他会话来说,你只会收到提及你的消息的推送通知。 + +**免打扰模式** + +在你完成 SDK 初始化和成功登录 app 后,可以对 app 以及各类型的会话开启离线推送功能以及通过设置免打扰模式关闭推送。 + +你可以在 app 级别指定免打扰时间段和免打扰时长,即时通讯 IM 在这两个时间段内不发送离线推送通知。若既设置了免打扰时间段,又设置了免打扰时长,免打扰模式的生效时间为这两个时间段的累加。 + +免打扰时间参数的说明如下表所示: + +| 参数 | 描述 | App | 单聊和群聊会话 | +| :--------| :----- | :------------------- | :----- | +| `SILENT_MODE_INTERVAL` | 每天定时触发离线推送免打扰的时间段,采用 24 小时制,精确到分钟,格式为 H:M-H:M,例如 8:30-10:0,开始时间和结束时间中的小时数和分钟数的取值范围分别为 [0,23] 和 [0,59]。免打扰时间段的设置说明如下:
  • 开始时间和结束时间设置后,免打扰模式每天定时触发。例如,若该时间段设置为 `8:0`-`10:0`,免打扰模式在每天的 8:00-10:00 内生效。若你在 11:00 设置开始时间为 8:0,结束时间为 12:0,则免打扰模式在当天的 11:00-12:00 生效,以后每天均在 8:00-12:00 生效。
  • 若开始时间和结束时间相同,免打扰模式则全天生效。不过,若设置为 `0:0-0:0`,则关闭免打扰模式。
  • 若结束时间早于开始时间,则免打扰模式在每天的开始时间到次日的结束时间内生效。例如,开始时间为 `10:0`,结束时间为 `8:0`,则免打扰模式的在当天的 10:00 到次日的 8:00 生效。
  • 目前仅支持在每天的一个指定时间段内开启免打扰模式,不支持多个免打扰时间段,新的设置会覆盖之前的设置。
  • 若该参数和 `SILENT_MODE_DURATION` 均设置,免打扰模式当日在这两个时间段均生效,例如,例如,上午 8:00 将 `SILENT_MODE_INTERVAL` 设置为 8:0-10:0,`SILENT_MODE_DURATION` 设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。
| ✓ | ✗ | +| `SILENT_MODE_DURATION`| 免打扰时长,单位为分钟。免打扰时长的取值范围为 [0,10080],`0` 表示该参数无效,`10080` 表示免打扰模式持续 7 天。
与免打扰时间段的设置每天生效不同,该参数为一次有效。设置后立即生效,例如,上午 8:00 将 app 层级的 `SILENT_MODE_DURATION` 设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 处于免打扰模式。
- 若该参数和 `SILENT_MODE_INTERVAL` 均设置,免打扰模式当日在这两个时间段均生效,例如,上午 8:00 将 app 级的 `SILENT_MODE_INTERVAL` 设置为 8:00-10:00,免打扰时长设置为 240 分钟(4 个小时),则 app 在当前 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。 | ✓ | ✓ | + +若在免打扰时段或时长生效期间需要对指定用户推送消息,需设置[强制推送](./7_push_extension#强制推送)。 + +**推送通知方式与免打扰时间设置之间的关系** + +对于 app 和 app 中的所有会话,免打扰模式的设置优先于推送通知方式的设置。例如,假设在 app 级别指定了免打扰时间段,并将指定会话的推送通知方式设置为 `ALL`。App 在指定的时间段内进入免打扰模式,你不会收到任何推送通知。 + +或者,假设为会话指定了免打扰时间段,而 app 没有任何免打扰设置并且其推送通知方式设置为 `ALL`。在指定的免打扰时间段内,你不会收到来自该会话的任何推送通知,而所有其他会话的推送保持不变。 + +## 设置 app 的推送通知 + +你可以调用 `setSilentModeForAll` 方法设置 app 级别的推送通知,并通过指定 `ChatSilentModeParam` 字段设置推送通知方式和免打扰模式,如下代码示例所示: + +```dart +//设置推送通知方式为 `MENTION_ONLY`。 +ChatSilentModeParam param = ChatSilentModeParam.remindType(ChatPushRemindType.MENTION_ONLY); + +//设置离线推送免打扰时长为 15 分钟。 +ChatSilentModeParam param = ChatSilentModeParam.silentDuration(15); + +//设置离线推送的免打扰时间段为 8:30 至 15:00。 +ChatSilentModeParam param = ChatSilentModeParam.silentModeInterval( + startTime: ChatSilentModeTime(hour: 8, minute: 30), + endTime: ChatSilentModeTime(hour: 15, minute: 0), +); + +try { + //设置 app 的离线推送通知。 + await ChatClient.getInstance.pushManager.setSilentModeForAll(param: param); +} on ChatError catch (e) {} +``` + +## 获取 app 的推送通知设置 + +你可以调用 `fetchSilentModeForAll` 方法获取 app 级别的推送通知设置,如以下代码示例所示: + +```dart +try { + ChatSilentModeResult result = + await ChatClient.getInstance.pushManager.fetchSilentModeForAll(); + // 获取 app 的推送通知方式的设置。 + ChatPushRemindType? remindType = result.remindType; + + // 获取 app 的离线推送免打扰过期的 Unix 时间戳。 + int? timestamp = result.expireTimestamp; + + // 获取 app 的离线推送免打扰时间段的开始时间。 + ChatSilentModeTime? startTime = result.startTime; + // 免打扰时间段的开始时间中的小时数。 + startTime?.hour; + // 免打扰时间段的开始时间中的分钟数。 + startTime?.minute; + + // 获取 app 的离线推送免打扰时间段的结束时间。 + ChatSilentModeTime? endTime = result.endTime; + // 免打扰时间段的结束时间中的小时数。 + endTime?.hour; + // 免打扰时间段的结束时间中的分钟数。 + endTime?.minute; +} on ChatError catch (e) {} +``` + +## 设置单个会话的推送通知 + +你可以调用 `setSilentModeForConversation` 方法设置指定会话的推送通知,并通过指定 `SilentModeParam` 字段设置推送通知方式和免打扰模式,如以下代码示例所示: + +```dart +//设置推送通知方式为 `MENTION_ONLY`。 +ChatSilentModeParam param = ChatSilentModeParam.remindType(ChatPushRemindType.MENTION_ONLY); + +//设置离线推送免打扰时长为 15 分钟。 +ChatSilentModeParam param = ChatSilentModeParam.silentDuration(15); + +try { + //设置会话的离线推送免打扰模式。目前,暂不支持设置会话免打扰时间段。 + ChatClient.getInstance.pushManager.setConversationSilentMode( + conversationId: conversationId, + type: conversationType, + param: param, + ); +} on ChatError catch (e) {} +``` + +## 获取单个会话的推送通知设置 + +你可以调用 `fetchConversationSilentMode` 方法获取指定会话的推送通知设置,如以下代码示例所示: + +```dart +try { + //设置会话的离线推送免打扰模式。目前,暂不支持设置会话免打扰时间段。 + ChatSilentModeResult result = + await ChatClient.getInstance.pushManager.fetchConversationSilentMode( + conversationId: conversationId, + type: conversationType, + ); + + //获取会话的推送通知方式。 + result.remindType; + + // 获取会话的离线推送免打扰过期 Unix 时间戳。 + result.expireTimestamp; +} on ChatError catch (e) {} +``` + +## 获取多个会话的推送通知设置 + +1. 你可以在每次调用中最多获取 20 个会话的推送通知设置。 + +2. 如果会话使用了 app 设置或其推送通知设置已过期,则返回的字典不包含此会话。 + +你可以调用 `fetchSilentModeForConversations` 方法获取多个会话的推送通知设置,如以下示例代码所示: + +```dart +try { + Map map = await ChatClient.getInstance.pushManager.fetchSilentModeForConversations(conversationList); +} on ChatError catch (e) {} +``` + +## 清除单个会话的推送通知方式的设置 + +你可以调用 `clearRemindTypeForConversation` 方法清除指定会话的推送通知方式的设置。清除后,默认情况下,该会话会使用 app 的设置。 + +以下代码示例显示了如何清除会话的推送通知方式: + +```dart +try { + await ChatClient.getInstance.pushManager.removeConversationSilentMode(conversationId: conversationId, type: conversationType); +} on ChatError catch (e) {} +``` diff --git a/agora_chat_en_draft/flutter/6_push_translation.md b/agora_chat_en_draft/flutter/6_push_translation.md new file mode 100644 index 0000000..2d80227 --- /dev/null +++ b/agora_chat_en_draft/flutter/6_push_translation.md @@ -0,0 +1,19 @@ +# 设置推送翻译 + +推送通知与翻译功能协同工作。如果用户启用[自动翻译](./agora_chat_translation_flutter)功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 + +作为接收方,你可以设置你在离线时希望接收的推送通知的首选语言。如果翻译后消息的语言匹配你的设置,则翻译后消息显示在推送通知栏;否则,将显示原始消息。 + +以下示例代码显示如何设置和获取推送通知的首选语言: + +```dart +// 设置离线推送的首选语言。 +try { + await ChatClient.getInstance.pushManager.setPreferredNotificationLanguage('en'); +} on ChatError catch (e) {} + +// 获取设置的离线推送的首选语言。 +try { + String? language = await ChatClient.getInstance.pushManager.fetchPreferredNotificationLanguage(); +} on ChatError catch (e) {} +``` \ No newline at end of file diff --git a/agora_chat_en_draft/flutter/7_push_extension.md b/agora_chat_en_draft/flutter/7_push_extension.md new file mode 100644 index 0000000..816f8ff --- /dev/null +++ b/agora_chat_en_draft/flutter/7_push_extension.md @@ -0,0 +1,90 @@ +# 设置推送扩展功能 + +你可以利用扩展字段实现自定义推送设置,本文以强制推送和发送静默消息为例介绍如何实现推送扩展功能。 + +## 设置自定义推送字段 + +创建推送消息时,可以在消息中添加自定义字段,满足个性化业务需求。 + +```dart +// 本示例以文本消息为例,图片和文件等消息类型的设置方法相同。 +ChatMessage msg = ChatMessage.createTxtSendMessage( + targetId: 'receiveId', + content: 'content', +); +msg.attributes = { + // 将推送扩展设置到消息中。 + "em_push_ext": { + "custom": { + "key1": "value1", + "key2": "value2" + } + } +}; + +try { + await ChatClient.getInstance.chatManager.sendMessage(msg); +} on ChatError catch (e) {} + +``` + +自定义字段的数据结构如下: + +```json +{ + "em_push_ext": { + "custom": { + "key1": "value1", + "key2": "value2" + } + } +} +``` + +| 参数 | 描述 | +| :--------------- | :----------------- | +| `em_push_ext` | Agora 消息推送扩展固定值,不可修改。 | +| `custom` | 消息扩展,使用扩展的方式向推送中添加自定义字段,该值为固定值。 | +| `key1`/`key2` | 自定义消息推送扩展的具体内容。 | + +## 强制推送 + +设置强制推送后,用户发送消息时会忽略接收方的免打扰设置,不论是否处于免打扰时间段都会正常向接收方推送消息。 + +```dart +// 本示例以文本消息为例,图片和文件等消息类型的设置方法相同。 +ChatMessage msg = ChatMessage.createTxtSendMessage( + targetId: 'receiveId', + content: 'content', +); +msg.attributes = { + 'em_force_notification': true, +}; + +try { + await ChatClient.getInstance.chatManager.sendMessage(msg); +} on ChatError catch (e) {} + +``` + +## 发送静默消息 + +发送静默消息指发送方在发送消息时设置不推送消息,即用户离线时,即时通讯 IM 服务不会通过 FCM 推送服务向该用户的设备推送消息通知。因此,用户不会收到消息推送通知。当用户再次上线时,会收到离线期间的所有消息。 + +发送静默消息和免打扰模式下均为不推送消息,区别在于发送静默消息为发送方在发送消息时设置,而免打扰模式为接收方设置在指定时间段内不接收推送通知。 + +```dart +// 本示例以文本消息为例,图片和文件等消息类型的设置方法相同。 +ChatMessage msg = ChatMessage.createTxtSendMessage( + targetId: 'receiveId', + content: 'content', +); +msg.attributes = { + 'em_ignore_notification': true, +}; + +try { + await ChatClient.getInstance.chatManager.sendMessage(msg); +} on ChatError catch (e) {} + +``` \ No newline at end of file diff --git a/agora_chat_en_draft/image/push_add_template.png b/agora_chat_en_draft/image/push_add_template.png new file mode 100644 index 0000000..6246e2a Binary files /dev/null and b/agora_chat_en_draft/image/push_add_template.png differ diff --git a/agora_chat_en_draft/image/push_apns_add_certificate.png b/agora_chat_en_draft/image/push_apns_add_certificate.png new file mode 100644 index 0000000..6f6a3e9 Binary files /dev/null and b/agora_chat_en_draft/image/push_apns_add_certificate.png differ diff --git a/agora_chat_en_draft/image/push_apns_ca.png b/agora_chat_en_draft/image/push_apns_ca.png new file mode 100644 index 0000000..6ebc08e Binary files /dev/null and b/agora_chat_en_draft/image/push_apns_ca.png differ diff --git a/agora_chat_en_draft/image/push_apns_flow.png b/agora_chat_en_draft/image/push_apns_flow.png new file mode 100644 index 0000000..71dabfc Binary files /dev/null and b/agora_chat_en_draft/image/push_apns_flow.png differ diff --git a/agora_chat_en_draft/image/push_displayattribute_1.png b/agora_chat_en_draft/image/push_displayattribute_1.png new file mode 100644 index 0000000..01718aa Binary files /dev/null and b/agora_chat_en_draft/image/push_displayattribute_1.png differ diff --git a/agora_chat_en_draft/image/push_displayattribute_2.png b/agora_chat_en_draft/image/push_displayattribute_2.png new file mode 100644 index 0000000..e8682c7 Binary files /dev/null and b/agora_chat_en_draft/image/push_displayattribute_2.png differ diff --git a/agora_chat_en_draft/image/push_displayattribute_3.png b/agora_chat_en_draft/image/push_displayattribute_3.png new file mode 100644 index 0000000..e6d02f0 Binary files /dev/null and b/agora_chat_en_draft/image/push_displayattribute_3.png differ diff --git a/agora_chat_en_draft/image/push_fcm_add_certificate.png b/agora_chat_en_draft/image/push_fcm_add_certificate.png new file mode 100644 index 0000000..2da06fe Binary files /dev/null and b/agora_chat_en_draft/image/push_fcm_add_certificate.png differ diff --git a/agora_chat_en_draft/image/push_fcm_download_googleservice.png b/agora_chat_en_draft/image/push_fcm_download_googleservice.png new file mode 100644 index 0000000..63cbfae Binary files /dev/null and b/agora_chat_en_draft/image/push_fcm_download_googleservice.png differ diff --git a/agora_chat_en_draft/image/push_fcm_flow.png b/agora_chat_en_draft/image/push_fcm_flow.png new file mode 100644 index 0000000..6d6cc1b Binary files /dev/null and b/agora_chat_en_draft/image/push_fcm_flow.png differ diff --git a/agora_chat_en_draft/image/push_fcm_newcertificate_upload.png b/agora_chat_en_draft/image/push_fcm_newcertificate_upload.png new file mode 100644 index 0000000..b91200a Binary files /dev/null and b/agora_chat_en_draft/image/push_fcm_newcertificate_upload.png differ diff --git a/agora_chat_en_draft/image/push_fcm_oldcertificate_edit.png b/agora_chat_en_draft/image/push_fcm_oldcertificate_edit.png new file mode 100644 index 0000000..a313e1e Binary files /dev/null and b/agora_chat_en_draft/image/push_fcm_oldcertificate_edit.png differ diff --git a/agora_chat_en_draft/image/push_fcm_oldcertificate_switch.png b/agora_chat_en_draft/image/push_fcm_oldcertificate_switch.png new file mode 100644 index 0000000..def67d7 Binary files /dev/null and b/agora_chat_en_draft/image/push_fcm_oldcertificate_switch.png differ diff --git a/agora_chat_en_draft/image/push_fcm_private_key.png b/agora_chat_en_draft/image/push_fcm_private_key.png new file mode 100644 index 0000000..a847bb7 Binary files /dev/null and b/agora_chat_en_draft/image/push_fcm_private_key.png differ diff --git a/agora_chat_en_draft/image/push_fcm_senderid.png b/agora_chat_en_draft/image/push_fcm_senderid.png new file mode 100644 index 0000000..3b015fe Binary files /dev/null and b/agora_chat_en_draft/image/push_fcm_senderid.png differ diff --git a/agora_chat_en_draft/image/push_flow_editable.pptx b/agora_chat_en_draft/image/push_flow_editable.pptx new file mode 100644 index 0000000..ea2a0a2 Binary files /dev/null and b/agora_chat_en_draft/image/push_flow_editable.pptx differ diff --git a/agora_chat_en_draft/image/push_googleservice_Info_plist.png b/agora_chat_en_draft/image/push_googleservice_Info_plist.png new file mode 100644 index 0000000..40b84a1 Binary files /dev/null and b/agora_chat_en_draft/image/push_googleservice_Info_plist.png differ diff --git a/agora_chat_en_draft/image/push_multidevice_policy.png b/agora_chat_en_draft/image/push_multidevice_policy.png new file mode 100644 index 0000000..0d32648 Binary files /dev/null and b/agora_chat_en_draft/image/push_multidevice_policy.png differ diff --git a/agora_chat_en_draft/ios/1_overview.md b/agora_chat_en_draft/ios/1_overview.md new file mode 100644 index 0000000..4be152c --- /dev/null +++ b/agora_chat_en_draft/ios/1_overview.md @@ -0,0 +1,39 @@ +# 离线推送概述 + +即时通讯 IM 支持集成 APNs 消息推送服务,为 iOS 开发者提供低延时、高送达、高并发、不侵犯用户个人数据的离线消息推送服务。 + +客户端断开连接或应用进程被关闭等原因导致用户离线时,即时通讯 IM 会通过 APNs 消息推送服务向该离线用户的设备推送消息通知。当用户再次上线时,服务器会将离线期间的消息发送给用户(这里角标表示的是离线消息数,并不是实际的未读消息数)。例如,当你离线时,有用户向你发送了消息,你的手机的通知中心会弹出消息通知,当你再次打开 app 并登录成功,即时通讯 IM SDK 会主动拉取你不在线时的消息。 + +若应用在后台运行且用户仍为在线状态,即时通讯 IM 不会向用户推送消息通知。多设备登录时,可在声网控制台的 **Push Certificate** 页面配置推送在所有设备离线或任一设备离线时发送推送消息,该配置对所有推送通道生效。 + +
1. 应用在后台运行或手机锁屏等情况,若客户端未断开与声网服务器的连接,则即时通讯 IM 不会收到离线推送通知。
2. 多端登录时若有设备被踢下线,即使接入了 IM 离线推送,也收不到离线推送消息。
+ +除了满足用户离线条件外,要使用 APNs 离线推送,用户还需在声网控制台配置推送证书信息并调用客户端 SDK 提供的 `bindDeviceToken` 方法向声网服务器上传 device token。 + +要体验离线推送功能,请点击[这里](https://testflight.apple.com/join/MO0UuYJH)下载即时推送 IM 的 demo。 + +## 推送流程 + +下图展示了消息推送的基本工作流程: + +![](push_apns_flow.png) + +消息推送流程如下: + +1. 用户 B 向 APNs 推送服务注册,获取推送 token。 +2. APNs 返回 推送 token。 +3. 用户 B 向声网即时通讯服务器上传推送证书名称和推送 token。 +4. 用户 A 向 用户 B 发送消息。 +5. 声网即时通讯服务器检查用户 B 是否在线。若在线,声网即时通讯服务器直接将消息发送给用户 B。 +6. 若用户 B 离线,声网即时通讯服务器判断该用户是否使用了 APNs 推送。 +7. 声网即时通讯服务器将消息发送给 APNs 推送服务器。 +8. APNs 推送服务器将消息发送给用户 B。 + +
device token 是 APNs 推送提供的推送 token,即初次启动你的应用时,APNs SDK 为客户端应用实例生成的推送 token。该 token 用于标识每台设备上的每个应用,APNs 通过该 token 明确消息是发送给哪个设备的,然后将消息转发给设备,设备再通知应用程序。你可以调用 registerForRemoteNotifications 方法获得 token。另外,如果退出即时通讯 IM 登录时不解绑 device token(调用 `logout` 方法时对 `aIsUnbindDeviceToken` 参数传 `NO` 表示不解绑 device token,传 `YES` 表示解绑 token),用户在推送证书有效期和 token 有效期内仍会接收到离线推送通知。
+ +## 前提条件 + +使用 APNs 推送前,确保满足以下条件: + +- 已开启即时通讯 IM,详见[开启和配置即时通讯服务](./enable_agora_chat); +- 了解即时通讯 IM 套餐包中的 API 调用频率限制,详见[使用限制](./agora_chat_limitation)。 \ No newline at end of file diff --git a/agora_chat_en_draft/ios/2_integration_test.md b/agora_chat_en_draft/ios/2_integration_test.md new file mode 100644 index 0000000..7420723 --- /dev/null +++ b/agora_chat_en_draft/ios/2_integration_test.md @@ -0,0 +1,172 @@ +# 在即时通讯 IM 中集成 APNs 并测试推送 + +本页介绍如何在即时通讯 IM 中集成 APNs 并测试推送是否成功集成。 + +## 集成 APNs 推送 + +按以下步骤在即时通讯 IM 中集成 APNs: + +1. 在[苹果的开发者平台](https://developer.apple.com/)创建推送证书。 +2. 在[声网控制台](https://console.agora.io/)上传 APNs 证书。 +3. 在客户端集成 APNs。 + + + +### 在苹果开发者平台创建推送证书 + +APNs 支持 p8 和 p12 证书。声网服务端需要具备你的 APNs 证书才能与 APNs 通信,向客户端发送推送通知。 + +以下步骤介绍如何在[苹果的开发者平台](https://developer.apple.com/)创建 p12 证书: + +#### 步骤 1 申请证书签名请求 Certificate Signing Request (CSR) 文件 + +1. 在设备上打开 **Keychain Access** 应用,选择 **Keychain Access** > **Certificate Assistant** > **Request a Certificate from a Certificate Authority**。 +2. 在 **Certificate Assistant** 对话框中填写 **User Email Address**(电子邮件地址)和 **Common Name**(常用名称),对 **Request is** 选择 **Saved to disk**,点击 **Continue**,添加存储路径保存文件。 + + ![](push_apns_ca.png) + +3. 该存储路径下生成了 CSR 文件 `CertificateSigningRequest.certSigningRequest`。 + +#### 步骤 2 创建 App ID + +1. 登录 [iOS Developer Center](https://developer.apple.com/cn/),选择 **Account** > **Certificates, Identifiers & Profiles** > **Identifiers**。 +2. 在 **Identifiers** 页签,点击 **Identifiers** 右侧的 **+**。 +3. 在 **Register a new identifier** 页面中,选择 `App IDs`,点击 `Continue`。 +4. 对 **Select a type** 选择 **App**,点击 **Continue**。 +5. 在 **Register an App ID** 页面中,配置如下字段: + - **Description**: App ID 的描述信息。 + - **Bundle ID**: 可以设置为 `com.YourCompany.YourProjectName`。 + - **Capabilities**: 选择 **Push Notification**。 +6. 确定信息无误,点击 `Register`。 + +#### 步骤 3 分别创建开发环境和生产环境的消息推送证书 + +1. 在 **Identifiers** 页签中,选择[步骤 2](#step1-2)中创建的 **App ID**。 +2. 在 **Edit your App ID Configuration** 页面,找到 **Push Notifications**,点击 **Configure**。 +3. 在 **Apple Push Notification service SSL Certificates** 对话框中,点击 **Create Certificate** 创建适用于开发环境或生产环境的推送证书。 +4. 在 **Create a New Certificate** 页面,**Platform** 选择 **iOS**,上传[步骤 1](#step1-1) 中创建的 CSR 文件,点击 **Continue**。 +5. 在 **Download Your Certificate** 页面,点击 **Download** 生成 [APNs](https://help.apple.com/xcode/mac/current/?spm=a2c4g.11186623.0.0.14864088B1zf4p#/dev80c6204ec) 证书。 + +#### 步骤 4 生成推送证书 + + 1. 双击导入[步骤 3](#step1-3)中 Keychain 中创建的推送证书。 + 2. 打开 **Keychain Access**,选择 **login** > **Certificates**,找到已经导入的证书,右键选择该证书导出为 `.p12` 文件,设置证书密钥。 + +#### 步骤 5 生成 Provisioning Profile 文件 + +1. 登录 [iOS Developer Center](https://developer.apple.com/cn/),选择 **Account** > **Certificates, Identifiers & Profiles** > **Profiles**。 +2. 在 **Provisioning** 页签,点击 **Profiles** 右侧的 **+** 图标。 +3. 在 **Register a New Provisioning Profile** 页面,**Development** 选择 **iOS App Development**,**Distribution** 选择 **Ad Hoc**,点击 **Continue**。 + 对应于 App Store 上的正式版本,**Distribution** 选择 **App Store** 。 +4. 在 **Generate a Provisioning Profile** 页面,配置如下字段: + - **App ID**:填写[步骤 2](#step1-2)创建的 App ID。 + - **Select Certificates**:选择[步骤 4](#step1-4)中生成的 `.p12` 文件。 + - **Select Devices**:选择待开发的设备。 + - **Provisioning Profile Name**:填写 Provisioning Profile 文件名称。 +5. 确认信息,点击 **Download** 生成 Provisioning Profile 文件。 + +### 步骤 6 在声网控制台上传 APNs 证书 + +登录即时通讯 IM SDK 成功后,可在声网控制台配置多设备登录场景下的推送策略以及上传 APNs 推送证书。 + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Certificate**。 +5. 在 **Push Certificate** 页面,单击 **Add Push Certificate**。在弹出的对话框中,选择 **Apple** 页签,配置字段。 + +
若使用 FCM 推送,需选择 **Google** 页签,配置 FCM 推送参数。
+ +[image](push_apns_add_certificate.png) + +| 参数 | 类型 | 是否必需 | 描述 | +| :--------- | :----- | :------- | :----------------------- | +| **Certificate Type** | | 是 | 消息推送证书类型,目前支持 **p8** 和 **p12**。 | +| **Certificate Name** | String | 是 | 消息推送证书名称。填写在[创建推送证书](#certificate)的[第三步](##step1-3)中创建的消息推送证书名称。 | +| **Push Key** | String | 是 | 消息推送证书密钥。填写在[创建推送证书](#certificate)的[第四步](#step1-4)中导出消息推送证书文件时设置的证书密钥。该参数仅在使用 p12 证书时需要配置。 | +| **Upload Certificate** | File | 是 | 点击 `Upload` 上传[创建推送证书](#certificate)的[第四步](#step1-4)中获取的消息推送证书文件。 | +| **Key ID** | String | 是 | 输入推送证书的 Key ID。该参数仅在使用 p8 证书时需要配置。 | +| **Team ID** | String | 是 | 输入推送证书的 Team ID。该参数仅在使用 p8 证书时需要配置。 | +| **Integration Environment** | | 是 | 集成环境:
- **Development**:开发环境;
- **Production**:生产环境。 | +| **Bundle ID** | String | 是 | 绑定 ID。[创建推送证书](#certificate)的[第二步](#step1-2)中创建 App ID 时设置的 Bundle ID。 | +| **sound** | String | 否 | 接收方收到推送通知时的铃声提醒。 | + +### 在客户端集成 APNs + +1. 打开 Xcode,选择 **Targets** > **Capability** > **Push Notifications** 开启消息推送权限。 + +2. 将证书名称传递给 SDK。 + +```Objective-C +#import + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // 申请通知权限 + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) { + if (granted) { + NSLog(@"request authorization succeed"); + } + }]; + + // 注册推送 + [application registerForRemoteNotifications]; + + // 初始化选项,并设置 App Key + AgoraChatOptions *options = [AgoraChatOptions optionsWithAppkey:@"XXXX#XXXX"]; + + // 填写上传证书时设置的名称。确保这里设置的证书名称与在声网控制台上填写的证书名称一致。 + options.apnsCertName = @"PushCertName"; + + [AgoraChatClient.sharedClient initializeSDKWithOptions:options]; + + return YES; +} +``` + +3. 获取 device token 并传递给服务器。 + +Device token 注册后,iOS 系统会通过以下方式将 device token 回调给你,你需要将 device token 传给 SDK。 + +```Objective-C +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + [AgoraChatClient.sharedClient registerForRemoteNotificationsWithDeviceToken:deviceToken completion:^(AgoraChatError *aError) { + if (aError) { + NSLog(@"bind deviceToken error: %@", aError.errorDescription); + } + }]; +} +- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + NSLog(@"Register Remote Notifications Failed"); +} +``` + +## 测试 APNs 推送 + +在即时通讯 IM 中集成并启用 APNs 推送后,可测试推送是否成功集成。 + +### 前提条件 + +准备一台使用 iOS 系统的未越狱的设备。 + +为了确保测试效果可靠,请避免使用模拟器进行测试。 + +### 测试步骤 + +1. 在设备上登录应用,并确认 device token 绑定成功。 + 可以查看日志或调用[获取用户详情的 RESTful 接口](https://docs.agora.io/en/agora-chat/restful-api/user-system-registration#querying-a-user)确认 device token 是否绑定成功。 +2. 杀掉应用进程。 +3. 在声网控制台发送测试消息。 + 在左侧导航栏中选择 **Operation Management** > **User**。在 Users 页面中,在对应用户 ID 的 **Action** 栏中选择 **Send Admin Message**。在弹出的对话框中选择消息类型,输入消息内容,然后点击 **Send**。 + +
在 **Push Certificate** 页面中证书列表中,在每个证书的 **Action** 一栏中,点击 **More**,会出现 **Test**,这里是直接调用第三方接口推送,而 **Users** 页面中的消息发送测试是先调用即时通讯 IM 的发消息的接口,满足条件后(即用户离线、推送证书有效且绑定了 device token)再调第三方的接口进行推送。
+ +4. 查看设备是否收到推送通知。 + +### 故障排除 + +1. 检查在即时通讯 IM 中是否正确集成或启用了 APNs 推送。 + 在左侧导航栏中选择 **Operation Management** > **User**。在用户管理页面中,在对应用户 ID 的 **Action** 栏中选择 **Push Certificate**。在弹出框中查看是否正确显示了证书名称和 device token。 +2. 检查是否在声网控制台上传了正确的 APNs 证书且设置了正确的证书环境。 +3. 检查是否在聊天室中推送消息。聊天室不支持离线消息推送。 +4. 检查发送消息时是否设置了只发在线(`AgoraChatMessage#deliverOnlineOnly = YES`)。只发在线的消息不推送。 \ No newline at end of file diff --git a/agora_chat_en_draft/ios/3_parsing.md b/agora_chat_en_draft/ios/3_parsing.md new file mode 100644 index 0000000..ebaa303 --- /dev/null +++ b/agora_chat_en_draft/ios/3_parsing.md @@ -0,0 +1,51 @@ +# 解析收到的推送字段 + +当设备收到推送通知并点击时,iOS 系统会将推送通知中的自定义推送内容(JSON)传递给 app,这样你就可以根据推送内容自定义点击推送通知触发的行为,例如,页面跳转等。当收到推送通知并点击时,app 获取推送内容的方式如下: + +- 若 app 中使用了 `SceneDelegate`,app 的启动流程通过场景系统进行管理。当你点击离线推送的消息打开 app 时,app 将首先启动场景,然后调用 `SceneDelegate` 中的相应方法处理场景的连接和配置。你需要在 `SceneDelegate` 的 `scene(_:willConnectTo:options:)` 方法中查看 `connectionOptions` 参数获取推送内容,示例代码如下: + +```objectivec +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + // 获取启动选项 + NSDictionary *launchOptions = connectionOptions.notificationResponse.notification.request.content.userInfo; + // 进行相应的处理 + // ... +} +``` + +- 若 app 中不使用 `SceneDelegate`,iOS 系统会通过 `application:didFinishLaunchingWithOptions:` 方法中的 `launchOptions` 将推送中的用户自定义信息传递给 app。你需要查看 `launchOptions` 参数获取推送内容。 + +```plaintext +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; + } + +``` + +推送中的用户自定义信息 `userInfo` 的数据结构: + +```json +{ + "aps":{ + "alert":{ + "body":"您有一条新消息" + }, + "badge":1, + "sound":"default" + }, + "f":"6001", + "t":"6006", + "g":"1421300621769", + "m":"373360335316321408" +} +``` + +| 参数 | 描述 | +| :------ | :---------------------- | +| `body` | 显示内容。 | +| `badge` | 角标数。 | +| `sound` | 提示铃声。 | +| `f` | 消息发送方 ID。 | +| `t` | 消息接收方 ID。 | +| `g` | 群组 ID,仅当消息为群组消息时,该字段存在。 | +| `m` | 消息 ID。 | \ No newline at end of file diff --git a/agora_chat_en_draft/ios/4_push_display.md b/agora_chat_en_draft/ios/4_push_display.md new file mode 100644 index 0000000..f573bad --- /dev/null +++ b/agora_chat_en_draft/ios/4_push_display.md @@ -0,0 +1,162 @@ +# 设置推送通知的显示内容 + +通知收到后,通知栏中显示的推送标题和内容可通过以下方式设置,配置的优先级为由低到高: + +1. 设置推送通知的显示属性; +2. 使用默认推送模板; +3. 使用消息扩展字段; +4. 使用自定义推送模板。 + +## 设置推送通知的显示属性 + +你可以分别调用 `updatePushDisplayName` 和 `updatePushDisplayStyle` 方法设置推送通知中显示的昵称(`displayName`)和通知显示样式(`pushDisplayStyle`),确定通知栏中的推送标题和推送内容。 + +```Objective-C +[AgoraChatClient.sharedClient.pushManager updatePushDisplayName:@"displayName" completion:^(NSString * aDisplayName, AgoraChatError * aError) { + if (aError) + { + NSLog(@"update push display name error: %@", aError.errorDescription); + } +}]; +``` + +```Objective-C +[AgoraChatClient.sharedClient.pushManager updatePushDisplayStyle:AgoraChatPushDisplayStyleSimpleBanner completion:^(AgoraChatError * aError) +{ + if(aError) + { + NSLog(@"update display style error --- %@", aError.errorDescription); + } +}]; +``` + +你可以调用 `getPushNotificationOptionsFromServerWithCompletion` 方法获取推送通知中的显示属性,如以下代码示例所示: + +```Objective-C +[AgoraChatClient.sharedClient.pushManager getPushNotificationOptionsFromServerWithCompletion:^(AgoraChatPushOptions *aOptions, AgoraChatError *aError) { + if (!aError) { + // 获取推送通知中的显示昵称。 + NSString *displayName = aOptions.displayName; + // 获取推送通知的显示样式。 + AgoraChatPushDisplayStyle displayStyle = aOptions.displayStyle; + } + }]; +``` + +若要在通知栏中显示消息内容,需要设置通知显示样式 `pushDisplayStyle`。该参数有如下两种设置: +- (默认)`AgoraChatPushDisplayStyleSimpleBanner`:不论 `displayName` 是否设置,对于推送任何类型的消息,通知栏采用默认显示设置,即推送标题为“您有一条新消息”,推送内容为“请点击查看”。 +- `AgoraPushDisplayStyleMessageSummary`:显示消息内容。设置的昵称只在 `pushDisplayStyle` 为 `AgoraPushDisplayStyleMessageSummary` 时生效,在 `AgoraChatPushDisplayStyleSimpleBanner` 时不生效。 + +下表以单聊文本消息为例介绍这显示属性的设置。 + +
对于群聊,下表中的“消息发送方的推送昵称”和“消息发送方的 IM 用户 ID”显示为“群组 ID”。
+ +| 参数设置 | 推送显示 | 图片 | +| :--------- | :----- |:------------- | +|
  • `pushDisplayStyle`:(默认)`AgoraChatPushDisplayStyleSimpleBanner`
  • `displayName`:设置或不设置
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“请点击查看”
| push_displayattribute_1.png | +|
  • `pushDisplayStyle`:`AgoraPushDisplayStyleMessageSummary`
  • `displayName`:设置具体值
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“消息发送方的推送昵称:消息内容”
| push_displayattribute_2.png | +|
  • `pushDisplayStyle`:`AgoraPushDisplayStyleMessageSummary`
  • `displayName`:不设置
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“消息发送方的 IM 用户 ID: 消息内容”
| push_displayattribute_3.png | + +## 使用默认推送模板 + +默认推送模板主要用于服务器提供的默认配置不满足你的需求时,可使你设置全局范围的推送标题和推送内容。例如,服务器提供的默认设置为中文和英文的推送标题和内容,你若需要使用韩语或日语的推送标题和内容,则可以设置对应语言的推送模板。 + +要使用默认模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建默认推送模板,模板名称为 `default`。设置完毕,消息推送时自动使用默认模板,创建消息时无需传入模板名称。 + +按照以下步骤在声网控制台创建默认推送模板: + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Template**,单击 **Add Push Template**,在弹出的对话框中配置字段,如下图所示。 + +![image](\agora_doc_source\en\markdown\agora-chat\images\push\push_add_template.png) + +5. 将 **Template Name** 设置为 **default**,然后设置 **Title** 和 **Content** 参数,点击 **OK**。 + +| 参数 | 类型 | 描述 | 是否必须 | +| :--------- | :----- | :----- | :----- | +| **Template Name** | String | 推送模板名称,默认模板为 **default**。 | Yes | +| **Title** | Array | 推送标题。可通过以下方式设置:
  • 输入固定的推送标题。
  • 使用内置变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入该参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。 | Yes | +| **Content** | Array | 推送内容。可通过以下方式设置:
  • 输入固定的推送内容。
  • 使用变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。| Yes | + +## 使用消息扩展字段 + +创建推送消息时,你可以设置消息扩展字段自定义要显示的推送内容。 + +对于推送通知的显示属性,即推送通知的显示属性和显示样式,除了调用具体方法设置,你还可以通过自定义字段设置。若你同时采用了这两种方法,设置的自定义字段优先级较高。 + +```Objective-C +AgoraChatTextMessageBody *body = [[AgoraChatTextMessageBody alloc] initWithText:@"test"]; + AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:conversationId from:AgoraChatClient.sharedClient.currentUsername to:conversationId body:body ext:nil]; + message.ext = @{@"em_apns_ext":@{@"em_push_content":@"custom push content",@"em_push_title":@"custom push title"}}; + message.chatType = AgoraChatTypeChat; + [AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +自定义显示字段的结构如下: + +```json +{ + "em_apns_ext": { + "em_push_title": "custom push title", + "em_push_content": "custom push content" + } +} +``` + +| 参数 | 描述 | +| :---------------- | :----------------- | +| `em_apns_ext` | 消息扩展字段。 | +| `em_push_title` | 自定义推送消息标题。该字段名固定,不可修改。 | +| `em_push_content` | 自定义推送消息内容。该字段名固定,不可修改。 | + +## 使用自定义推送模板 + +使用自定义推送模板的步骤如下: + +1. 若使用自定义推送模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建自定义推送模板。**Add Push Template** 对话框中参数的描述,详见[使用默认推送模板](#使用默认推送模板)。使用自定义模板时,**Title** 和 **Content** 参数无论通过哪种方式设置,创建消息时均需通过扩展字段传入。 + +2. 创建消息时需通过使用扩展字段传入模板名称、推送标题和推送内容,通知栏中的推送标题和内容分别使用模板中的格式。 + +```objective-C +// 下面以文本消息为例,其他类型的消息设置方法相同。 +AgoraChatTextMessageBody *body = [[AgoraChatTextMessageBody alloc]initWithText:@"test"]; +AgoraChatMessage *message = [[AgoraChatMessage alloc]initWithConversationID:@"conversationId" from:@"currentUsername" to:@"conversationId" body:body ext:nil]; + // 将在声网控制台上创建的推送模板设置为默认推送模板。 + NSDictionary *pushObject = @{ + @"name":@"templateName",// 设置推送模板名称。 + @"title_args":@[@"titleValue1"],// 设置推送标题变量。如果模板中指定的推送标题为占位数据,则在这里可自定义标题;若指定的标题为固定值,则使用该模板时标题为固定值。 + @"content_args":@[@"contentValue1"]// 设置推送内容变量。如果模板中指定的推送内容为占位数据,则在这里可自定义推送内容;若指定的推送内容为固定值,则使用该模板时推送内容为固定值。 + }; + message.ext = @{ + @"em_push_template":pushObject, + }; + message.chatType = AgoraChatTypeChat; +[[AgoraChatClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; +``` + +推送模板的 JSON 结构如下: + +```json +"em_push_template":{ + "name":"test6", + "title_args":[ + "test1" + ], + "content_args":[ + "{$fromNickname}", + "{$msg}" + ] +} +``` + +消息接收方可以调用 `setPushTemplate` 方法传入推送模板名称,选择要使用的模板。 + +
若发送方在发送消息时使用了推送模板,则推送通知栏中的显示内容以发送方的推送模板为准。
+ +```objective-C +[AgoraChatClient.sharedClient.pushManager setPushTemplate:@"templateName" completion:^(AgoraChatError * _Nullable aError) { + +}]; +``` \ No newline at end of file diff --git a/agora_chat_en_draft/ios/5_dnd_notificationmode.md b/agora_chat_en_draft/ios/5_dnd_notificationmode.md new file mode 100644 index 0000000..fd26499 --- /dev/null +++ b/agora_chat_en_draft/ios/5_dnd_notificationmode.md @@ -0,0 +1,142 @@ +# 设置推送通知方式和免打扰模式 + +为优化用户在处理大量推送通知时的体验,即时通讯 IM 在 app 和会话层面提供了推送通知方式和免打扰模式的细粒度选项。 + +**推送通知方式** + +| 推送通知方式参数 | 描述 | App | 单聊和群聊会话 | +| :------- | :----- | :----- | :----- | +| `All` | 接收所有离线消息的推送通知。 | ✓ | ✓ | +| `MentionOnly` | 仅接收提及消息的推送通知。
该参数推荐在群聊中使用。若提及一个或多个用户,需在创建消息时对 `ext` 字段传 "em_at_list":["user1", "user2" ...];若提及所有人,对该字段传 "em_at_list":"all"。 | ✓ | ✓ | +| `NONE` | 不接收离线消息的推送通知。 | ✓ | ✓ | + +会话级别的推送通知方式设置优先于 app 级别的设置,未设置推送通知方式的会话默认采用 app 的设置。 + +例如,假设 app 的推送方式设置为 `MentionOnly`,而指定会话的推送方式设置为 `All`。你会收到来自该会话的所有推送通知,而对于其他会话来说,你只会收到提及你的消息的推送通知。 + +**免打扰模式** + +在你完成 SDK 初始化和成功登录 app 后,可以对 app 以及各类型的会话开启离线推送功能以及通过设置免打扰模式关闭推送。 + +你可以在 app 级别指定免打扰时间段和免打扰时长,即时通讯 IM 在这两个时间段内不发送离线推送通知。若既设置了免打扰时间段,又设置了免打扰时长,免打扰模式的生效时间为这两个时间段的累加。 + +免打扰时间参数的说明如下表所示: + +| 免打扰时间参数 | 描述 | App | 单聊和群聊会话 | +| :--------| :----- | :------------ | :------------ | +| `silentModeStartTime & silentModeEndTime` | 每天定时触发离线推送免打扰的时间段,采用 24 小时制,精确到分钟,格式为 H:M-H:M,例如 8:30-10:0,开始时间和结束时间中的小时数和分钟数的取值范围分别为 [0,23] 和 [0,59]。免打扰时间段的设置说明如下:
  • 开始时间和结束时间设置后,免打扰模式每天定时触发。例如,若该时间段设置为 `8:0`-`10:0`,免打扰模式在每天的 8:00-10:00 内生效。若你在 11:00 设置开始时间为 8:0,结束时间为 12:0,则免打扰模式在当天的 11:00-12:00 生效,以后每天均在 8:00-12:00 生效。
  • 若开始时间和结束时间相同,免打扰模式则全天生效。不过,若设置为 `0:0-0:0`,则关闭免打扰模式。
  • 若结束时间早于开始时间,则免打扰模式在每天的开始时间到次日的结束时间内生效。例如,开始时间为 `10:0`,结束时间为 `8:0`,则免打扰模式的在当天的 10:00 到次日的 8:00 生效。
  • 目前仅支持在每天的一个指定时间段内开启免打扰模式,不支持多个免打扰时间段,新的设置会覆盖之前的设置。
  • 若该参数和 `silentModeDuration` 均设置,免打扰模式当日在这两个时间段均生效,例如,例如,上午 8:00 将 `silentModeDuration` 设置为 8:0-10:0,`silentModeDuration` 设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。
| ✓ | ✗ | +| `silentModeDuration` | 免打扰时长,单位为分钟。免打扰时长的取值范围为 [0,10080],`0` 表示该参数无效,`10080` 表示免打扰模式持续 7 天。
与免打扰时间段的设置每天生效不同,该参数为一次有效。设置后立即生效,例如,上午 8:00 将 app 层级的 `silentModeDuration` 设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 处于免打扰模式。
- 若该参数和 `silentModeStartTime & silentModeEndTime` 均设置,免打扰模式当日在这两个时间段均生效,例如,上午 8:00 将 app 级的 `silentModeStartTime & silentModeEndTime` 设置为 8:00-10:00,免打扰时长设置为 240 分钟(4 个小时),则 app 在当前 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。 | ✓ | ✓ | + +若在免打扰时段或时长生效期间需要对指定用户推送消息,需设置[强制推送](./7_push_extension#强制推送)。 + +**推送通知方式与免打扰时间设置之间的关系** + +对于 app 和 app 中的所有会话,免打扰模式的设置优先于推送通知方式的设置。例如,假设在 app 级别指定了免打扰时间段,并将指定会话的推送通知方式设置为 `All`。App 在指定的时间段内进入免打扰模式,你不会收到任何推送通知。 + +或者,假设为会话指定了免打扰时间段,而 app 没有任何免打扰设置并且其推送通知方式设置为 `All`。在指定的免打扰时间段内,你不会收到来自该会话的任何推送通知,而所有其他会话的推送保持不变。 + +## 设置 app 的推送通知 + +你可以调用 `setSilentModeForAll` 设置 app 级别的推送通知,并通过指定 `AgoraChatSilentModeParam` 字段设置推送通知方式和免打扰模式,如下代码示例所示: + +```Objective-C +// 设置推送通知方式为 `MentionOnly`。 +AgoraChatSilentModeParam *param = [[AgoraChatSilentModeParam alloc]initWithParamType:AgoraChatSilentModeParamTypeRemindType]; + param.remindType = AgoraChatPushRemindTypeMentionOnly; +// 设置 app 的离线推送通知。 +[[AgoraChatClient sharedClient].pushManager setSilentModeForAll:param completion:^(AgoraChatSilentModeResult *aResult, AgoraChatError *aError) { + if (aError) { + NSLog(@"setSilentModeForAll error---%@",aError.errorDescription); + } + }]; +// 设置离线推送免打扰时长为 15 分钟。 +AgoraChatSilentModeParam *param = [[AgoraChatSilentModeParam alloc]initWithParamType:AgoraChatSilentModeParamTypeDuration]; + param.silentModeDuration = 15; +//设置离线推送的免打扰时间段为 8:30 到 15:00。 +AgoraChatSilentModeParam *param = [[AgoraChatSilentModeParam alloc]initWithParamType:AgoraChatSilentModeParamTypeInterval]; + param.silentModeStartTime = [[AgoraChatSilentModeTime alloc]initWithHours:8 minutes:30]; + param.silentModeEndTime = [[AgoraChatSilentModeTime alloc]initWithHours:15 minutes:0]; +``` + +## 获取 app 的推送通知设置 + +你可以调用 `getSilentModeForAllWithCompletion` 获取 app 级别的推送通知设置,如以下代码示例所示: + +```Objective-C +[[AgoraChatClient sharedClient].pushManager getSilentModeForAllWithCompletion:^(AgoraChatSilentModeResult *aResult, AgoraChatError *aError) { + if (!aError) { + // 获取 app 的推送通知方式的设置。 + AgoraChatPushRemindType remindType = aResult.remindType; + // 获取 app 的离线推送免打扰过期的 Unix 时间戳。 + NSTimeInterval ex = aResult.expireTimestamp; + // 获取 app 的离线推送免打扰时间段的开始时间。 + AgoraChatSilentModeTime *startTime = aResult.silentModeStartTime; + // 获取 app 的离线推送免打扰时间段的结束时间。 + AgoraChatSilentModeTime *endTime = aResult.silentModeEndTime; + }else{ + NSLog(@"getSilentModeForAll error---%@",aError.errorDescription); + } + }]; +``` + +## 设置单个会话的推送通知 + +你可以调用 `setSilentModeForConversation` 方法设置指定会话的推送通知,并通过指定 `SilentModeParam` 字段设置推送通知方式和免打扰模式,如以下代码示例所示: + +```Objective-C +// 设置推送通知方式为 `MentionOnly`。 +AgoraChatSilentModeParam *param = [[AgoraChatSilentModeParam alloc]initWithParamType:AgoraChatSilentModeParamTypeRemindType]; + param.remindType = AgoraChatPushRemindTypeMentionOnly; + +// 设置离线推送免打扰时长为 15 分钟。 +AgoraChatSilentModeParam *param = [[AgoraChatSilentModeParam alloc]initWithParamType:AgoraChatSilentModeParamTypeDuration]; + param.silentModeDuration = 15; +// 设置会话的离线推送免打扰模式。目前,暂不支持设置会话免打扰时间段。 +AgoraChatConversationType conversationType = AgoraChatConversationTypeGroupChat; +[[AgoraChatClient sharedClient].pushManager setSilentModeForConversation:@"conversationId" conversationType:conversationType params:param completion:^(AgoraChatSilentModeResult *aResult, AgoraChatError *aError) { + if (aError) { + NSLog(@"setSilentModeForConversation error---%@",aError.errorDescription); + } + }]; +``` + +## 获取单个会话的推送通知设置 + +你可以调用 `getSilentModeForConversation` 获取指定会话的推送通知设置,如以下代码示例所示: + +```Objective-C +[[AgoraChatClient sharedClient].pushManager getSilentModeForConversation:@"conversationId" conversationType:AgoraChatConversationTypeChat completion:^(AgoraChatSilentModeResult * _Nullable aResult, AgoraChatError * _Nullable aError) { + }]; +``` + +## 获取多个会话的推送通知设置 + +1. 你可以在每次调用中最多获取 20 个会话的推送通知设置。 + +2. 如果会话使用了 app 设置或其推送通知设置已过期,则返回的字典不包含此会话。 + +你可以调用 `getSilentModeForConversations` 获取多个会话的推送通知设置,如以下代码示例所示: + +```Objective-C +AgoraChatConversation* conv1 = [AgoraChatClient.sharedClient.chatManager getConversationWithConvId:@"conversationId1"]; +NSArray *conversations = @[conv1]; + [[AgoraChatClient sharedClient].pushManager getSilentModeForConversations:conversations completion:^(NSDictionary*aResult, AgoraChatError *aError) { + if (aError) { + NSLog(@"getSilentModeForConversations error---%@",aError.errorDescription); + } + }]; +``` + +## 清除单个会话的推送通知方式的设置 + +你可以调用 `clearRemindTypeForConversation` 方法清除指定会话的推送通知方式的设置。清除后,默认情况下,此会话会使用 app 的设置。 + +以下代码示例显示了如何清除会话的推送通知方式的设置: + +```Objective-C + [[AgoraChatClient sharedClient].pushManager clearRemindTypeForConversation:@"" conversationType:conversationType completion:^(AgoraChatSilentModeResult *aResult, AgoraChatError *aError) { + if (aError) { + NSLog(@"clearRemindTypeForConversation error---%@",aError.errorDescription); + } + }]; +``` \ No newline at end of file diff --git a/agora_chat_en_draft/ios/6_push_translation.md b/agora_chat_en_draft/ios/6_push_translation.md new file mode 100644 index 0000000..0dbaac0 --- /dev/null +++ b/agora_chat_en_draft/ios/6_push_translation.md @@ -0,0 +1,22 @@ +# 设置离线推送翻译 + +推送通知与翻译功能协同工作。如果用户启用[自动翻译功能](./agora_chat_translation_ios)并发送消息,SDK 会同时发送原始消息和翻译后的消息。 + +作为接收方,你可以设置你在离线时希望接收的推送通知的首选语言。如果翻译消息的语言匹配你的设置,则翻译消息显示在推送通知中;否则,将显示原始消息。 + +以下代码示例显示了如何设置和获取推送通知的首选语言: + +```Objective-C +// 设置离线推送的首选语言。 +[[AgoraChatClient sharedClient].pushManager setPreferredNotificationLanguage:@"EU" completion:^(AgoraChatError *aError) { + if (aError) { + NSLog(@"setPushPerformLanguageCompletion error---%@",aError.errorDescription); + } +}]; +// 获取设置的离线推送的首选语言。 +[[AgoraChatClient sharedClient].pushManager getPreferredNotificationLanguageCompletion:^(NSString *aLanguageCode, AgoraChatError *aError) { + if (!aError) { + NSLog(@"getPushPerformLanguage---%@",aLanguageCode); + } +}]; +``` \ No newline at end of file diff --git a/agora_chat_en_draft/ios/7_push_extension.md b/agora_chat_en_draft/ios/7_push_extension.md new file mode 100644 index 0000000..9e3ecc7 --- /dev/null +++ b/agora_chat_en_draft/ios/7_push_extension.md @@ -0,0 +1,134 @@ +# 设置推送扩展 + +你可以利用扩展字段实现自定义推送设置,本文以强制推送、发送静默消息和富文本推送为例介绍如何实现推送扩展功能。 + +## 自定义推送字段 + +创建推送消息时,可以在消息中添加自定义字段,满足个性化业务需求。 + +```Objective-C +AgoraChatTextMessageBody *body = [[AgoraChatTextMessageBody alloc] initWithText:@"test"]; + NSString* currentUsername = AgoraChatClient.sharedClient.currentUsername; + NSString* conversationId = @"remoteId"; + AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:conversationId from:currentUsername to:conversationId body:body ext:nil]; + message.ext = @{@"em_apns_ext":@{@"extern":@{@"test":123}}}; + message.chatType = AgoraChatTypeChat; + [AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +自定义字段的数据结构如下: + +```json +{ + "em_apns_ext": { + "extern": {"test": 123} + } +} +``` + +| 参数 | 描述 | +| :--------------- | :------------------ | +| `em_apns_ext` | 内置的消息扩展字段。 | +| `extern` | 用户添加的自定义 key,可添加多个。 | + +## 自定义铃声 + +创建推送消息时,你可以自定义接收方收到消息时的提示音。你需要将音频文件加入到 app 中,并在推送中配置使用的音频文件名称。详见[苹果官方文档](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification?language=objc)。 + +```Objective-C +AgoraChatTextMessageBody *body = [[AgoraChatTextMessageBody alloc] initWithText:@"test"]; + AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:conversationId from:AgoraChatClient.sharedClient.currentUsername to:conversationId body:body ext:nil]; + message.ext = @{@"em_apns_ext":@{@"em_push_sound":@"custom.caf"}}; + message.chatType = AgoraChatTypeChat; + [AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +自定义铃声字段的数据结构如下: + +```json +{ + "ext": { + "em_apns_ext": { + "em_push_sound":"custom.caf" + } + } +} +``` + +| 参数 | 描述 | +| :--------------- | :------------------- | +| `em_apns_ext` | 内置的消息扩展字段。 | +| `em_push_sound` | 自定义提示铃声字段的 Key。该字段为内置字段,字段名不可修改。 | +| `custom.caf` | 铃声的音频文件名称。 | + +## 强制推送 + +设置强制推送后,用户发送消息时会忽略接收方的免打扰设置,不论是否处于免打扰时间段都会正常向接收方推送消息。 + +```Objective-C +AgoraChatTextMessageBody *body = [[AgoraChatTextMessageBody alloc] initWithText:@"test"]; +AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:conversationId from:AgoraChatClient.sharedClient.currentUsername to:conversationId body:body ext:nil]; +// 设置是否为强制推送,该扩展字段为内置字段,取值如下:`YES`:强制推送;(默认)`NO`:非强制推送。 +message.ext = @{@"em_force_notification":@YES}; +message.chatType = AgoraChatTypeChat; +[AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +## 发送静默消息 + +发送静默消息指发送方在发送消息时设置不推送消息,即用户离线时,即时通讯 IM 服务不会通过第三方厂商的消息推送服务向该用户的设备推送消息通知。因此,用户不会收到消息推送通知。当用户再次上线时,会收到离线期间的所有消息。 + +发送静默消息和免打扰模式下均为不推送消息,区别在于发送静默消息为发送方在发送消息时设置,而免打扰模式为接收方设置在指定时间段内不接收推送通知。 + +```Objective-C +AgoraChatTextMessageBody *body = [[AgoraChatTextMessageBody alloc] initWithText:@"test"]; +AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:conversationId from:AgoraChatClient.sharedClient.currentUsername to:conversationId body:body ext:nil]; +// 设置是否发送静默消息。该字段为内置扩展字段,取值如下:`YES`:发送静默消息;(默认)`NO`:推送该消息。 +message.ext = @{@"em_ignore_notification":@YES}; +message.chatType = AgoraChatTypeChat; +[AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +## 实现富文本推送 + +如果你的目标平台是 iOS 10.0 或以上版本,你可以参考如下代码实现 [`UNNotificationServiceExtension`](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension?language=objc) 的富文本推送功能。 + +```Objective-C +AgoraChatTextMessageBody *body = [[AgoraChatTextMessageBody alloc] initWithText:@"test"]; +AgoraChatMessage *message = [[AgoraChatMessage alloc] initWithConversationID:conversationId from:AgoraChatClient.sharedClient.currentUsername to:conversationId body:body ext:nil]; +// em_apns_ext:消息扩展字段 +message.ext = @{@"em_apns_ext":@{@"em_push_mutable_content":@YES}}; +message.chatType = AgoraChatTypeChat; +[AgoraChatClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +| 参数 | 描述 | +| :------------------------ | :----------------------------- | +| `body` | 推送消息内容。 | +| `conversationId` | 消息所属的会话 ID。 | +| `from` | 消息发送方的用户 ID。 | +| `to` | 消息接收方的用户 ID。 | +| `em_apns_ext` | 内置的消息扩展字段。 | +| `em_push_mutable_content` | 是否使用富文本推送通知(`em_apns_ext`):
  • `YES`:富文本推送通知;
  • (默认)`NO`:普通推送通知。

该字段为内置字段,字段名不可修改。 | + +接收方收到富文本推送时,会进入回调 `didReceiveNotificationRequest:withContentHandler:`,示例代码如下: + +```Objective-C +- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler { + // 推送扩展字段 + NSDictionary *userInfo = request.content.userInfo; + // 通知内容 + UNNotificationContent *content = [request.content mutableCopy]; + contentHandler(content); +} +``` + +| 参数 | 描述 | +| :---------------- | :------------------------------------------------- | +| `body` | 推送消息内容。 | +| `badge` | 角标数字。 | +| `sound` | 接收方收到消息后的提示铃声。 | +| `mutable-content` | 设置为 `1` 表示激活 `UNNotificationServiceExtension`。 | +| `f` | 消息发送方的用户 ID。 | +| `t` | 消息接收方的用户 ID。 | +| `m` | 消息 ID。 | \ No newline at end of file diff --git a/agora_chat_en_draft/react_native/1_overview.md b/agora_chat_en_draft/react_native/1_overview.md new file mode 100644 index 0000000..ac24b4c --- /dev/null +++ b/agora_chat_en_draft/react_native/1_overview.md @@ -0,0 +1,38 @@ +# 离线推送概述 + +即时通讯 IM 支持集成 FCM 消息推送服务,为 React-Native 开发者提供低延时、高送达、高并发、不侵犯用户个人数据的离线消息推送服务。 + +客户端断开连接或应用进程被关闭等原因导致用户离线时,即时通讯 IM 会通过 FCM 消息推送服务向该离线用户的设备推送消息通知。当用户再次上线时,服务器会将离线期间的消息发送给用户(这里角标表示的是离线消息数,并不是实际的未读消息数)。例如,当你离线时,有用户向你发送了消息,你的手机的通知中心会弹出消息通知,当你再次打开 app 并登录成功,即时通讯 IM SDK 会主动拉取你不在线时的消息。 + +若应用在后台运行且用户仍为在线状态,即时通讯 IM 不会向用户推送消息通知。多设备登录时,可在声网控制台的 **Push Certificate** 页面配置推送在所有设备离线或任一设备离线时发送推送消息,该配置对所有推送通道生效。 + +
1. 应用在后台运行或手机锁屏等情况,若客户端未断开与声网服务器的连接,则即时通讯 IM 不会收到离线推送通知。
2. 多端登录时若有设备被踢下线,即使接入了 IM 离线推送,也收不到离线推送消息。
+ +除了满足用户离线条件外,要使用 FCM 离线推送,用户还需声网控制台配置 FCM 推送证书信息,例如 **Private Key** 和 **Certificate Name**,并调用客户端 SDK 提供的 `updatePushConfig` 方法向声网服务器上传 device token。 + +你可以点击[这里](https://github.com/AgoraIO/Agora-Chat-API-Examples/tree/main/Chat-RN/firebase_push_demo)参考离线推送 demo 源码。 + +## 推送流程 + +![](push_fcm_flow.png) + +消息推送流程如下: + +1. 用户 B 初始化 FCM 推送 SDK,检查是否使用了 FCM 推送。 +2. 用户 B 根据配置的 FCM 推送 SDK 从 FCM 推送服务器获取 device token。 +3. FCM 推送服务器向用户 B 返回 device token。 +4. 用户 B 向声网即时通讯服务器上传推送证书名称和 device token。 +5. 用户 A 向 用户 B 发送消息。 +6. 声网即时通讯服务器检查用户 B 是否在线。若在线,声网即时通讯服务器直接将消息发送给用户 B。 +7. 若用户 B 离线,声网即时通讯服务器判断该用户是否使用了 FCM 推送。 +8. 声网即时通讯服务器将消息发送给 FCM 推送服务器。 +9. FCM 推送服务器将消息发送给用户 B。 + +
device token 是 FCM 推送提供的推送 token,即初次启动你的应用时,FCM SDK 为客户端应用实例生成的注册令牌 (registration token)。该 token 用于标识每台设备上的每个应用,FCM 通过该 token 明确消息是发送给哪个设备的,然后将消息转发给设备,设备再通知应用程序。你可以调用 FirebaseMessaging.getInstance().getToken() 方法获得 token。另外,如果退出即时通讯 IM 登录时不解绑 device token(调用 `logout` 方法时对 `unbindToken` 参数传 `false` 时不解绑 device token,传 `true` 表示解绑 token),用户在推送证书有效期和 token 有效期内仍会接收到离线推送通知。
+ +## 前提条件 + +使用 FCM 推送前,确保满足以下条件: + +- 已开启即时通讯 IM ,详见[开启和配置即时通讯服务](./enable_agora_chat)。 +- 了解即时通讯 IM 套餐包中的 API 调用频率限制,详见[使用限制](./agora_chat_limitation)。 \ No newline at end of file diff --git a/agora_chat_en_draft/react_native/2_integration_test.md b/agora_chat_en_draft/react_native/2_integration_test.md new file mode 100644 index 0000000..f04c251 --- /dev/null +++ b/agora_chat_en_draft/react_native/2_integration_test.md @@ -0,0 +1,288 @@ +# 在即时通讯 IM 中集成 FCM 并测试推送 + +本页介绍如何在即时通讯 IM 中集成 FCM 并测试推送是否成功集成。 + +## 集成 FCM 推送 + +Note: Currently, the official Chat website shows the latest configuration on the Firebase Console and Agora Console. +Therefore, you can ignore this part enclosed by "///////////////" during translation. +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +按以下步骤在即时通讯 IM 中集成 FCM: + +1. 在 [Firebase 控制台](https://console.firebase.google.com/)创建项目和应用。 +2. 在[声网控制台](https://console.agora.io/)上传 FCM 推送证书。 +3. 在客户端集成 FCM 组件。 + +### 在 Firebase 控制台创建项目 + +**对于 Android 平台:** + +1. 登录 [Firebase 控制台](https://console.firebase.google.com/),[添加项目](https://firebase.google.com/docs/android/setup#create-firebase-project)。 + +2. 在项目中[注册应用](https://firebase.google.com/docs/web/setup/#create-firebase-project)。 + +a. 在 **Add Firebase to your Android app** 页面中的 **Download and then add config file** 步骤中,点击 **Download google-services.json**,将该文件放入你的 Android 应用模块的根目录。 + +[img] push_fcm_download_googleservice.png + +b. 首先,将 `google-services` 插件作为信赖,添加到 `/android/build.gradle` 文件中: + +```gradle +buildscript { + dependencies { + classpath 'com.google.gms:google-services:4.3.15' + } +} +``` + +c. 最后,将下面的代码添加到你的 `/android/app/build.gradle` 文件中以执行该插件: + +```gradle +apply plugin: 'com.android.application' +apply plugin: 'com.google.gms.google-services' // <- Add this line +``` + +3. 查询 **Sender ID**。在 **Project settings** 页面,选择 **Cloud Messaging** 页签,查看 **Server ID**。在声网控制台上传 FCM 证书时,需要将证书名称设置为 FCM 的发送者 ID。 + +[img] push_fcm_senderid.png + +4. 在 **Project settings** 页面,选择 **Service accounts** 页签,点击 **Generate new private key** 按钮生成密钥(JSON 文件)。请保存该文件,使用 V1 证书时需在声网控制台上传该文件。 + +[img](fcm_private-key) + +**对于 iOS 平台:** + +1. 登录 [Firebase 控制台](https://console.firebase.google.com/),[添加项目](https://firebase.google.com/docs/ios/setup#create-firebase-project)。 + +2. 在项目中[注册应用](https://firebase.google.com/docs/ios/setup#register-app)。 + + a. 在 **Add Firebase to your Apple app** 页面中的 **Download config file** 步骤中,点击 **Download GoogleService-Info.plist**,将该文件放入你的 Xcode 项目的根目录,然后再将其放入所有目标。 + + [img](push_googleservice_Info_plist.png) + + b. 在文件顶部,在 `#import "AppDelegate.h"` 后面导入 Firebase SDK。 + + ```objective-C + #import + ``` + + c. 在当前的 `didFinishLaunchingWithOptions` 方法的顶部,添加以下代码: + + ```objective-C + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [FIRApp configure];} + ``` + +3. 在 **Project settings** 页面的 **Cloud Messaging** 选项卡下,选择该应用,添加 [APNs 身份验证密钥](https://developer.apple.com/help/account/manage-keys/create-a-private-key)或者[证书](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns?language=objc)。 + +4. 查询 **Sender ID** 和生成密钥(JSON 文件),与 Android 应用相同。 + +### 在声网控制台上传 FCM 推送证书 + +登录即时通讯 IM SDK 成功后,可在声网控制台上传 FCM 推送证书。 + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Certificate**。 + +![image](push_multidevice_policy.png) + +5. 在 **Push Certificate** 页面,单击 **Add Push Certificate**。 在弹出的对话框中,选择 **Google** 页签,配置字段,单击**保存**。 + +[img](push_fcm_add_certificate.png) + +| 参数 | 类型 | 是否必需 | 描述 | +| :------------------- | :----- | :------- | :--------------- | +| **Certificate Type** | | 否 | 选择使用旧版证书还是 V1 证书。
  • **V1**:你需要配置 **Private Key**。推荐使用 V1 证书。
  • **Old Version**:你需要配置 **Push Key**。老版本证书即将被弃用。
| +| **Private Key** | file | 是 | 点击 **Upload** 上传推送证书文件(.json)。你需要在 Firebase 控制台的 **Project settings** > **Service accounts** 页面点击 **Generate new private key** 生成的推送证书文件(.json)。 | +| **Push Key** | String | 是 | FCM 的服务器密钥(Server Key)。你需在 Firebase 控制台的 **Project settings** > **Cloud Messaging** 页面,在 **Cloud Messaging API (Legacy)** 区域中获取服务器密钥。 | +| **Certificate Name** | String | 是 | 配置为 FCM 的发送者 ID。你可以在 FCM 控制台的 **Project settings** > **Cloud Messaging** 页面查看 **Sender ID** 参数的值。
证书名称是声网即时通讯服务器用于判断目标设备使用哪种推送通道的唯一条件。 | +| **Sound** | String | 否 | 接收方收到推送通知时的铃声标记。 | +| **Push Priority** | | 否 | 消息传递优先级,详见 [FCM 官网](https://firebase.google.cn/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message)。 | +| **Push Msg Type** | | 否 | 通过 FCM 向客户端发送的消息的类型,详见 [FCM 消息简介](https://firebase.google.cn/docs/cloud-messaging/concept-options#notifications_and_data_messages) 。
  • **Data**:数据消息,由客户端应用处理。
  • **Notification**:通知消息,由 FCM SDK 自动处理。
  • **Both**:可以通过 FCM 客户端发送通知消息和数据消息。
| + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +### 在客户端集成 FCM + +对于 React Native 平台,在客户端集成 FCM 分为三个步骤: + +1. 添加依赖。 +2. 添加原生平台配置。 +3. FCM 推送代码实现。 + +#### 添加依赖 + +```sh +yarn add @react-native-firebase/app @react-native-firebase/messaging react-native-agora-chat +``` + +#### 添加原生平台配置 + +**Android 平台** + +1. 下载 `google-services.json` 文件,放入你的项目中的以下路径中:`/android/app/google-services.json`。 + +2. 在你的 `/android/build.gradle` 文件中,添加 google-services 插件作为依赖: + +```groovy +buildscript { + dependencies { + classpath 'com.google.gms:google-services:4.3.15' + } +} +``` + +3. 将 google-services 插件添加到 `/android/app/build.gradle` 文件中,执行插件: + +```groovy +apply plugin: 'com.google.gms.google-services' // <- Add this line +``` + +**对于 iOS 平台** + +1. 修改 `Podfile` 配置文件: + +```ruby +# 设置 Reaction Native app 中集成的 Firebase SDK 的版本。 +$FirebaseSDKVersion = '10.12.0' +# 设置 Firebase 使用静态框架。 +$RNFirebaseAsStaticFramework = true +``` + +```ruby +target 'rn_firebase_push_demo' do + pod 'GoogleUtilities', :modular_headers => true + pod 'FirebaseCore', :modular_headers => true +end +``` + +2. 运行 `pod install` 命令在 `ios` 目录中安装依赖。 + +3. 在 Xcode 中打开 `/ios/{projectName}.xcworkspace` 文件。 + +4. 右击项目名称,选择 **Add files**,从本地选择下载的 `GoogleService-Info.plist` 文件,确保选择 `Copy items if needed`。 + +5. 为此,打开 `/ios/{projectName}/AppDelegate.mm` 文件(在 React Native 较早版本中打开 `AppDelegate.m`)。 + +6. 在文件顶部,在 `#import "AppDelegate.h"` 后面导入 Firebase SDK。 + +```objective-c +#import +``` + +7. 在 `didFinishLaunchingWithOptions` 方法中,在顶部添加以下代码: + +```objective-c +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [FIRApp configure]; +} +``` + +#### FCM 推送代码实现 + +1. 设置消息通知接收。 + +```typescript +React.useEffect(() => { + const sub1 = messaging().onMessage(async (remoteMessage) => { + // 进行离线消息通知的处理,例如打印日志和消息展示等。 + console.log("A new FCM message arrived!", JSON.stringify(remoteMessage)); + }); + return sub1; +}, []); +``` + +2. 初始化即时通讯 IM SDK。 + +```typescript +// 获取 device token。 +fcmToken.current = await messaging().getToken(); +// 推送设置。 +const pushConfig = new ChatPushConfig({ + deviceId: senderId, + deviceToken: fcmToken.current, +}); +// 在 ChatOptions 类中配置推送设置。 +let o = new ChatOptions({ + autoLogin: false, + appKey: appKey, + pushConfig: pushConfig, +}); +// 执行设置,初始化即时通讯 IM SDK。 +ChatClient.getInstance() + .init(o) + .then(() => { + // 初始化成功。 + }) + .catch((error) => { + // 初始化失败,返回错误信息。 + }); +``` + +3. 登录服务器。 + +```typescript +// 使用用户 ID 和 token 登录服务器。 +ChatClient.getInstance() + .loginWithAgoraToken(username, token) + .then(() => { + // 登录成功。 + }) + .catch((reason) => { + // 登录失败,返回错误信息。 + }); +``` + +4. 发送 device token 到服务器。 + +```typescript +// 发送 device token 到服务器。 +ChatClient.getInstance() + .updatePushConfig( + new ChatPushConfig({ deviceId: senderId, deviceToken: fcmToken.current }) + ) + .then(() => { + // 发送成功。 + }) + .catch((reason) => { + // 发送失败,返回错误信息。 + }); +``` + +## 测试 FCM 推送 + +在即时通讯 IM 中集成并启用 FCM 后,可测试推送是否成功集成。 + +### 前提条件 + +准备一台在海外正式发售的 Android 设备用于接收推送通知,确保该设备满足以下条件: + +- 使用国外 IP 地址与即时通讯 IM 建立连接。 +- 支持 Google GMS 服务(Google Mobile Services)。 +- 可以正常访问 Google 网络服务,否则该设备无法从 FCM 服务接收推送通知。 + +为了确保测试效果可靠,请避免使用模拟器进行测试。 + +### 测试步骤 + +1. 在设备上登录应用,并确认 device token 绑定成功。 + 可以查看日志或调用[获取用户详情的 RESTful 接口](https://docs.agora.io/en/agora-chat/restful-api/user-system-registration#querying-a-user)确认 device token 是否绑定成功。 +2. 开启应用通知栏权限。 +3. 杀掉应用进程。 +4. 在声网控制台发送测试消息。 + 在左侧导航栏中选择 **Operation Management** > **User**。在 Users 页面中,在对应用户 ID 的 **Action** 栏中选择 **Send Admin Message**。在弹出的对话框中选择消息类型,输入消息内容,然后点击 **Send**。 + +
在 **Push Certificate** 页面中证书列表中,在每个证书的 **Action** 一栏中,点击 **More**,会出现 **Test**,这里是直接调用第三方接口推送,而 **Users** 页面中的消息发送测试是先调用即时通讯 IM 的发消息的接口,满足条件后(即用户离线、推送证书有效且绑定了 device token)再调第三方的接口进行推送。
+ +5. 查看设备是否收到推送通知。 + +### 故障排除 + +1. 检查在即时通讯 IM 中是否正确集成或启用了 FCM 推送。 + 在左侧导航栏中选择 **Operation Management > User**。在用户管理页面中,在对应用户 ID 的 **Action** 栏中选择 **Push Certificate**。在弹出框中查看是否正确显示了证书名称和 device token。 +2. 检查是否在声网控制台上传了正确的 FCM 证书。 +3. 检查是否在聊天室中推送消息。聊天室不支持离线消息推送。 +4. 检查设备是否为国行手机的 ROM。一些品牌的国产手机不支持 GMS 服务,需替换为海外发售的设备。 diff --git a/agora_chat_en_draft/react_native/3_parsing.md b/agora_chat_en_draft/react_native/3_parsing.md new file mode 100644 index 0000000..a6ec95b --- /dev/null +++ b/agora_chat_en_draft/react_native/3_parsing.md @@ -0,0 +1,49 @@ +# 解析 FCM 推送字段 + +收到推送通知后,你需要解析数据。 + +重写 `FirebaseMessagingService.onMessageReceived` 方法可以在 `RemoteMessage` 对象中获取自定义扩展字段,示例代码如下: + +```typescript +messaging().onMessage(async (remoteMessage) => { + console.log("A new FCM message arrived!", JSON.stringify(remoteMessage)); + // "t":"receiver", + // "f":"fromUsername", + // "m":"msg_id", + // "g":"group_id", + // "e":{} +}); +``` + +| 参数 | 描述 | +| ---- | --------------- | +| `f` | 推送通知的发送方的用户 ID。 | +| `t` | 推送通知的接收方的用户 ID。 | +| `m` | 消息 ID。消息唯一标识符。 | +| `g` | 群组 ID,仅当消息为群组消息时,该字段存在。 | +| `e` | 用户自定义扩展字段。 | + +其中 `e` 为完全用户自定义扩展,数据来源为消息扩展的 `em_push_ext.custom`,数据结构如下: + +```json +{ + "em_push_ext": { + "custom": { + "key1": "value1", + "key2": "value2" + } + } +} +``` + +`RemoteMessage` 对象中的扩展信息的数据结构如下: + +```json +{ + "t": "receiver", + "f": "fromUsername", + "m": "msg_id", + "g": "group_id", + "e": {} +} +``` \ No newline at end of file diff --git a/agora_chat_en_draft/react_native/4_push_display.md b/agora_chat_en_draft/react_native/4_push_display.md new file mode 100644 index 0000000..6c7843e --- /dev/null +++ b/agora_chat_en_draft/react_native/4_push_display.md @@ -0,0 +1,172 @@ +# 设置推送通知的显示内容 + +通知收到后,通知栏中显示的推送标题和内容可通过以下方式设置,配置的优先级为由低到高: + +1. 设置推送通知的显示属性; +2. 使用默认推送模板; +3. 使用消息扩展字段; +4. 使用自定义推送模板。 + +## 设置推送通知的显示属性 + +你可以分别调用 `updatePushNickname` 和 `updatePushDisplayStyle` 方法设置推送通知中显示的昵称(`nickname`)和通知显示样式(`displayStyle`),确定通知栏中的推送标题和推送内容。 + +```typescript +ChatClient.getInstance() + .pushManager.updatePushNickname(nickname) + .then(() => { + console.log("Succeeded in updating the nickname."); + }) + .catch((reason) => { + console.log("Failed to update the nickname.", reason); + }); +``` + +```typescript +ChatClient.getInstance() + .pushManager.updatePushDisplayStyle(displayStyle) + .then(() => { + console.log("Succeeded in updating the display style."); + }) + .catch((reason) => { + console.log("Failed to update the display style.", reason); + }); +``` + +你可以调用 `fetchPushOptionFromServer` 方法获取推送通知中的显示属性,如以下代码示例所示: + +```typescript +ChatClient.getInstance() + .pushManager.fetchPushOptionFromServer() + .then(() => { + console.log("Succeeded in getting the push configurations."); + }) + .catch((reason) => { + console.log("Failed to get the push configuration.", reason); + }); +``` + +若要在通知栏中显示消息内容,需要设置通知显示样式 `displayStyle`。该参数有如下两种设置: + +- (默认)`Simple`:不论 `nickname` 是否设置,对于推送任何类型的消息,通知栏采用默认显示设置,即推送标题为“您有一条新消息”,推送内容为“请点击查看”。 +- `Summary`:显示消息内容。设置的昵称只在 `displayStyle` 为 `Summary` 时生效,在 `Simple` 时不生效。 + +下表以单聊文本消息为例介绍这显示属性的设置。 + +
对于群聊,下表中的“消息发送方的推送昵称”和“消息发送方的 IM 用户 ID”显示为“群组 ID”。
+| 参数设置 | 推送显示 | 图片 | +| :--------- | :----- |:------------- | +|
  • `displayStyle`:(默认)`Simple`
  • `nickname`:设置或不设置
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“请点击查看”
| push_displayattribute_1.png | +|
  • `displayStyle`:`Summary`
  • `nickname`:设置具体值
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“消息发送方的推送昵称:消息内容”
| push_displayattribute_2.png | +|
  • `displayStyle`:`Summary`
  • `nickname`:不设置
|
  • 推送标题:“您有一条新消息”
  • 推送内容:“消息发送方的 IM 用户 ID: 消息内容”
| push_displayattribute_3.png | + +## 使用默认推送模板 + +默认推送模板主要用于服务器提供的默认配置不满足你的需求时,可使你设置全局范围的推送标题和推送内容。例如,服务器提供的默认设置为中文和英文的推送标题和内容,你若需要使用韩语或日语的推送标题和内容,则可以设置对应语言的推送模板。 + +要使用默认模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建默认推送模板,模板名称为 `default`。设置完毕,消息推送时自动使用默认模板,创建消息时无需传入模板名称。 + +按照以下步骤在声网控制台创建默认推送模板: + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Template**,单击 **Add Push Template**,在弹出的对话框中配置字段,如下图所示。 + +![image](\agora_doc_source\en\markdown\agora-chat\images\push\push_add_template.png) + +5. 将 **Template Name** 设置为 **default**,然后设置 **Title** 和 **Content** 参数,点击 **OK**。 + +| 参数 | 类型 | 描述 | 是否必须 | +| :---------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------- | +| **Template Name** | String | 推送模板名称,默认模板为 **default**。 | Yes | +| **Title** | Array | 推送标题。可通过以下方式设置:
  • 输入固定的推送标题。
  • 使用内置变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入该参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。 | Yes | +| **Content** | Array | 推送内容。可通过以下方式设置:
  • 输入固定的推送内容。
  • 使用变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。 | Yes | + +## 使用消息扩展字段 + +创建推送消息时,你可以设置消息扩展字段自定义要显示的推送标题 `em_push_title` 和推送内容 `em_push_content`。 + +```typescript +msg.attributes = { + // 消息扩展字段。该字段为内置内置字段,字段名不可修改。 + em_apns_ext: { + em_push_title: "custom push title", // 自定义推送消息标题。该字段为内置内置字段,字段名不可修改。 + em_push_content: "custom push content", // 自定义推送消息内容。该字段为内置内置字段,字段名不可修改。 + }, +}; +``` + +自定义显示字段的数据结构如下: + +```java +{ + "em_apns_ext": { + "em_push_title": "custom push title", + "em_push_content": "custom push content" + } +} +``` + +## 使用自定义推送模板 + +使用自定义推送模板的步骤如下: + +1. 若使用自定义推送模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建自定义推送模板。**Add Push Template** 对话框中参数的描述,详见[使用默认推送模板](#使用默认推送模板)。使用自定义模板时,**Title** 和 **Content** 参数无论通过哪种方式设置,创建消息时均需通过扩展字段传入。 + +2. 创建消息时需通过使用扩展字段传入模板名称、推送标题和推送内容,通知栏中的推送标题和内容分别使用模板中的格式。 + +```typescript +// 下面以文本消息为例,其他类型的消息设置方法相同。 +const msg = ChatMessage.createTextMessage(targetId, content, targetType); +msg.attributes = { + em_push_template: { + name: "foo", + // 设置模板中推送标题的 value 数组。如果模板中指定的推送标题为占位数据,则在这里可自定义标题;若指定的标题为固定值,则使用该模板时标题为固定值。 + title_args: "title", + // 设置模板中的推送内容的 value 数组。如果模板中指定的模板内容为占位数据,则在这里可自定义内容;若指定的内容为固定值,则使用该模板时内容为固定值。 + content_args: "test", + }, +}; +ChatClient.getInstance() + .chatManager.sendMessage(msg, { + onError: (error) => {}, + onSuccess: (msg) => {}, + } as any) + .then(() => { + console.log("send message success"); + }) + .catch((reason) => { + console.log("set message fail.", reason); + }); +``` + +推送模板的 JSON 结构如下: + +```json +"em_push_template":{ + "name":"test6", + "title_args":[ + "test1" + ], + "content_args":[ + "{$fromNickname}", + "{$msg}" + ] +} +``` + +消息接收方可以调用 `selectPushTemplate` 方法传入推送模板名称,选择要使用的模板。 + +
若发送方在发送消息时使用了推送模板,则推送通知栏中的显示内容以发送方的推送模板为准。
+ +```typescript +ChatClient.getInstance() + .pushManager.selectPushTemplate(templateName) + .then(() => { + console.log("Succeeded in updating the nickname."); + }) + .catch((reason) => { + console.log("Failed to update the nickname.", reason); + }); +``` diff --git a/agora_chat_en_draft/react_native/5_dns_notificationmode.md b/agora_chat_en_draft/react_native/5_dns_notificationmode.md new file mode 100644 index 0000000..c7a76fa --- /dev/null +++ b/agora_chat_en_draft/react_native/5_dns_notificationmode.md @@ -0,0 +1,173 @@ +# 设置推送通知方式和免打扰模式 + +为优化用户在处理大量推送通知时的体验,即时通讯 IM 在 app 和会话层面提供了推送通知方式和免打扰模式的细粒度选项。 + +**推送通知方式** + +| 推送通知方式参数 | 描述 | App | 单聊和群聊会话 | +| :--------------- | :---------------------- | :----------- | +| `ALL` | 接收所有离线消息的推送通知。 | ✓ | ✓ | +| `MENTION_ONLY` | 仅接收提及消息的推送通知。
该参数推荐在群聊中使用。若提及一个或多个用户,需在创建消息时对 `ext` 字段传 "em_at_list":["user1", "user2" ...];若提及所有人,对该字段传 "em_at_list":"all"。 | ✓ | ✓ | +| `NONE` | 不接收离线消息的推送通知。 | ✓ | ✓ | + +会话级别的推送通知方式设置优先于 app 级别的设置,未设置推送通知方式的会话默认采用 app 的设置。 + +例如,假设 app 的推送方式设置为 `MENTION_ONLY`,而指定会话的推送方式设置为 `ALL`。你会收到来自该会话的所有推送通知,而对于其他会话来说,你只会收到提及你的消息的推送通知。 + +**免打扰模式** + +你可以在 app 级别指定免打扰时间段和免打扰时长,即时通讯 IM 在这两个时间段内不发送离线推送通知。若既设置了免打扰时间段,又设置了免打扰时长,免打扰模式的生效时间为这两个时间段的累加。 + +免打扰时间参数的说明如下表所示: + +| 免打扰时间参数 | 类型 |描述 | 应用范围 | +| :------------------- | :--------------------------- | :--------------------------- | :------------------- | +| `startTime & endTime` | Int |每天定时触发离线推送免打扰的时间段,采用 24 小时制,精确到分钟,格式为 H:M-H:M,例如 8:30-10:0,开始时间和结束时间中的小时数和分钟数的取值范围分别为 [0,23] 和 [0,59]。免打扰时间段的设置说明如下:
- 开始时间和结束时间设置后,免打扰模式每天定时触发。例如,若该时间段设置为 `8:0`-`10:0`,免打扰模式在每天的 8:00-10:00 内生效。若你在 11:00 设置开始时间为 `8:0`,结束时间为 `12:0`,则免打扰模式在当天的 11:00-12:00 生效,以后每天均在 8:00-12:00 生效。
- 若开始时间和结束时间相同,免打扰模式则全天生效。不过,若设置为 `0:0`-`0:0`,则关闭免打扰模式。
- 若结束时间早于开始时间,则免打扰模式在每天的开始时间到次日的结束时间内生效。例如,开始时间为 `10:0`,结束时间为 `8:0`,则免打扰模式的在当天的 10:00 到次日的 8:00 生效。
- 目前仅支持在每天的一个指定时间段内开启免打扰模式,不支持多个免打扰时间段,新的设置会覆盖之前的设置。
- 若该参数和免打扰时长 `expireTimestamp` 均设置,免打扰模式当日在这两个时间段均生效,例如,例如,上午 8:00 将免打扰的时间段设置为 8:0-10:0,免打扰时长设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。 | 仅针对 app 生效,对单聊或群聊不生效。 | +| `expireTimestamp` | Int |免打扰时长,单位为毫秒。免打扰时长最长不超过 7 天。
与免打扰时间段(`startTime & endTime`)的设置每天生效不同,该参数为一次有效。设置后立即生效,例如,上午 8:00 将 app 层级的免打扰时长设置为 4 个小时,则 app 在当天 8:00-12:00 处于免打扰模式。
- 若该参数和 `startTime & endTime` 均设置,免打扰模式当日在这两个时间段均生效,例如,上午 8:00 将 app 级的 `startTime & endTime` 设置为 8:00-10:00,免打扰时长设置为 4 个小时,则 app 在当前 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。 | App 或单聊/群聊会话。| + +若在免打扰时段或时长生效期间需要对指定用户推送消息,需设置[强制推送](./7_push_extension#强制推送)。 + +**推送通知方式与免打扰时间设置之间的关系** + +对于 app 和 app 中的所有会话,免打扰模式的设置优先于推送通知方式的设置。例如,假设在 app 级别指定了免打扰时间段,并将指定会话的推送通知方式设置为 `ALL`。App 在指定的时间段内进入免打扰模式,你不会收到任何推送通知。 + +或者,假设为会话指定了免打扰时间段,而 app 没有任何免打扰设置并且其推送通知方式设置为 `ALL`。在指定的免打扰时间段内,你不会收到来自该会话的任何推送通知,而所有其他会话的推送保持不变。 + +## 设置 app 的推送通知 + +你可以调用 `setSilentModeForAll` 设置 app 级别的推送通知,并通过指定 `ChatSilentModeParam` 字段设置推送通知方式和免打扰模式,如下代码示例所示: + +```typescript +// convId:会话 ID。 +// convType:会话类型。 +// 将推送通知方式设置为 `MENTION_ONLY`。 +const option = ChatSilentModeParam.constructorWithNotification( + ChatPushRemindType.MENTION_ONLY +); +// 将免打扰时长设置为 10 分钟。 +const option = ChatSilentModeParam.constructorWithDuration(10); +// 将免打扰时间段设置为 10:10-11:00。 +const option = ChatSilentModeParam.constructorWithPeriod({ + startTime: new ChatSilentModeTime({ hour: 10, minute: 10 }), + endTime: new ChatSilentModeTime({ hour: 11, minute: 10 }), +}); +// 设置 app 的离线推送通知。 +ChatClient.getInstance() + .pushManager.setSilentModeForAll(option) + .then(() => { + console.log("Succeeded in setting the push notification."); + }) + .catch((reason) => { + console.log("Failed to set the push notification.", reason); + }); +``` + +## 获取 app 的推送通知设置 + +你可以调用 `fetchSilentModeForAll` 获取 app 级别的推送通知设置,如以下代码示例所示: + +```typescript +ChatClient.getInstance() + .pushManager.fetchSilentModeForAll() + .then((result) => { + console.log("Succeeded in getting the push notification settings of the app.", result); + }) + .catch((reason) => { + console.log("Failed to get the push notification settings of the app.", reason); + }); +``` + +## 设置单个会话的推送通知 + +你可以调用 `setSilentModeForConversation` 方法设置指定会话的推送通知,并通过指定 `ChatSilentModeParam` 字段设置推送通知方式和免打扰模式,如以下代码示例所示: + +```typescript +// convId:会话 ID。 +// convType:会话类型。 +// 将推送通知方式设置为 `MENTION_ONLY`。 +const option = ChatSilentModeParam.constructorWithNotification( + ChatPushRemindType.MENTION_ONLY +); +// 将免打扰时长设置为 10 分钟。 +const option = ChatSilentModeParam.constructorWithDuration(10); +// 将免打扰时间段设置为 10:10-11:00。 +const option = ChatSilentModeParam.constructorWithPeriod({ + startTime: new ChatSilentModeTime({ hour: 10, minute: 10 }), + endTime: new ChatSilentModeTime({ hour: 11, minute: 10 }), +}); +// 设置指定会话的推送通知。 +ChatClient.getInstance() + .pushManager.setSilentModeForConversation({ + convId, + convType, + option, + }) + .then(() => { + console.log("Succeeded in getting the push notification settings of the conversation."); + }) + .catch((reason) => { + console.log("Failed to get the push notification settings of the conversation.", reason); + }); +``` + +## 获取单个会话的推送通知 + +你可以调用 `fetchSilentModeForConversation` 方法获取指定会话的推送通知设置,如以下代码示例所示: + +```typescript +// convId:会话 ID。 +// convType:会话类型。 +ChatClient.getInstance() + .pushManager.fetchSilentModeForConversation({ + convId, + convType, + }) + .then(() => { + console.log("Succeeded in getting the push notification settings of the conversation."); + }) + .catch((reason) => { + console.log("Failed to get the push notification settings of the conversation.", reason); + }); +``` + +## 获取多个会话的推送通知设置 + +1. 你可以在每次调用中最多获取 20 个会话的推送通知设置。 + +2. 如果会话使用了 app 设置或其推送通知设置已过期,则返回的字典不包含此会话。 + +你可以调用 `fetchSilentModeForConversations` 方法获取多个会话的推送通知设置,如以下示例代码所示: + +```typescript +// conversations:会话列表。 +ChatClient.getInstance() + .pushManager.fetchSilentModeForConversations(conversations) + .then(() => { + console.log("Succeeded in getting the conversation list."); + }) + .catch((reason) => { + console.log("Failed to get the conversation list.", reason); + }); +``` + +## 清除单个会话的推送通知方式的设置 + +你可以调用 `removeSilentModeForConversation` 方法清除指定会话的推送通知方式的设置。清除后,默认情况下,该会话会使用 app 的设置。 + +以下代码示例显示了如何清除会话的推送通知方式: + +```typescript +// convId:会话 ID。 +// convType:会话类型。 +ChatClient.getInstance() + .pushManager.removeSilentModeForConversation({ + convId, + convType, + }) + .then(() => { + console.log("Succeeded in deleting the push notification settings of the conversation."); + }) + .catch((reason) => { + console.log("Failed to delete the push notification settings of the conversation.", reason); + }); +``` \ No newline at end of file diff --git a/agora_chat_en_draft/react_native/6_push_translation.md b/agora_chat_en_draft/react_native/6_push_translation.md new file mode 100644 index 0000000..3a2ae09 --- /dev/null +++ b/agora_chat_en_draft/react_native/6_push_translation.md @@ -0,0 +1,18 @@ +# 设置推送翻译 + +推送通知与翻译功能协同工作。如果用户启用[自动翻译](./agora_chat_translation_rn)功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 + +作为接收方,你可以设置你在离线时希望接收的推送通知的首选语言。如果翻译后消息的语言匹配你的设置,则翻译后消息显示在推送通知栏;否则,将显示原始消息。 + +以下示例代码显示如何设置和获取推送通知的首选语言: + +```typescript +ChatClient.getInstance() + .pushManager.setPreferredNotificationLanguage(languageCode) + .then(() => { + console.log("Succeeded in setting the preferred notification language."); + }) + .catch((reason) => { + console.log("Failed to set the preferred notification language.", reason); + }); +``` \ No newline at end of file diff --git a/agora_chat_en_draft/react_native/7_push_extension.md b/agora_chat_en_draft/react_native/7_push_extension.md new file mode 100644 index 0000000..dc15274 --- /dev/null +++ b/agora_chat_en_draft/react_native/7_push_extension.md @@ -0,0 +1,64 @@ +# 设置推送扩展功能 + +你可以利用扩展字段实现自定义推送设置,本文以强制推送和发送静默消息为例介绍如何实现推送扩展功能。 + +## 设置自定义推送字段 + +创建推送消息时,可以在消息中添加自定义字段,满足个性化业务需求。 + +```typescript +msg.attributes = { + // 消息扩展字段。 + "em_push_ext": { + "custom": { + "key1": "value1", + "key2": "value2" + } + }, +}; +``` + +自定义字段的数据结构如下: + +```json +{ + "em_push_ext": { + "custom": { + "key1": "value1", + "key2": "value2" + } + } +} +``` + +| 参数 | 描述 | +| :--------------- | :----------------- | +| `em_push_ext` | Agora 消息推送扩展固定值,不可修改。 | +| `custom` | 消息扩展,使用扩展的方式向推送中添加自定义字段,该值为固定值。 | +| `key1`/`key2` | 自定义消息推送扩展的具体内容。 | + +### 强制推送 + +设置强制推送后,用户发送消息时会忽略接收方的免打扰设置,不论是否处于免打扰时间段都会正常向接收方推送消息。 + +```typescript +// 下面以文本消息为例,其他类型的消息设置方法相同。 +msg.attributes = { + // 是否为强制推送。该字段为内置字段,取值如下:`true`:强制推送;(默认)`false`:非强制推送。 + em_force_notification: true, +}; +``` + +### 发送静默消息 + +发送静默消息指发送方在发送消息时设置不推送消息,即用户离线时,即时通讯 IM 服务不会通过第三方厂商的消息推送服务向该用户的设备推送消息通知。因此,用户不会收到消息推送通知。当用户再次上线时,会收到离线期间的所有消息。 + +发送静默消息和免打扰模式下均为不推送消息,区别在于发送静默消息为发送方在发送消息时设置,而免打扰模式为接收方设置在指定时间段内不接收推送通知。 + +```typescript +// 下面以文本消息为例,其他类型的消息设置方法相同。 +msg.attributes = { + // 是否发送静默消息。该字段为内置字段,取值如下:`true`:发送静默消息;(默认)`false`:推送该消息。 + em_ignore_notification: true, +}; +``` \ No newline at end of file diff --git a/agora_chat_en_draft/web/agora_chat_push_web.md b/agora_chat_en_draft/web/agora_chat_push_web.md new file mode 100644 index 0000000..75c25fa --- /dev/null +++ b/agora_chat_en_draft/web/agora_chat_push_web.md @@ -0,0 +1,356 @@ +# 离线推送概述 + +即时通讯 IM 支持集成离线推送服务,为开发者提供低延时、高送达、高并发、不侵犯用户个人数据的离线消息推送服务。**即时通讯 IM Web SDK 本身不支持离线推送,但支持移动平台的离线推送配置。** + +客户端断开连接或应用进程被关闭等原因导致用户离线时,即时通讯 IM 会通过 FCM 消息推送服务向该离线用户的设备推送消息通知。当用户再次上线时,服务器会将离线期间的消息发送给用户(这里角标表示的是离线消息数,并不是实际的未读消息数)。 + +若应用在后台运行且用户仍为在线状态,即时通讯 IM 不会向用户推送消息通知。多设备登录时,可在声网控制台的 **Push Certificate** 页面配置推送在所有设备离线或任一设备离线时发送推送消息,该配置对所有推送通道生效。 + +
1. 应用在后台运行或手机锁屏等情况,若客户端未断开与声网服务器的连接,则即时通讯 IM 不会收到离线推送通知。
2. 多端登录时若有设备被踢下线,即使接入了 IM 离线推送,也收不到离线推送消息。
+ +除了满足用户离线条件外,要使用第三方离线推送,用户还需声网控制台配置推送证书信息,例如对于 FCM 推送,需配置 **Private Key** 和 **Certificate Name**,并调用 `uploadPushToken` 方法向声网即时通讯服务器上传 device token。 + +```javascript +const params = { + deviceId: WebIM.conn.clientResource, // 设备 ID,用于标识设备。 + deviceToken: 'deviceToken', // 推送 token,用于标识每台设备上的每个应用。 + notifierName: 'PUSH_CERT_NAME', // 推送服务的证书名称。 +}; + +WebIM.conn.uploadPushToken(params); +``` + +## 技术原理 + +即时通讯 IM SDK 可实现以下功能: + +- 设置 app 的推送通知; +- 获取 app 的推送通知; +- 设置会话的推送通知; +- 获取会话的推送通知; +- 清除会话的推送通知; +- 设置推送翻译; +- 设置推送模板; +- 设置强制推送; +- 发送静默消息。 + +## 前提条件 + +使用离线推送前,确保满足以下条件: + +- 已经完成即时通讯 IM SDK。详见[快速开始](https://docs.agora.io/en/agora-chat/get-started/get-started-sdk?platform=web)。 +- 了解即时通讯 IM 套餐包中的 API 调用频率限制,详见[使用限制](./agora_chat_limitation)。 + +## 实现方法 + +为优化用户在处理大量推送通知时的体验,即时通讯 IM 在 app 和会话层面提供了推送通知方式和免打扰模式的细粒度选项。 + +**推送通知方式** + +| 参数 | 描述 | App | 单聊和群聊会话 | +| :------- | :----- | :----- | :----- | +| `ALL` | 接收所有离线消息的推送通知。 | ✓ | ✓ | +| `AT` | 仅接收提及消息的推送通知。
该参数推荐在群聊中使用。若提及一个或多个用户,需在创建消息时对 `ext` 字段传 "em_at_list":["user1", "user2" ...];若提及所有人,对该字段传 "em_at_list":"all"。 | ✓ | ✓ | +| `NONE` | 不接收离线消息的推送通知。 | ✓ | ✓ | + +会话级别的推送通知方式设置优先于 app 级别的设置,未设置推送通知方式的会话默认采用 app 的设置。 + +例如,假设 app 的推送方式设置为 `AT`,而指定会话的推送方式设置为 `ALL`。你会收到来自该会话的所有推送通知,而对于其他会话来说,你只会收到提及你的消息的推送通知。 + +**免打扰模式** + +在你完成 SDK 初始化和成功登录 app 后,可以对 app 以及各类型的会话开启离线推送功能以及通过设置免打扰模式关闭推送。 + +你可以在 app 级别指定免打扰时间段和免打扰时长,即时通讯 IM 在这两个时间段内不发送离线推送通知。若既设置了免打扰时间段,又设置了免打扰时长,免打扰模式的生效时间为这两个时间段的累加。 + +免打扰时间参数的说明如下表所示: + +| 参数 | 描述 | App | 单聊和群聊会话 | +| :--------| :----- | :------------------- | :----- | +| `startTime & endTime` | 每天定时触发离线推送免打扰的时间段,采用 24 小时制,精确到分钟,格式为 H:M-H:M,例如 8:30-10:0,开始时间和结束时间中的小时数和分钟数的取值范围分别为 [0,23] 和 [0,59]。免打扰时间段的设置说明如下:
  • 开始时间和结束时间设置后,免打扰模式每天定时触发。例如,若该时间段设置为 `8:0`-`10:0`,免打扰模式在每天的 8:00-10:00 内生效。若你在 11:00 设置开始时间为 8:0,结束时间为 12:0,则免打扰模式在当天的 11:00-12:00 生效,以后每天均在 8:00-12:00 生效。
  • 若开始时间和结束时间相同,免打扰模式则全天生效。不过,若设置为 `0:0-0:0`,则关闭免打扰模式。
  • 若结束时间早于开始时间,则免打扰模式在每天的开始时间到次日的结束时间内生效。例如,开始时间为 `10:0`,结束时间为 `8:0`,则免打扰模式的在当天的 10:00 到次日的 8:00 生效。
  • 目前仅支持在每天的一个指定时间段内开启免打扰模式,不支持多个免打扰时间段,新的设置会覆盖之前的设置。
  • 若该参数和 `duration` 均设置,免打扰模式当日在这两个时间段均生效,例如,例如,上午 8:00 将 `startTime & endTime` 设置为 8:0-10:0,`duration` 设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。
| ✓ | ✗ | +| `duration` | 免打扰时长,单位为分钟。免打扰时长的取值范围为 [0,10080],`0` 表示该参数无效,`10080` 表示免打扰模式持续 7 天。
与免打扰时间段的设置每天生效不同,该参数为一次有效。设置后立即生效,例如,上午 8:00 将 app 层级的 `duration` 设置为 240 分钟(4 个小时),则 app 在当天 8:00-12:00 处于免打扰模式。
- 若该参数和 `startTime & endTime` 均设置,免打扰模式当日在这两个时间段均生效,例如,上午 8:00 将 app 级的 `startTime & endTime` 设置为 8:00-10:00,免打扰时长设置为 240 分钟(4 个小时),则 app 在当前 8:00-12:00 和以后每天 8:00-10:00 处于免打扰模式。 | ✓ | ✓ | + +若在免打扰时段或时长生效期间需要对指定用户推送消息,需设置[强制推送](./7_push_extension#forced)。 + +**推送通知方式与免打扰时间设置之间的关系** + +对于 app 和 app 中的所有会话,免打扰模式的设置优先于推送通知方式的设置。例如,假设在 app 级别指定了免打扰时间段,并将指定会话的推送通知方式设置为 `ALL`。App 在指定的时间段内进入免打扰模式,你不会收到任何推送通知。 + +或者,假设为会话指定了免打扰时间段,而 app 没有任何免打扰设置并且其推送通知方式设置为 `ALL`。在指定的免打扰时间段内,你不会收到来自该会话的任何推送通知,而所有其他会话的推送保持不变。 + +### 设置 app 的推送通知 + +你可以调用 `setSilentModeForAll` 方法设置 app 级别的推送通知,并通过指定 `paramType` 字段设置推送通知方式和免打扰模式,如下代码示例所示: + +```javascript +/** + options // 推送通知配置选项。 + options: { + paramType: 0, // 推送通知方式。 + remindType: 'ALL' // 可设置为 `ALL`、`AT` 或 `NONE`。 + } + options: { + paramType: 1, // 免打扰时长。 + duration: 7200000 // 免打扰时长,单位为毫秒。 + } + options: { + paramType: 2, // 免打扰时间段。 + startTime: { + hours: 8, // 免打扰时间段的开始时间中的小时数。 + minutes: 0 // 免打扰时间段的开始时间中的分钟数。 + }, + endTime: { + hours: 12, // 免打扰时间段的结束时间中的小时数。 + minutes: 0 // 免打扰时间段的结束时间中的分钟数。 + } + } +*/ +const params = { + options: { + paramType: 0, + remindType: "ALL", + }, +}; +connection.setSilentModeForAll(params); +``` + +### 获取 app 的推送通知设置 + +你可以调用 `getSilentModeForAll` 获取 app 的推送通知设置,示例代码如下: + +```javascript +connection.getSilentModeForAll(); +``` + +### 设置单个会话的推送通知 + +你可以调用 `setSilentModeForConversation` 设置指定会话的推送通知设置,示例代码如下: + +```javascript +/** + const params = { + conversationId: 'conversationId', // 会话 ID:单聊为对方用户 ID,群聊为群组 ID。 + type: 'singleChat', // 会话类型:singleChat(单聊)、groupChat(群聊)。 + options: { + paramType: 0, // 推送通知方式。 + remindType: 'ALL' // 可设置为 `ALL`、`AT` 或 `NONE`。 + } + } + + const params = { + conversationId: 'conversationId', + type: 'groupChat', + options: { + paramType: 1, // 免打扰时长。 + duration: 7200000 // 免打扰时长,单位为毫秒。 + } + } + + const params = { + conversationId: 'conversationId', + type: 'chatRoom', + options: { + paramType: 2, // 免打扰时间段。 + startTime: { + hours: 8, // 免打扰时间段的开始时间中的小时数。 + minutes: 0 // 免打扰时间段的开始时间中的分钟数。 + }, + endTime: { + hours: 12, // 免打扰时间段的结束时间中的小时数。 + minutes: 0 // 免打扰时间段的结束时间中的分钟数。 + } + } + } +*/ +const params = { + conversationId: "conversationId", + type: "groupChat", + options: { + paramType: 0, + remindType: "ALL", + }, +}; +connection.setSilentModeForConversation(params); +``` + +### 获取单个会话的推送通知设置 + +调用 `getSilentModeForConversation` 获取单个会话的推送通知设置,示例代码如下: + +```javascript +const params = { + conversationId: "conversationId", // 会话 ID:单聊为对方用户 ID,群聊为群组 ID。 + type: "singleChat", // 会话类型:singleChat 为单聊,groupChat 为群聊。 +}; +connection.getSilentModeForConversation(params); +``` + +### 获取多个会话的推送通知设置 + +1. 每次最多可获取 20 个会话的推送通知设置。 +2. 如果会话使用了 app 设置或其推送通知设置已过期,则返回的字典不包含此会话。 + +你可以调用 `getSilentModeForConversations` 获取多个会话的推送通知设置,示例代码如下: + +```javascript +const params = { + conversationList: [ + { + id: "conversationId", // 会话 ID:单聊为对方用户 ID,群聊为群组 ID。 + type: "singleChat", // 会话类型:singleChat 为单聊,groupChat 为群聊。 + }, + { + id: "conversationId", + type: "groupChat", + }, + ], +}; +connection.getSilentModeForConversations(params); +``` + +### 清除单个会话的推送通知方式的设置 + +你可以调用 `clearRemindTypeForConversation` 方法清除指定会话的推送通知方式的设置。清除后,默认情况下,此会话会使用 app 的设置。示例代码如下: + +```javascript +const params = { + conversationId: "conversationId", // 会话 ID:单聊为对方用户 ID,群聊为群组 ID。 + type: "groupChat", // 会话类型:singleChat 为单聊,groupChat 为群聊。 +}; +connection.clearRemindTypeForConversation(params); +``` + +### 设置推送翻译 + +推送通知与翻译功能配合使用。如果用户启用[自动翻译](./agora_chat_translation_web)功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 + +作为接收方,你可以设置你在离线时希望接收的推送通知的首选语言。如果翻译后消息的语言匹配你的首选语言,则翻译后的消息显示在推送通知中;否则,将显示原始消息。 + +你可以调用 `setPushPerformLanguage` 方法设置推送通知的首选语言,示例代码如下: + +```javascript +// 设置推送通知的首选语言。 +const params = { + language: "EU", +}; +connection.setPushPerformLanguage(params); + +// 获取推送通知的首选语言。 +connection.getPushPerformLanguage(); +``` + +### 设置推送模板 + +默认推送模板主要用于服务器提供的默认配置不满足你的需求时,可使你设置全局范围的推送标题和推送内容。例如,服务器提供的默认设置为中文和英文的推送标题和内容,你若需要使用韩语或日语的推送标题和内容,则可以设置对应语言的推送模板。 + +#### 使用默认推送模板 + +要使用默认模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建默认推送模板,模板名称为 `default`。设置完毕,消息推送时自动使用默认模板,创建消息时无需传入模板名称。 + +按照以下步骤在声网控制台创建默认推送模板: + +1. 登录[声网控制台](https://console.agora.io/),在左侧导航栏中单击 **Project Management**。 +2. 在 **Project Management** 页面上,在启用了即时通讯 IM 的项目的 **Action** 一栏中单击 **Config**。 +3. 在 **Edit Project** 页面的 **Features** 区域,单击 **Chat** 对应的 **Enable/Config**。 +4. 在项目配置页面,选择 **Features** > **Push Template**,单击 **Add Push Template**,在弹出的对话框中配置字段,如下图所示。 + +![image](\agora_doc_source\en\markdown\agora-chat\images\push\push_add_template.png) + +5. 将 **Template Name** 设置为 **default**,然后设置 **Title** 和 **Content** 参数,点击 **OK**。 + +| 参数 | 类型 | 描述 | 是否必须 | +| :--------- | :----- | :----- | :----- | +| **Template Name** | String | 推送模板名称,默认模板为 **default**。 | Yes | +| **Title** | Array | 推送标题。可通过以下方式设置:
  • 输入固定的推送标题。
  • 使用内置变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入该参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。 | Yes | +| **Content** | Array | 推送内容。可通过以下方式设置:
  • 输入固定的推送内容。
  • 使用变量,输入 **{$fromNickname}, {$msg}**。
  • 通过 value 数组设置自定义变量,字段格式为: **{0} {1} {2} ... {n}**。

若使用默认模板,前两种设置方式在创建消息时无需传入参数,服务器自动获取,第三种设置方式则需要通过扩展字段传入。| Yes | + +#### 使用自定义推送模板 + +使用自定义推送模板的步骤如下: + +1. 若使用自定义推送模板,你需要在声网控制台或[调用 RESTful 接口](./agora_chat_restful_push#set-up-push-templates)创建自定义推送模板。**Add Push Template** 对话框中参数的描述,详见[使用默认推送模板](#使用默认推送模板)。使用自定义模板时,**Title** 和 **Content** 参数无论通过哪种方式设置,创建消息时均需通过扩展字段传入。 + +2. 创建消息时需通过使用扩展字段传入模板名称、推送标题和推送内容,通知栏中的推送标题和内容分别使用模板中的格式。 + +```javascript +// 下面以文本消息为例,其他类型的消息设置方法相同。 + +const sendTextMsg = () => { + let option: AgoraChat.CreateTextMsgParameters = { + chatType: chatType, + type: "txt", + to: targetUserId, + msg: msgContent, + ext: { + em_push_template: { + name: "templateName", // 设置推送模板名称。 + title_args: ["titleValue1"], // 设置模板中推送标题的 value 数组。如果模板中指定的推送标题为占位数据,则在这里可自定义标题;若指定的标题为固定值,则使用该模板时标题为固定值。 + content_args: ["contentValue1"], // 设置模板中的推送内容的 value 数组。如果模板中指定的模板内容为占位数据,则在这里可自定义内容;若指定的内容为固定值,则使用该模板时内容为固定值。 + }, + }, + }; + let msg = AC.message.create(option); + connection.send(msg); +}; +``` + +推送模板的 JSON 结构如下: + +```json +"em_push_template":{ + "name":"test6", + "title_args":[ + "test1" + ], + "content_args":[ + `${fromNickname}`, + `${msg}` + ] +} +``` + +### 强制推送 + +设置强制推送后,用户发送消息时会忽略接收方的免打扰设置,不论是否处于免打扰时间段都会正常向接收方推送消息。 + +```javascript +// 下面以文本消息为例,其他类型的消息设置方法相同。 +const sendTextMsg = () => { + let option: AgoraChat.CreateTextMsgParameters = { + chatType: chatType, + type: "txt", + to: targetUserId, + msg: msgContent, + ext: { + // 设置是否为强制推送,该字段为内置内置字段,取值如下:`YES`:强制推送;(默认)`NO`:非强制推送。 + em_force_notification: "YES" + }, + }; + let msg = AC.message.create(option); + connection.send(msg); +}; +``` + +### 发送静默消息 + +发送静默消息指发送方在发送消息时设置不推送消息,即用户离线时,即时通讯 IM 服务不会通过推送服务向该用户的设备推送消息通知。因此,用户不会收到消息推送通知。当用户再次上线时,会收到离线期间的所有消息。 + +发送静默消息和免打扰模式下均为不推送消息,区别在于发送静默消息为发送方在发送消息时设置,而免打扰模式为接收方设置在指定时间段内不接收推送通知。 + +```javascript +// 下面以文本消息为例,其他类型的消息设置方法相同。 +const sendTextMsg = () => { + let option: AgoraChat.CreateTextMsgParameters = { + chatType: chatType, + type: "txt", + to: targetUserId, + msg: msgContent, + ext: { + // 设置是否发送静默消息。该字段为内置内置字段,取值如下:`YES`:发送静默消息;(默认)`NO`:推送该消息。 + em_ignore_notification: "NO" + }, + }; + let msg = AC.message.create(option); + connection.send(msg); +}; +```