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。
+
+## 推送流程
+
+
+
+消息推送流程如下:
+
+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 证书。- **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。- 对于新版证书,你可以在 [Firebase 控制台](https://console.firebase.google.com)的 **Project settings** > **Cloud Messaging** 页面查看 **Sender ID** 参数的值。
- 对于旧版证书,你需在 [Firebase 控制台](https://console.firebase.google.com)的 ***Project settings > Cloud Messaging** 页面中,在 **Cloud Messaging API (Legacy)** 区域中获取发送者 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 客户端发送通知消息和数据消息。
|
+
+#### **旧版证书无缝切换至 V1 证书**
+
+旧版 HTTP 或 XMPP API 于 2024 年 6 月 20 日停用,请尽快切换到最新的 FCM API(HTTP v1)版本证书。详见 [FCM 控制台](https://console.firebase.google.com)。请确保切换过程中上传的 V1 证书可用,因为执行转换证书后,旧证书会被删除,若此时新证书不可用会导致推送失败。
+
+你可以参考以下步骤从旧版证书无缝切换到 V1 新证书:
+
+1. 在 **Push Certificate** 页面的旧版证书的 **Action** 栏中点击 **Edit**。
+
+
+
+2. 在 **Edit Push Certificate** 窗口的 **Google** 页签,将**Certificate Type**切换为 **V1**。
+
+
+
+3. 点击 **Upload** 上传本地保存的 V1 证书文件(.json)。
+
+
+
+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**,在弹出的对话框中配置字段,如下图所示。
+
+
+
+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