From a734483b78e8d1691c59d95db2ce1108550919c0 Mon Sep 17 00:00:00 2001
From: shanjingheng <1198955192@qq.com>
Date: Mon, 25 Sep 2023 19:04:26 +0800
Subject: [PATCH] =?UTF-8?q?(update):=20v1,v2=E6=96=87=E6=A1=A3=E5=8C=BA?=
=?UTF-8?q?=E5=88=86=E6=96=87=E6=A1=A3=E7=B1=BB=E5=9E=8B=E4=B8=8B=E6=8B=89?=
=?UTF-8?q?=E8=8F=9C=E5=8D=95=E5=86=85=E5=AE=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/.vuepress/components/PlatformSwitch.vue | 87 +-
docs/document/v1/electron/appendix.md | 53 +
docs/document/v1/electron/chatmanage.md | 458 ++++++++
docs/document/v1/electron/demo.md | 6 +
docs/document/v1/electron/group_manage.md | 1018 +++++++++++++++++
docs/document/v1/electron/message.md | 257 +++++
docs/document/v1/electron/multi_device.md | 23 +
docs/document/v1/electron/overview.md | 152 +++
docs/document/v1/electron/quickstart.md | 228 ++++
docs/document/v1/electron/releasenote.md | 59 +
docs/document/v1/electron/room_manage.md | 106 ++
.../document/v1/electron/user_relationship.md | 338 ++++++
12 files changed, 2752 insertions(+), 33 deletions(-)
create mode 100644 docs/document/v1/electron/appendix.md
create mode 100644 docs/document/v1/electron/chatmanage.md
create mode 100644 docs/document/v1/electron/demo.md
create mode 100644 docs/document/v1/electron/group_manage.md
create mode 100644 docs/document/v1/electron/message.md
create mode 100644 docs/document/v1/electron/multi_device.md
create mode 100644 docs/document/v1/electron/overview.md
create mode 100644 docs/document/v1/electron/quickstart.md
create mode 100644 docs/document/v1/electron/releasenote.md
create mode 100644 docs/document/v1/electron/room_manage.md
create mode 100644 docs/document/v1/electron/user_relationship.md
diff --git a/docs/.vuepress/components/PlatformSwitch.vue b/docs/.vuepress/components/PlatformSwitch.vue
index e23a553a5..aab20a1b5 100644
--- a/docs/.vuepress/components/PlatformSwitch.vue
+++ b/docs/.vuepress/components/PlatformSwitch.vue
@@ -54,39 +54,9 @@ const PLATFORM_ICON_MAP = {
},
}
-const platform = ref('android')
-let version = ''
-const platformIcon = computed(() => PLATFORM_ICON_MAP[platform.value]?.activeIcon)
-const route = useRoute()
-const router = useRouter()
-watch(()=>route.path, ()=> {
- if (route.path.indexOf('/document') == 0) {
- version = route.path.split('/')[2]
- platform.value = route.path.split('/')[3]
- }
-}, {immediate:true})
-
+const V1_PLATFORM = ['android', 'ios', 'web', 'applet', 'electron', 'server-side']
-// 切换平台,如果有相同路径的route就直接跳转
-const onChange = (platform) => {
- if (platform === 'privatization') {
- router.push(`/document/${version}/privatization/uc_deploy.html`)
- return
- }
- const nextPlatformDocRouters = router.options.routes.filter(item=>item.hasOwnProperty('name') && item?.path.indexOf(`/document/${version}/${platform}`) == 0).map(item=>item.path)
-
- let newPath = route.path.split('/')
- newPath[3] = platform
- const nextPathPath = newPath.join('/')
-
- if (nextPlatformDocRouters.indexOf(nextPathPath) > -1) {
- router.push(nextPathPath)
- } else {
- router.push(`/document/${version}/${platform}/overview.html`)
- }
-}
-
-const options = [
+const OPTIONS = [
{
label: '安装部署',
options: [
@@ -147,6 +117,57 @@ const options = [
],
},
]
+
+const platform = ref('android')
+const platformOptions = ref(OPTIONS)
+let version = ''
+const platformIcon = computed(() => PLATFORM_ICON_MAP[platform.value]?.activeIcon)
+const route = useRoute()
+const router = useRouter()
+
+
+
+const handleVersionOptions = (version:string) =>{
+ if (version === 'v2') {
+ platformOptions.value = OPTIONS
+ }
+ if (version === 'v1') {
+ let v1Options = JSON.parse(JSON.stringify(OPTIONS))
+ v1Options[1].options = v1Options[1].options.filter((item) =>
+ V1_PLATFORM.includes(item.value)
+ )
+ platformOptions.value = v1Options
+
+ }
+}
+
+watch(()=>route.path, ()=> {
+ if (route.path.indexOf('/document') == 0) {
+ version = route.path.split('/')[2]
+ handleVersionOptions(version)
+ platform.value = route.path.split('/')[3]
+ }
+}, {immediate:true})
+
+// 切换平台,如果有相同路径的route就直接跳转
+const onChange = (platform) => {
+ if (platform === 'privatization') {
+ router.push(`/document/${version}/privatization/uc_deploy.html`)
+ return
+ }
+ const nextPlatformDocRouters = router.options.routes.filter(item=>item.hasOwnProperty('name') && item?.path.indexOf(`/document/${version}/${platform}`) == 0).map(item=>item.path)
+
+ let newPath = route.path.split('/')
+ newPath[3] = platform
+ const nextPathPath = newPath.join('/')
+
+ if (nextPlatformDocRouters.indexOf(nextPathPath) > -1) {
+ router.push(nextPathPath)
+ } else {
+ router.push(`/document/${version}/${platform}/overview.html`)
+ }
+}
+
@@ -156,7 +177,7 @@ const options = [
diff --git a/docs/document/v1/electron/appendix.md b/docs/document/v1/electron/appendix.md
new file mode 100644
index 000000000..08097e268
--- /dev/null
+++ b/docs/document/v1/electron/appendix.md
@@ -0,0 +1,53 @@
+# 附录
+
+文档中用到的结构体定义
+
+```
+Result
+{
+ code, //{Number} 0表示成功,其它值为失败
+ description //{String} code为非0值时,表示失败原因
+}
+ContactListResult
+{
+ code:result.errorCode, //{Number} 0表示成功,其它值为失败
+ description:result.description, //{String} code为非0值时有效,表示失败原因
+ data //{StringArray} 用户ID数组,code为0时有效,["ID1","ID2"]
+}
+GroupResult
+{
+ code:result.errorCode, //{Number} 0表示成功,其它值为失败
+ description:result.description, //{String} code为非0值时有效,表示失败原因
+ data //{StringArray} EMGroup对象,code为0时有效
+}
+GroupListResult
+{
+ code:result.errorCode, //{Number} 0表示成功,其它值为失败
+ description:result.description, //{String} code为非0值时有效,表示失败原因
+ data //{Array} EMGroup对象数组,code为0时有效
+}
+SharedFileResult
+{
+ code:result.errorCode, //{Number} 0表示成功,其它值为失败
+ description:result.description, //{String} code为非0值时有效,表示失败原因
+ data //{Object} EMMucSharedFile,code为0时有效
+}
+SharedFileListResult
+{
+ code:result.errorCode, //{Number} 0表示成功,其它值为失败
+ description:result.description, //{String} code为非0值时有效,表示失败原因
+ data //{Array} EMMucSharedFile对象数组,code为0时有效
+}
+AnnouncementResult
+{
+ code:result.errorCode, //{Number} 0表示成功,其它值为失败
+ description:result.description, //{String} code为非0值时有效,表示失败原因
+ data //{String} 群组公告内容,code为0时有效
+}
+MessageListResult
+{
+ code:result.errorCode, //{Number} 0表示成功,其它值为失败
+ description:result.description, //{String} code为非0值时有效,表示失败原因
+ data //{Array} EMMessage对象数组,code为0时有效
+}
+```
\ No newline at end of file
diff --git a/docs/document/v1/electron/chatmanage.md b/docs/document/v1/electron/chatmanage.md
new file mode 100644
index 000000000..cc5152285
--- /dev/null
+++ b/docs/document/v1/electron/chatmanage.md
@@ -0,0 +1,458 @@
+# 会话管理
+
+环信桌面端 SDK 支持会话管理的集成,集成后可以进行如下操作:
+
+- 会话处理
+
+- 获取消息
+
+- 消息处理
+
+通过这些操作,可以组合帮助您完成多种场景下的 IM 需求。
+
+会话管理模块为 EMChatManager,由 EMClient 模块加载时主动创建,可以使用 EMClient 模块的 getChatManager 方法获取,代码如下:
+
+```
+var chatManager = emclient.getChatManager();
+```
+
+------
+
+## 会话处理
+
+会话处理包含以下处理操作:
+
+- 获取会话列表
+
+- 根据 ID 获取会话
+
+- 删除会话
+
+- 获取会话属性
+
+- 会话属性扩展
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 获取会话列表
+
+接口 API 如下:
+
+```
+/**
+ * 获取会话列表
+ * return 返回会话列表,EMConversation 数组
+ */
+getConversations()
+```
+
+调用方法如下:
+
+```
+var convlist = chatManager.getConversations();
+```
+
+------
+
+### 根据 ID 获取会话
+
+根据会话 ID 获取会话,接口 API 如下:
+
+```
+/**
+ * 获取会话
+ * param conversationId 会话 ID,输入参数,String
+ * param type 会话类型,输入参数,0为单聊,1为群聊
+ * return 会话,EMConversation
+ */
+conversationWithType(conversationId,type)
+```
+
+调用方法如下:
+
+```
+let conversationlist = chatManager.conversationWithType(conversationId,type);
+```
+
+------
+
+### 删除会话
+
+接口 API 如下:
+
+```
+/** 根据 ID 删除会话
+ * param conversationId 会话 ID,输入参数
+ * param isRemoveMessages 是否删除消息,ture 为删除
+ */
+removeConversation(conversationId,isRemoveMessages)
+```
+
+调用方法如下:
+
+```
+chatManager.removeConversation(conversationId,true);
+```
+
+------
+
+### 获取会话属性
+
+```
+// 获取会话 ID
+console.log("conversationId" + conversation.conversationId());
+// 获取会话类型,0为单聊,1为群聊
+console.log("conversationType" + conversation.conversationType());
+```
+
+------
+
+### 会话扩展属性
+
+接口 API 如下:
+
+```
+/**
+ * 设置会话扩展属性
+ * param ext 扩展属性,String
+ */
+setExtField(strAttr)
+/**
+ * 获取会话扩展属性
+ * return 扩展属性,String
+ */
+extField()
+```
+
+调用方法如下:
+
+```
+conversation.setExtField(ext);
+var strAttr = conversation.extField();
+```
+
+------
+
+## 获取消息
+
+获取消息包含以下处理操作:
+
+- 获取历史消息
+
+- 根据 ID 获取当前会话消息
+
+- 获取会话中的消息计数
+
+- 获取会话中的未读消息计数
+
+- 获取最新消息
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 获取历史消息
+
+接口 API 如下:
+
+```
+/**
+ * 分页获取历史消息,从服务器获取
+ * param conversationId 会话 ID,输入参数
+ * param type 会话类型,1为群组,0为单聊
+ * param pageSize 每页的消息计数
+ * param startMsgId 起始消息 ID
+ * return 返回 Promise 对象,response 参数为 MessageListResult
+ */
+chatManager.fetchHistoryMessages(conversationId, type, pageSize, startMsgId)
+```
+
+调用方法如下:
+
+```
+chatManager.fetchHistoryMessages(conversationId, type, pageSize, startMsgId).then((res) => {},(error) => {});
+```
+
+------
+
+### 根据 ID 获取当前会话消息
+
+根据消息 ID 获取当前会话消息,接口 API 如下:
+
+```
+/**
+ * 根据消息 ID 获取消息
+ * param msgid 消息 ID
+ * return 未读消息计数
+ */
+loadMessage(msgid)
+```
+
+调用方法如下:
+
+```
+var msg = conversation.loadMessage(msgid);
+```
+
+------
+
+### 获取会话中的消息计数
+
+接口 API 如下:
+
+```
+/**
+ * 获取会话中的消息计数
+ * return 消息计数,Number
+ */
+messagesCount()
+```
+
+调用方法如下:
+
+```
+var msgCount = conversation.messagesCount();
+```
+
+------
+
+### 获取会话中的未读消息计数
+
+接口 API 如下:
+
+```
+/**
+ * 获取会话中的未读消息计数
+ * return 未读消息计数,Number
+ */
+unreadMessagesCount()
+```
+
+调用方法如下:
+
+```
+var unreaddMsgCount = conversation.unreadMessagesCount();
+```
+
+------
+
+### 获取最新一条消息
+
+接口 API 如下:
+
+```
+/**
+ * 获取会话中的最新一条消息
+ * return EMMessage 消息对象
+ */
+latestMessage()
+```
+
+调用方法如下:
+
+```
+var msg = conversation.latestMessage();
+```
+
+------
+
+## 消息处理
+
+消息处理包含以下处理操作:
+
+- 插入消息
+
+- 添加消息
+
+- 修改消息
+
+- 加载会话消息
+
+- 删除会话消息
+
+- 清空会话消息
+
+- 下载图片、附件
+
+- 设置消息已读状态
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 插入消息
+
+接口 API 如下:
+
+```
+/**
+ * 不发送消息,只是插入到本地,按照时间插入到本地数据库
+ * param messagelist 要插入的消息列表,EMMessage 数组
+ * return 返回操作结果,Bool
+*/
+insertMessages(messagelist);
+```
+
+调用方法如下:
+
+```
+chatManager.insertMessages(messagelist);
+```
+
+------
+
+### 添加消息
+
+接口 API 如下:
+
+```
+/**
+ * 在末尾添加一条消息
+ * param message 要插入的消息,EMMessage 对象
+ * return 返回操作结果,Bool
+*/
+appendMessage(message);
+```
+
+调用方法如下:
+
+```
+chatManager.appendMessage(message);
+```
+
+------
+
+### 修改消息
+
+接口 API 如下:
+
+```
+/**
+ * 修改一条消息,不能改变消息 ID
+ * param message 要插入的消息,EMMessage 对象
+ * return 返回操作结果,Bool
+*/
+updateMessage(message);
+```
+
+调用方法如下:
+
+```
+chatManager.updateMessage(message);
+```
+
+------
+
+### 加载会话消息
+
+接口 API 如下:
+
+```
+/**
+ * 按照 ID 加载会话消息
+ * param refMsgId 起始消息 ID,输入参数,空为最新消息,String
+ * param count 加载的消息数,输入参数,Number
+ * param direction 消息加载方向填0
+ * return 返回为 EMMessage 数组
+ */
+loadMoreMessagesByMsgId(refMsgId, count, direction);
+
+/**
+ * 按照时间加载会话消息
+ * param timeStamp 起始消息时间,输入参数
+ * param count 加载的消息数,输入参数
+ * param direction 消息加载方向,填0
+ * return 返回EMMessage数组
+ */
+conversation.loadMoreMessagesByTime(timeStamp, count, direction);
+```
+
+调用方法如下:
+
+```
+conversation.loadMoreMessagesByMsgId("", 20,0);
+conversation.loadMoreMessagesByTime(timeStamp, 20,0);
+```
+
+------
+
+### 删除会话消息
+
+接口 API 如下:
+
+```
+/**
+ * 按照 ID 移除会话消息,只操作缓存和本地数据库
+ * param messageId 要删除的消息 ID
+ * return 返回操作结果,bool 型
+ */
+removeMessage(messageId)
+```
+
+调用方法如下:
+
+```
+conversation.removeMessage(messageId).then((res)=>{},(error) => {});
+```
+
+------
+
+### 清空会话消息
+
+接口 API 如下:
+
+```
+/**
+ * 清空会话消息,只操作缓存和本地数据库
+ * return 返回操作结果,bool 型
+ */
+clearAllMessages()
+```
+
+调用方法如下:
+
+```
+conversation.clearAllMessages();
+```
+
+------
+
+### 下载图片、附件
+
+```
+// 下载附件消息,message 为 EMMessage 对象,可在 message 中设置回调
+chatManager.downloadMessageAttachments(message);
+// 下载图片缩略,message 为 EMMessage 对象,可在 message 中设置回调
+chatManager.downloadMessageThumbnail(message);
+```
+
+------
+
+### 设置消息已读状态
+
+接口 API 如下:
+
+```
+/**
+ * 根据消息 ID 标记消息已读状态
+ * param msgid,消息 ID
+ * isread bool,已读状态
+ * return 返回操作结果,bool 型
+ */
+markMessageAsRead(msgid,isread);
+/**
+ * 标记会话中所有消息的已读状态
+ * isread bool,已读状态
+ * return 返回操作结果,bool 型
+ */
+markAllMessagesAsRead(isread);
+```
+
+调用方法如下:
+
+```
+conversation.markMessageAsRead(msgid,isread);
+conversation.markAllMessagesAsRead(isread);
+```
\ No newline at end of file
diff --git a/docs/document/v1/electron/demo.md b/docs/document/v1/electron/demo.md
new file mode 100644
index 000000000..e5a62b9d7
--- /dev/null
+++ b/docs/document/v1/electron/demo.md
@@ -0,0 +1,6 @@
+# Demo 下载体验
+
+
+- [Windows Demo](https://download-sdk.oss-cn-beijing.aliyuncs.com/downloads/DesktopDemo.3.8.4.win.setup.exe)
+- [Mac Demo](https://download-sdk.oss-cn-beijing.aliyuncs.com/downloads/DesktopDemo.3.8.4.mac.dmg)
+- [Demo 源码](https://github.com/easemob/sdkdemoapp_windows/tree/electron)
\ No newline at end of file
diff --git a/docs/document/v1/electron/group_manage.md b/docs/document/v1/electron/group_manage.md
new file mode 100644
index 000000000..475423c5d
--- /dev/null
+++ b/docs/document/v1/electron/group_manage.md
@@ -0,0 +1,1018 @@
+# 群组管理
+
+环信桌面端 SDK 支持群组功能的集成,集成后可以进行如下操作:
+
+- 获取群组
+
+- 群组管理
+
+- 群成员管理
+
+- 加群处理
+
+- 群消息
+
+- 群文件
+
+- 群组变更的监听
+
+通过这些操作,可以组合帮助您完成多种场景下的 IM 需求。
+
+群组管理模块为 EMGroupManager ,由 EMClient 模块加载时主动创建,可以使用 EMClient 模块的 getGroupManager 方法获取,代码如下
+
+```
+var groupManager = emclient.getGroupManager();
+```
+
+------
+
+## 获取群组
+
+获取群组包含以下处理操作:
+
+- 本地获取群组
+
+- 服务器获取群组
+
+- ID 获取群组
+
+- 获取群组信息
+
+- 获取公开群组
+
+- 查找公开群组
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 本地获取群组
+
+本地获取用户所在的所有群组,接口 API 如下:
+
+```
+/**
+ * 本地获取用户所有的组
+ * return GroupListResult
+ */
+allMyGroups()
+```
+
+调用方法如下:
+
+```
+let res = groupManager.allMyGroups()
+```
+
+------
+
+### 服务器获取群组
+
+服务器获取用户所在的所有群组,接口 API 如下:
+
+```
+/**
+ * 服务器获取用户所有的组
+ * return 返回 Promise 对象,response 参数为 GroupListResult
+ */
+fetchAllMyGroups()
+```
+
+调用方法如下:
+
+```
+groupManager.fetchAllMyGroups().then((res)=>{},(error) => {});
+```
+
+------
+
+### ID 获取群组
+
+根据 ID 获取群组
+
+```
+let group = groupManager.groupWithId(groupId);
+```
+
+------
+
+### 获取群组信息
+
+```
+// 获取组 ID
+console.log("group.groupId" + group.groupId());
+// 获取组名
+console.log("group.groupSubject" + group.groupSubject());
+// 获取组描述
+console.log("group.groupDescription" + group.groupDescription());
+// 获取群主
+console.log("group.groupOwner" + group.groupOwner());
+// 获取成员计数
+console.log("group.groupMembersCount" + group.groupMembersCount());
+// 获取群设置类型
+console.log("group.groupMemberType" + group.groupMemberType());
+// 获取群成员
+console.log("members:"+group.groupMembers().join(' || '));
+// 获取群设置对象
+var set = group.groupSetting();
+console.log("set.style() = " + set.style());
+console.log("set.maxUserCount() = " + set.maxUserCount());
+console.log("set.extension() = " + set.extension());
+```
+
+------
+
+### 获取公开群组
+
+接口 API 如下:
+
+```
+/**
+ * 分页获取公开群组
+ * param pageNum 第几页,输入参数,Number,0表示不分页,获取所有公开组,1为分页起始
+ * param pageSize 每页计数,输入参数,Number,最大200
+ * return 返回 Promise 对象,response 参数为 GroupListResult
+ */
+fetchPublicGroupsWithPage(pageNum, pageSize);
+```
+
+调用方法如下:
+
+```
+groupManager.fetchPublicGroupsWithPage(1,20).then((res) => {
+ },(error) => {})
+```
+
+------
+
+### 查找公开群组
+
+接口 API 如下:
+
+```
+/**
+ * 根据群 ID 查找公开群
+ * param1 groupId 群组 ID,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+searchPublicGroup(groupId);
+```
+
+调用方法如下:
+
+```
+groupManager.searchPublicGroup(groupId).then((res) => {
+ },(error) => {})
+```
+
+------
+
+## 群组管理
+
+群组管理包含以下处理操作:
+
+- 创建群组
+
+- 解散群组
+
+- 退出群组
+
+- 转移群组
+
+- 修改群信息
+
+- 群组公告管理
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 创建群组
+
+创建群组时,需要先实例化一个群组设置对象,然后创建群组。实例化群组设置接口 API 如下:
+
+```
+/**
+ * 实例化区群组设置
+ * param style 组类型, Number ,0为私有群,只有群主可以邀请成员加入,1为私有群,成员也可以邀请成员加入,2为公开群,但申请入群需要群主同意,3为公开群,成员可以随意申请加入
+ * param maxUserCount 最大成员数, Number ,最大200
+ * param inviteNeedConfirm 邀请是否需要确认,Bool
+ * param extension 扩展信息,String
+ * return 返回组设置对象
+ */
+EMMucSetting(style, maxUserCount, inviteNeedConfirm, extension)
+```
+
+调用方法如下:
+
+```
+var setting = new easemob.EMMucSetting(1, 20, false, "test");
+```
+
+创建群组接口 API 如下:
+
+```
+/**
+ * 创建群组 api
+ * param subject 群组名称,输入参数,String
+ * param description 群组描述,输入参数,String
+ * param welcomeMessage 欢迎信息,输入参数,String
+ * param setting 群组设置,输入参数,Object
+ * param members 群组初始成员,输入参数,StringArray
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+createGroup(subject, description, welcomeMessage, setting, members)
+```
+
+调用方法如下:
+
+```
+groupManager.createGroup("subject","description","welcome message",setting,["jwfan1", "jwfan2"]).then((res) => {},(error) => {})
+```
+
+------
+
+### 解散群组
+
+接口 API 如下:
+
+```
+/**
+ * 解散群组 api
+ * param groupId 组 ID,输入参数
+ * return 返回 Promise 对象,response 参数为 Result
+ */
+destroyGroup(groupId);
+```
+
+调用方法如下:
+
+```
+groupManager.destroyGroup("55139673112577").then((res)=>{},(error) => {})
+```
+
+------
+
+### 退出群组
+
+接口 API 如下:
+
+```
+/**
+ * 成员主动退出群组
+ * param groupId 群组 ID,输入参数,String
+ * 返回 Promise 对象,response 参数为 Result
+ */
+leaveGroup(groupId)
+```
+
+调用方法如下:
+
+```
+groupManager.leaveGroup(groupId).then((res)=>{},(error) => {})
+```
+
+------
+
+### 转移群组
+
+接口 API 如下:
+
+```
+/**
+ * 转移群主,只有群主能操作
+ * param groupId 群组ID,输入参数,String
+ * param member 新群主用户名,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+transferGroupOwner(groupId, member)
+```
+
+调用方法如下:
+
+```
+groupManager.transferGroupOwner(groupId, member).then((res) =>{},(error) => {});
+```
+
+------
+
+### 修改群组信息
+
+接口 API 如下:
+
+```
+/**
+ * 修改群标题
+ * param groupId 群组 ID ,输入参数,String
+ * param newSubject 群组新组名,输入参数,String
+ * return 返回 Promise对象,response 参数为 GroupResult
+ */
+groupManager.changeGroupSubject(groupId, newSubject);
+
+
+/**
+ * 修改群描述
+ * param groupId 群组 ID,输入参数,String
+ * param newDescription 群组新描述,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+changeGroupDescription(groupId, newDescription)
+```
+
+调用方法如下:
+
+```
+groupManager.changeGroupSubject(groupId, "new Subject", error).then((res) =>{},(error) => {});
+groupManager.changeGroupDescription(groupId, "new Description", error).then((res) =>{},(error) => {});
+```
+
+------
+
+### 群组公告管理
+
+接口 API 如下:
+
+```
+/**
+ * 设置群组公告
+ * param groupId 群组 ID,输入参数,String
+ * param announcement 群组公告,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+updateGroupAnnouncement(groupId, announcement,error)
+
+/**
+ * 获取群组公告
+ * param groupId 群组 ID,输入参数,String
+ * return 返回 Promise 对象,response 参数为 AnnouncementResult
+ */
+fetchGroupAnnouncement(groupId)
+```
+
+调用方法如下:
+
+```
+groupManager.fetchGroupAnnouncement(groupId).then((res) =>{},(error) => {}); groupManager.updateGroupAnnouncement(groupId, "new announcement").then((res) =>{},(error) => {});
+```
+
+------
+
+## 群成员管理
+
+群成员管理包含以下处理操作:
+
+- 群成员邀请
+
+- 群成员移除
+
+- 添加管理员
+
+- 删除管理员
+
+- 获取禁言成员列表
+
+- 成员禁言
+
+- 取消成员禁言
+
+- 加入群组黑名单
+
+- 从群组黑名单移除
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 群成员邀请
+
+接口 API 如下:
+
+```
+/**
+ * 邀请成员入群,一次可邀请多个成员
+ * param groupId 群组 ID,输入参数,String
+ * param members 邀请的成员,输入参数,StringArray,["ID1","ID2"]
+ * param welcomeMessage 欢迎信息,输入参数,String
+ * 返回 Promise 对象,response 参数为 GroupResult
+ */
+addGroupMembers(groupId, members, welcomeMessage);
+```
+
+调用方法如下:
+
+```
+groupManager.addGroupMembers(groupId, ["jwfan3", "jwfan4"], "hahaha").then((res)=>{},(error) => {})
+```
+
+------
+
+### 群成员移除
+
+接口 API 如下:
+
+```
+/**
+ * 将成员踢出群,同样可踢出多人
+ * param groupId 群组ID,输入参数,String
+ * param members 踢出的成员,输入参数,StringArray,["ID1","ID2"]
+ * 返回 Promise 对象,response 参数为 Result
+ */
+removeGroupMembers(groupId, members, error);
+```
+
+调用方法如下:
+
+```
+groupManager.removeGroupMembers(groupId, ["jwfan3", "jwfan4"]).then((res)=>{},(error) => {})
+```
+
+------
+
+### 添加管理员
+
+接口 API 如下:
+
+```
+/**
+ * 将普通群成员提升为管理员
+ * param groupId 群组 ID,输入参数,String
+ * param member 成员用户名,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+addGroupAdmin(groupId, member)
+```
+
+调用方法如下:
+
+```
+groupManager.addGroupAdmin(groupId, member).then((res) =>{},(error) => {});
+```
+
+------
+
+### 删除管理员
+
+接口 API 如下:
+
+```
+/**
+ * 将管理员降级为普通成员
+ * param groupId 群组ID,输入参数,String
+ * param member 管理员用户名,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+removeGroupAdmin(groupId, member)
+```
+
+调用方法如下:
+
+```
+groupManager.removeGroupAdmin(groupId, member).then((res) =>{},(error) => {});
+```
+
+------
+
+### 获取禁言列表
+
+接口API如下:
+
+```
+/**
+ * 获取禁言列表
+ * param groupId 群组 ID,输入参数,String
+ * param pageNum 第几页,输入参数,Number,1为起始页
+ * param pageSize 每页计数,输入参数,Number,最大200
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+fetchGroupMutes(groupId, pageNum, pageSize)
+```
+
+------
+
+### 群组禁言
+
+接口API如下:
+
+```
+/**
+ * 将成员加入禁言列表,被禁言的成员无法在群组内发消息
+ * param {String} groupId 群组ID,输入参数,String
+ * param {Array} members 成员列表,输入参数,String 数组
+ * param {Number} muteDuration 禁言时间,单位毫秒
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+muteGroupMembers(groupId,members,muteDuration)
+```
+
+------
+
+### 取消禁言
+
+接口API如下:
+
+```
+/**
+ * 将成员从禁言列表移除
+ * param {String} groupId 群组ID,输入参数,String
+ * param {Array} members 成员列表,输入参数,String 数组
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+unmuteGroupMembers(groupId,members)
+```
+
+------
+
+### 获取群组黑名单列表
+
+接口 API 如下:
+
+```
+/**
+ * 分页获取群组黑名单列表
+ * param groupId 群组 ID,输入参数,String
+ * param pageNum 第几页,输入参数,Number,1为起始页
+ * param pageSize 每页计数,输入参数,Number,最大200
+ * return 返回 Promise 对象,response 参数为 GroupListResult
+ */
+fetchGroupBans(groupId,pageNum, pageSize)
+```
+
+调用方法如下:
+
+```
+groupManager.fetchGroupBans(groupId, 1, 20).then((res) =>{},(error) => {});
+```
+
+------
+
+### 加入群组黑名单
+
+接口 API 如下:
+
+```
+/**
+ * 将成员加入群组黑名单,黑名单中的人员无法加入群组
+ * param groupId 群组ID,输入参数,String
+ * param members 成员列表,输入参数,String 数组
+ * param reason 加入黑名单原因,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+blockGroupMembers(groupId,members,reason)
+```
+
+调用方法如下:
+
+```
+groupManager.blockGroupMembers(groupId, members, "reason").then((res) =>{},(error) => {});
+```
+
+------
+
+### 从群组黑名单移除
+
+接口 API 如下:
+
+```
+/**
+ * 将人员从群组黑名单移除
+ * param groupId 群组 ID,输入参数,String
+ * param members 成员列表,输入参数,StringArray
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+unblockGroupMembers(groupId, members)
+```
+
+调用方法如下:
+
+```
+groupManager.unblockGroupMembers(groupId, members).then((res) =>{},(error) => {});
+```
+
+------
+
+## 加群处理
+
+加群处理包含以下处理操作:
+
+- 加入公开群组
+
+- 申请加入公开群组
+
+- 接受群邀请
+
+- 拒绝群邀请
+
+- 接受入群申请
+
+- 拒绝入群申请
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 加入公开群组
+
+接口 API 如下:
+
+```
+/**
+ * 加入 PUBLIC_JOIN_OPEN 类型公开群组
+ * param groupId 群组 ID,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+joinPublicGroup(groupId,error)
+```
+
+调用方法如下:
+
+```
+groupManager.joinPublicGroup(groupId,error).then((res) =>{},(error) => {});
+```
+
+------
+
+### 申请加入公开群组
+
+接口 API 如下:
+
+```
+/**
+ * 申请加入 applyJoinPublicGroup 类型公开群组,需要群主或管理员同意
+ * param groupId 群组 ID,输入参数,String
+ * param nickname 用户在群内的昵称,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+applyJoinPublicGroup(groupId,nickname,message)
+```
+
+调用方法如下:
+
+```
+groupManager.applyJoinPublicGroup(groupId,nickname,message).then((res) =>{},(error) => {});
+```
+
+------
+
+### 接受群邀请
+
+接口 API 如下:
+
+```
+/**
+ * 接受群组发来的入群邀请
+ * param groupId 群组ID,输入参数,String
+ * param inviter 邀请人,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+acceptInvitationFromGroup(groupId,inviter)
+```
+
+调用方法如下:
+
+```
+groupManager.acceptInvitationFromGroup(groupId,inviter).then((res) =>{},(error) => {});
+```
+
+### 拒绝群邀请
+
+接口 API 如下:
+
+```
+/**
+ * 拒绝群组发来的入群邀请
+ * param groupId 群组 ID,输入参数,String
+ * param inviter 邀请人,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+declineInvitationFromGroup(groupId,inviter)
+```
+
+调用方法如下:
+
+```
+groupManager.declineInvitationFromGroup(groupId,inviter).then((res) =>{},(error) => {});
+```
+
+------
+
+### 接受加入群申请
+
+接口 API 如下:
+
+```
+/**
+ * 同意成员的入群邀请,由群主操作
+ * param groupId 群组ID,输入参数,String
+ * param from 入群申请人,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+acceptJoinGroupApplication(groupId,from)
+```
+
+调用方法如下:
+
+```
+groupManager.acceptJoinGroupApplication(groupId,from).then((res) =>{},(error) => {});
+```
+
+------
+
+### 拒绝加入群申请
+
+接口 API 如下:
+
+```
+/**
+ * 拒绝成员的入群邀请,由群主操作
+ * param groupId 群组 ID,输入参数,String
+ * param from 入群申请人,输入参数,String
+ * param reason 拒绝原因,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+declineJoinGroupApplication(groupId,from,reason)
+```
+
+调用方法如下:
+
+```
+groupManager.declineJoinGroupApplication(groupId,from,"decline reason").then((res) =>{},(error) => {});
+```
+
+------
+
+## 群消息
+
+群消息包含以下处理操作:
+
+- 屏蔽群组消息
+
+- 取消屏蔽群组消息
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 屏蔽群组消息
+
+接口 API 如下:
+
+```
+/**
+ * 屏蔽群组消息
+ * param groupId 群组ID,输入参数,String
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+blockGroupMessage(groupId)
+```
+
+调用方法如下:
+
+```
+groupManager.blockGroupMessage(groupId).then((res) =>{},(error) => {});
+```
+
+------
+
+### 取消屏蔽群组消息
+
+接口 API 如下:
+
+```
+/**
+ * 取消屏蔽群组消息
+ * param groupId 群组 ID,输入参数,String
+ * return 返回 Promise 对象,response 参数为GroupResult
+ */
+unblockGroupMessage(groupId)
+```
+
+调用方法如下:
+
+```
+groupManager.unblockGroupMessage(groupId).then((res) =>{},(error) => {});
+```
+
+------
+
+## 群文件
+
+群文件包含以下处理操作:
+
+- 获取群文件列表
+
+- 上传群文件
+
+- 下载群文件
+
+- 删除群文件
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 获取群文件列表
+
+接口 API 如下:
+
+```
+/**
+ * 分页获取群文件列表
+ * param groupId 群组ID,输入参数,String
+ * param pageNum 当前页数,从1开始
+ * param pageSize 每页计数,最大200
+ * return 返回 Promise 对象,response 参数为 SharedFileListResult
+ */
+fetchGroupSharedFiles(groupId, pageNum, pageSize)
+```
+
+调用方法如下:
+
+```
+groupManager.fetchGroupSharedFiles(groupId, 1, 20).then((res) => {},(error) => {});
+```
+
+------
+
+### 上传群文件
+
+上传群文件过程中,需要使用回调监控上传进度及结果
+
+```
+// 设置回调函数显示上传进度和结果
+var emUploadCallback = new easemob.EMCallback();
+console.log("create upload emCallback success");
+
+// 上传成功
+emUploadCallback.onSuccess(() => {
+ console.log("upload emCallback call back success");
+ return true;
+});
+// 上传失败
+emUploadCallback.onFail((error) => {
+ console.log("upload emCallback call back fail");
+ console.log(error.description);
+ console.log(error.errorCode);
+ return true;
+});
+// 上传进度
+emUploadCallback.onProgress((progress) => {
+ if (progress >= 98) {
+ console.log("upload call back progress " + progress);
+ }
+});
+```
+
+接口 API 如下:
+
+```
+/**
+ * 上传群文件
+ * param groupId 群组 ID,输入参数,String
+ * param filepath 文件路径,输入参数,String
+ * param emUploadCallback 设置回调,输入
+ * 返回 Promise 对象,response 参数为 SharedFileResult
+ */
+uploadGroupSharedFile(groupId, filepath, emUploadCallback)
+```
+
+调用方法如下:
+
+```
+groupManager.uploadGroupSharedFile(groupId, filepath, emUploadCallback).then((res) => {},(error) => {});
+```
+
+------
+
+### 下载群文件
+
+下载群文件过程中需要使用回调监控下载进度及结果
+
+```
+var emDownloadCallback = new easemob.EMCallback();
+console.log("create download emCallback success");
+
+// 下载成功
+emDownloadCallback.onSuccess(() => {
+ console.log("download emCallback call back success");
+ return true;
+});
+// 下载失败
+emDownloadCallback.onFail((error) => {
+ console.log("download emCallback call back fail");
+ console.log(error.description);
+ console.log(error.errorCode);
+ return true;
+});
+// 下载进度
+emDownloadCallback.onProgress((progress) => {
+ if (progress >= 98) {
+ console.log("download call back progress " + progress);
+ }
+});
+```
+
+接口 API 如下:
+
+```
+/**
+ * 下载群文件
+ * param groupId 群组 ID,输入参数,String
+ * param filePath 文件本地存储路径,输入参数,String
+ * param fileId 文件 ID,输入参数,由文件列表数组获取
+ * param callback 设置回调,输入
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+downloadGroupSharedFile(groupId, filePath, fileId, callback)
+```
+
+调用方法如下:
+
+```
+let fileId = sharedFile.fileId();
+groupManager.downloadGroupSharedFile(groupid, filelocalpath, fileId, emDownloadCallback);
+```
+
+------
+
+### 删除群文件
+
+接口 API 如下:
+
+```
+/**
+ * 删除群文件
+ * param groupId 群组 ID,输入参数,String
+ * param fileId 文件 ID,输入参数,由文件列表获取
+ * return 返回 Promise 对象,response 参数为 GroupResult
+ */
+deleteGroupSharedFile(groupId, fileId)
+```
+
+调用方法如下:
+
+```
+let fileId = sharedFile.fileId();
+groupManager.deleteGroupSharedFile(groupId, fileId).then((res) =>{},(error) => {});
+```
+
+------
+
+## 群组变更的监听
+
+```
+groupManager = emclient.getGroupManager();
+groupListener = new easemob.EMGroupManagerListener(groupManager);
+// 添加群管理员时触发(只有是自己时才能收到通知)
+// group : 发生操作的群组
+// admin : 被提升的群管理员
+groupListener.onAddAdminFromGroup((groupId, admin) => {
+ console.log("onAddAdminFromGroup:"+groupId+" admin:"+admin);
+});
+
+// 删除群管理员时触发(只有是自己时才能收到通知)
+// group : 发生操作的群组
+// admin : 被删除的群管理员(群管理员变成普通群成员)
+groupListener.onRemoveAdminFromGroup((groupId, admin) => {
+ console.log("onRemoveAdminFromGroup:"+groupId+" admin:"+admin);
+});
+
+// 转让群主的时候触发
+// group : 发生操作的群组
+// newOwner : 新群主
+// oldOwner : 原群主
+groupListener.onAssignOwnerFromGroup((groupId, newOwner, oldOwner) => {
+ console.log("onAssignOwnerFromGroup:"+groupId+" newOwner:"+newOwner + " oldOwner:" + oldOwner);
+});
+
+// 我接收到自动进群时被触发
+// group : 发生操作的群组
+// inviter : 邀请人
+// inviteMessage : 邀请信息
+groupListener.onAutoAcceptInvitationFromGroup((groupId, inviter, inviteMessage)=>{
+ console.log("onAutoAcceptInvitationFromGroup:"+groupId+" inviter:"+inviter + " inviteMessage:" + inviteMessage);
+ });
+
+// 成员加入群组时触发
+// group : 发生操作的群组
+// member : 加入群组的成员名称
+groupListener.onMemberJoinedGroup((groupId, member)=>{
+ console.log("onMemberJoinedGroup:"+groupId+" member:"+member);
+});
+
+// 成员离开群组时触发
+// group : 发生操作的群组
+// member : 离开群组的成员名称
+groupListener.onMemberLeftGroup((groupId, member)=>{
+ console.log("onMemberLeftGroup:"+groupId+" member:"+member);
+});
+
+// 离开群组时触发
+// group : 发生操作的群组
+// reason : 离开群组的原因(0: 被踢出 1:群组解散 2:被服务器下线)
+groupListener.onLeaveGroup((groupId, reason)=>{
+ console.log("onLeaveGroup:"+groupId+" reason:"+reason);
+});
+groupManager.addListener(groupListener);
+// 移除监听
+groupManager.removeListener(groupListener);
+```
\ No newline at end of file
diff --git a/docs/document/v1/electron/message.md b/docs/document/v1/electron/message.md
new file mode 100644
index 000000000..c00b2af77
--- /dev/null
+++ b/docs/document/v1/electron/message.md
@@ -0,0 +1,257 @@
+# 消息管理
+
+消息是桌面端集成中最重要的功能之一,消息的使用方法主要为 :
+
+- 发送消息
+
+- 接受消息
+
+同时对于发送不超过2分钟的消息,允许主动撤回。
+
+通过对消息的集成,您可以最快速的集成体验 IM 收发消息的流畅体验。
+
+------
+
+## 发送消息
+
+发送消息类型主要有以下几种:
+
+- 文本消息
+
+- 文件消息
+
+- 图片消息
+
+- CMD 消息
+- 自定义 消息
+
+- 位置消息
+
+通过这些操作,可以组合帮助您完成多种场景下的 IM 需求。
+
+发送文本、文件、图片等消息(单聊/群聊通用)。完整的消息发送过程,包括创建消息体,创建消息,设置属性,设置回调,然后发送消息,不同的消息类型只是在创建消息体过程不同,其他步骤一样。
+
+------
+
+### 发送文本消息
+
+```
+/**
+ * 创建文本消息体
+ * param1 文本消息正文,输入参数,String
+ * return 消息体 EMTextMessageBody
+ */
+var textMsgBody = new easemob.EMTextMessageBody("wahhahahaha");
+/**
+ * 创建消息
+ * param1 发送者用户名,输入参数
+ * param2 目的端,会话 ID,输入参数
+ * param3 消息体 EMTextMessageBody
+ * return 消息 EMMessage
+ */
+var textSendMsg = easemob.createSendMessage("jwfan", "jwfan1", textMsgBody);
+// 消息可以设置扩展属性,用户界面可通过自定义属性,实现自定义等功能
+textSendMsg.setAttribute("data", 120);
+data = textSendMsg.getAttribute("data");
+// 设置消息类型,0为单聊,1为群聊,2为聊天室
+textSendMsg.setChatType(0);
+// 设置回调
+var emCallback = new easemob.EMCallback();
+emCallback.onSuccess(() => {
+ console.log("emCallback call back success");
+ if(me.cfr){
+ console.log(sendMessage);
+ console.log(sendMessage.msgId());
+ return true;
+ });
+ emCallback.onFail((error) => {
+ console.log("emCallback call back fail");
+ console.log(error.description);
+ console.log(error.errorCode);
+ return true;
+ });
+ emCallback.onProgress((progress) => {
+ console.log(progress);
+ console.log("call back progress");
+ });
+sendMessage.setCallback(emCallback);
+// 发送消息
+chatManager.sendMessage(textMsg);
+```
+
+------
+
+### 发送文件
+
+```
+/**
+ * 创建文件消息体
+ * param1 文件路径,输入参数,String
+ * return 消息体 EMFileMessageBody
+ */
+var fileMsgBody = new easemob.EMFileMessageBody("/Users/jiangwei/Code/fanjiangwei7/emclient-linux/testapp/file.txt");
+// 创建消息
+var fileMsg = easemob.createSendMessage("jwfan", "jwfan1", fileMsgBody);
+//setCallback(callback) 设置消息回调函数,通过回调函数显示消息发送成功失败,以及附件上传百分比
+//callback easemob.EMCallback的实例,设置onSuccess、onFail和onProgress三个回调函数。
+fileMsg.setCallback(emCallback);
+chatManager.sendMessage(fileMsg);
+```
+
+------
+
+### 发送图片
+
+```
+/**
+ * 创建图片消息体
+ * param1 图片文件路径,输入参数,String
+ * param2 图片缩略图路径,输入参数
+ * return 消息体EMFileMessageBody
+ */
+var imageMsgBody = new easemob.EMImageMessageBody('/Users/jiangwei/Code/fanjiangwei7/emclient-linux/testapp/image_960x718.jpg', '/Users/jiangwei/Code/fanjiangwei7/emclient-linux/testapp/thumb_image.jpg');
+var imageMsg = easemob.createSendMessage("jwfan", "jwfan1", imageMsgBody);
+imageMsg.setCallback(emCallback);
+chatManager.sendMessage(imageMsg);
+```
+
+------
+
+### 发送 CMD 消息
+
+```
+var cmdMsgBody = new easemob.EMCmdMessageBody("action");
+console.log("cmdMsgBody.type() = " + cmdMsgBody.type());
+
+console.log("cmdMsgBody.action() = " + cmdMsgBody.action());
+cmdMsgBody.setAction("displayName");
+console.log("cmdMsgBody.action() = " + cmdMsgBody.action());
+
+var obj1 = {"key" : "1", "value" : "1"};
+var obj2 = {"key" : "2", "value" : "2"};
+console.log("cmdMsgBody.params() = " + cmdMsgBody.params());
+cmdMsgBody.setParams([obj1, obj2]);
+var cmdMsg = easemob.createSendMessage("jwfan", "jwfan1", cmdMsgBody);
+chatManager.sendMessage(cmdMsg);
+```
+
+------
+
+### 发送 自定义 消息
+
+自定义消息包括消息event和消息扩展exts,构造及发送过程如下
+
+```
+let customMsgBody = new easemob.EMCustomMessageBody("userCard");
+customMsgBody.setExts({'avatar':'https://download-sdk.oss-cn-beijing.aliyuncs.com/downloads/IMDemo/avatar/Image5.png','nickname':'xiaoming','uid':'uid'});
+let customMsg = easemob.createSendMessage('lxm9','lxm',customMsgBody);
+chatManager.sendMessage(customMsg);
+```
+
+------
+
+### 位置消息
+
+```
+/**
+ * 创建位置消息体
+ * param1 位置经度,输入参数,String
+ * param2 位置纬度,输入参数
+ * param3 地址,输入参数
+ * return 消息体EMFileMessageBody
+ */
+var locationMsgBody = new easemob.EMLocationMessageBody(123.45, 35.67, 'USA');
+console.log("locationMsgBody.type() = " + locationMsgBody.type());
+console.log("locationMsgBody.latitude() = " + locationMsgBody.latitude());
+console.log("locationMsgBody.longitude() = " + locationMsgBody.longitude());
+console.log("locationMsgBody.address() = " + locationMsgBody.address());
+locationMsgBody.setLatitude(87.87);
+locationMsgBody.setLongitude(45.45);
+locationMsgBody.setAddress('china');
+var locationMsg = easemob.createSendMessage("jwfan", "jwfan1", locationMsgBody);
+chatManager.sendMessage(locationMsg);
+```
+
+------
+
+## 撤回消息
+
+默认发送两分钟内的消息可以撤回,撤回使用recallMessage接口
+
+```
+/**
+ * 撤回消息
+ * param msg {EMMessage} 要撤回的消息
+ */
+chatManager.recallMessage(msg);
+```
+
+------
+
+## 接收消息
+
+接收消息在会话管理中通过设置回调函数实现,在回调函数中处理
+
+```
+// 实例化监听回调,并添加到client
+chatManager = emclient.getChatManager();
+listener = new easemob.EMChatManagerListener();
+chatManager.addListener(listener);
+
+// 收到会话消息
+listener.onReceiveMessages((messages) => {
+ console.log("onReceiveMessages messages.length = " + messages.length);
+ for (var index = 0, len = messages.length; index < len; index++) {
+ var msg = messages[index];
+ var bodies = msg.bodies();
+ console.log("bodies.length = " + bodies.length);
+ var body = bodies[0];
+ var type = body.type();
+ console.log("msg.from() = " + msg.from());
+ console.log("msg.to() = " + msg.to());
+ console.log("body.type() = " + type);
+ if (type == 0) { //text message
+ console.log("body.text() = " + body.text());
+ } else if (type == 1) { //image message
+ console.log("body.displayName() = " + body.displayName());
+ console.log("body.localPath() = " + body.localPath());
+ chatManager.downloadMessageAttachments(msg);
+ chatManager.downloadMessageThumbnail(msg);
+ } else if (type == 5) { //file message
+ console.log("body.displayName() = " + body.displayName());
+ console.log("body.localPath() = " + body.localPath());
+ chatManager.downloadMessageAttachments(msg);
+ }
+});
+// 收到命令消息
+listener.onReceiveCmdMessages ((messages) => {
+ for (var index = 0, len = messages.length; index < len; index++) {
+ var msg = messages[index];
+ var bodies = msg.bodies();
+ console.log("bodies.length = " + bodies.length);
+ var body = bodies[0];
+ var type = body.type();
+ console.log("msg.from() = " + msg.from());
+ console.log("msg.to() = " + msg.to());
+ console.log("msg.type() = " + type);
+ console.log("body.action() = " + body.action());
+ var params = cmdMsgBody.params()
+ console.log("cmdMsgBody.params().length = " + params.length);
+ if (params.length > 0) {
+ console.log("cmdMsgBody.params()[0] = " + JSON.stringify(params[0]));
+ }
+}
+});
+
+// 收到消息撤回
+listener.onReceiveRecallMessages ((message) => {
+ console.log("onReceiveRecallMessages messages.length = " + messages.length);
+ for (var index = 0, len = messages.length; index < len; index++) {
+ var message = messages[index];
+ console.log("message.msgId() = " + message.msgId());
+ console.log("message.from() = " + message.from());
+ console.log("message.to() = " + message.to());
+}
+});
+// addListener(listener) 添加消息回调监听,从监听中获取接收消息。
+```
\ No newline at end of file
diff --git a/docs/document/v1/electron/multi_device.md b/docs/document/v1/electron/multi_device.md
new file mode 100644
index 000000000..9012368e0
--- /dev/null
+++ b/docs/document/v1/electron/multi_device.md
@@ -0,0 +1,23 @@
+# 多设备管理监听
+
+当同一账号同时使用桌面端,移动端登录时,需要使用多设备管理监听事件,使用回调实现
+
+```
+// 实例化监听,并添加到客户端
+var listener = new easemob.EMMultiDevicesListener();
+emclient.addMultiDevicesListener(listener);
+
+// 设置回调
+// 收到其他设备的会话操作
+listener.onContactMultiDevicesEvent((operation, target, ext) => {
+ console.log('operation = ' + operation);
+ console.log('target = ' + target);
+ console.log('ext = ' + ext);
+});
+// 收到其他设备的组操作
+listener.onGroupMultiDevicesEvent((operation, target, usernames) => {
+ console.log('operation = ' + operation);
+ console.log('target = ' + target);
+ console.log('usernames = ' + usernames);
+});
+```
\ No newline at end of file
diff --git a/docs/document/v1/electron/overview.md b/docs/document/v1/electron/overview.md
new file mode 100644
index 000000000..800f8b9d6
--- /dev/null
+++ b/docs/document/v1/electron/overview.md
@@ -0,0 +1,152 @@
+# 集成概述说明
+
+桌面端 SDK 为用户在 Windows/Mac OS 平台上进行开发的 js 接口及二进制文件,开发框架使用 electron 。
+
+目前支持登录、注册、单聊、群聊、聊天室、文本消息、图片、语音、位置等消息以及透传消息,还可以实现好友管理、群组管理等功能。
+
+**注意:**之前的 Windows SDK 将不再维护,同时对应的 demo ,文档也一并下线。如需查看旧版文档,点击[Windows SDK 集成说明](https://docs-im.easemob.com/im/windows/intro/integration)
+
+------
+
+## 准备
+
+### 开发环境需求
+
+#### 操作系统
+
+- win7/win8/win10 64位操作系统
+
+- mac OS 10.10 及以上
+
+#### 开发工具
+
+- nodejs
+
+版本 10.0 以上,[官网地址](http://nodejs.cn/)
+
+- electron
+
+版本 4.0 以上,[官网地址](https://electronjs.org/),nodejs 安装完成后,可以在命令行使用 npm 命令安装,安装命令:
+
+```
+npm install electron -g
+```
+
+------
+
+## SDK 目录结构
+
+Windows SDK 目录结构如下。使用时将 SDK 拷贝到工程目录下。
+
+```
+|-node
+ |-modules
+ |-message
+ index.js
+ load.js
+|-easemob
+ easemobMac.node
+ easemobWin.node
+ libcurl.dll
+ libcurl.lib
+ libcrypto.1.0.0.dylib
+```
+
+------
+
+## SDK 模块介绍
+
+SDK 采用模块化设计,每一模块的功能相对独立和完善,用户可以根据自己的需求选择使用下面的模块:
+
+![img](https://docs-im.easemob.com/_media/im/windows/intro/sdk%E6%A8%A1%E5%9D%97.png)
+
+### 模块化设计
+
+- EMClient
+
+SDK 的入口,主要完成登录、退出、注册、配置管理等功能,管理连接监听模块 EMConnectionListener 。也是获取其他模块的入口。
+
+- EMChatManager
+
+管理消息的收发,完成会话管理等功能,管理会话监听模块 EMChatManagerListener 。
+
+- EMContactManager
+
+负责好友的添加删除,黑名单的管理等功能,管理好友变更监听模块 EMContactListener。
+
+- EMGroupManager
+
+负责群组的管理,创建、删除群组,管理群组成员等功能,管理群组监听模块 EMGroupManagerListener。
+
+- EMChatroomManager
+
+负责聊天室的查询、加入、退出功能管理,管理聊天室监听模块 EMChatroomManagerListener。
+
+------
+
+## SDK 对象说明
+
+SDK 中使用到的对象包括:
+
+- 系统配置信息 EMChatConfigs
+
+- 群组信息 EMGroup
+
+- 群组配置信息 EMMucSetting
+
+- 群文件信息 EMMucSharedFile
+
+- 聊天室信息 EMChatroom
+
+- 会话信息 EMConversation
+
+- 消息 EMMessage
+
+- 文本消息体 EMFileMessageBody
+
+- 图片消息体 EMImageMessageBody
+
+- 文件消息体 EMTextMessageBody
+
+- 命令消息体 EMCmdMessageBody
+
+具体接口[详见 SDK API Doc](https://downloads.easemob.com/doc/desktop/apidoc/index.html)
+
+### 依赖模块安装
+
+electron 开发中依赖的模块及版本写在 package.json 中,安装依赖模块时,在 sdkdemoapp_windows 目录下使用命令:
+
+```
+npm install
+```
+
+如果安装过程中出现 error,可能是网络原因,可以选择使用 yarn 镜像下载安装:
+
+```
+npm install -g yarn
+yarn install
+```
+
+------
+
+### 软件调试
+
+首先需要编译软件,运行命令:
+
+```
+npm run build:app
+```
+
+调试过程需要使用热启动,运行命令:
+
+```
+npm run hot-server
+```
+
+然后另启动一个命令行工具,运行命令:
+
+```
+npm run start:hot
+```
+
+可启动软件。调试过程中修改代码后,hot-server 会自动编译新代码,在界面上使用 F5 按键可以立即刷新界面,应用新代码。在界面上点击鼠标右键,弹出右键菜单,点击检查元素,可以打开开发者工具,查看 console 控制台输出,在 Source 中加断点调试。
\ No newline at end of file
diff --git a/docs/document/v1/electron/quickstart.md b/docs/document/v1/electron/quickstart.md
new file mode 100644
index 000000000..92402d244
--- /dev/null
+++ b/docs/document/v1/electron/quickstart.md
@@ -0,0 +1,228 @@
+# 快速开始
+
+## 加载SDK
+
+直接加载 index.js 模块,代码如下:
+
+```
+var easemob = require('../../node/index');
+```
+
+------
+
+## 用户登录
+
+登录前,需要先创建配置对象和 client 对象,用户可以使用 **用户名+密码** 和 **用户名+token** 两种方式登录。
+
+### 创建配置对象
+
+```
+/**
+ * 首先构造 sdk 配置信息
+ * param1 为资源存储路径,输入参数
+ * param2 为工作路径,输入参数,日志存储在这里
+ * param3 为 appkey ,输入参数,easemob-demo#chatdemoui 为 DemoAppKey ,需填写自己的 Appkey
+ * param4 为设备 ID ,默认 0
+ * return 配置模块对象
+ */
+var emchatconfigs = new easemob.EMChatConfig(".", ".", "easemob-demo#chatdemoui", 0);
+```
+
+### 创建 client 对象
+
+```
+var emclient = new easemob.EMClient(emchatconfigs);
+```
+
+#### 用户名+密码登录方式代码如下:
+
+```
+/**
+ * 密码登录 api ,异步操作
+ * param username 为用户名,输入, String
+ * param password 为密码,输入, String
+ * return 返回 Promise 对象,response 参数为 #Result
+ */
+login(username, password)
+```
+
+调用用方法如下:
+
+```
+emclient.login("jwfan", "jwfan").then((res) =>{
+if(res.code == 0)
+ console.log("login success");
+},(error) => {});
+```
+
+#### 用户名+token 登录方式代码如下:
+
+```
+/**
+ * token 登录 api ,异步操作
+ * param username 用户名,输入, String
+ * param token 用户 token ,输入, String
+ * return 返回 Promise 对象,response 参数为 #Result
+ */
+loginWithToken(username, token)
+```
+
+调用方法如下:
+
+```
+emclient.loginWithToken("jwfan", "Mytoken").then((res) =>{
+if(res.code == 0)
+ console.log("login success");
+},(error) => {});
+```
+
+登录接口返回值 ret 为 EMError 对象,登录成功则 ret 的 errorCode 为 0,否则可以用 description 获取错误信息 登录后获取用户信息方法如下:
+
+```
+// 获取用户信息,包括用户名,密码,token
+var loginInfo = emclient.getLoginInfo();
+console.log("loginInfo.loginUser = " + loginInfo.loginUser);
+console.log("loginInfo.loginPassword = " + loginInfo.loginPassword);
+console.log("loginInfo.loginToken = " + loginInfo.loginToken);
+```
+
+------
+
+## 用户退出
+
+用户退出代码如下:
+
+```
+// 返回退出结果 EMError 对象
+emclient.logout().then((res) => {
+if(res.code == 0)
+ console.log("logout success");
+},(error) => {});
+```
+
+------
+
+## 用户注册
+
+接口API如下:
+
+```
+/**
+ * 账户注册api,异步操作
+ * param username 用户名,输入,String
+ * param password 密码,输入,String
+ * return Promise对象,该对象的response参数为Result
+ */
+createAccount(username, password);
+
+
+调用方法如下:
+
+emclient.createAccount("newAccount","password").then((res) => {
+ if(res.errorCode == 0)
+ console.log("createAccount success");
+ else
+ console.log("createAccount fail:" + res.description);
+ },(error) => {})
+```
+
+------
+
+## 连接监听管理
+
+通过注册回调函数,可以监听 SDK 的连接与断开状态,在用户登录成功后调用,代码如下
+
+```
+// 实例化监听模块
+var listener = new easemob.EMConnectionListener();
+// 添加到client
+emclient.addConnectionListener(listener);
+
+// 连接成功,什么都不需要做
+listener.onConnect(() => {
+console.log("EMConnectionListener onConnect");
+});
+
+// 连接断开,可能是断网或异地登录被踢,可通过error.errorCode判断,若为206,即为被踢,需要退出登录
+listener.onDisconnect((res) => {
+console.log(res.errorCode);
+console.log(res.description);
+console.log("EMConnectionListener onDisconnect");
+if(res.errorCode == 206)
+ emclient.logout();
+ console.log("你的账户已在其他地方登录");
+});
+
+// 移除监听
+emclient.removeConnectionListener(listener);
+```
+
+------
+
+## 系统配置
+
+系统配置信息模块为 EMChatConfig ,可以使用 emclient 的 getChatConfigs() 接口获取
+
+```
+let config = emclient.getChatConfigs();
+```
+
+配置信息包括日志路径,资源路径、下载路径、是否自动同意好友申请、是否自动同意组邀请、退出群组时是否删除消息等,[详见](https://github.com/easemob/sdkdemoapp_windows/blob/electron/jsdoc/out/EmChatConfigs.html)
+
+------
+
+## 私有化部署
+
+sdk 提供私有化部署中的服务器设置接口,私有化部署设置使用 api 中的 **EMChatPrivateConfigs**,可以由系统配置模块的 **privateConfigs** 接口获取,代码如下:
+
+```
+let privateconfigs = config.privateConfigs();
+```
+
+**EMChatPrivateConfigs** 使用属性配置服务器部署信息,设置及获取的方法如下:
+
+```
+privateconfigs.enableDns=false;
+privateconfigs.chatServer="192.168.1.100";
+privateconfigs.chatPort=5000;
+privateconfigs.restServer="http://192.168.1.101:5001";
+privateconfigs.resolverServer="http://192.168.1.101:5002";
+console.log(privateconfigs.enableDns);
+console.log(privateconfigs.chatServer);
+console.log(privateconfigs.chatPort);
+console.log(privateconfigs.restServer);
+console.log(privateconfigs.resolverServer);
+```
+
+------
+
+## 日志输出
+
+SDK 提供输出到日志文件的 js 接口,需要先创建 EMLog 对象,可以输出 String 和数字,代码如下:
+
+```
+// 实例化日志对象,日志按等级可分为error,warn,Debug 3级
+var log = new easemob.EMLog();
+
+// 设置日志等级,0为debug,1为warn,2为error
+log.setLogLevel(0);
+
+// 可以控制日志是否输出到控制台,默认不输出
+log.setIsDisplayOnConsole(true);
+
+//输出日志
+log.Log("Log Test");
+log.Log(5);
+log.Debug("Debug Test");
+log.Debug(5);
+log.Warn("Warn Test");
+log.Warn(5);
+log.Error("Error Test");
+log.Error(5);
+```
+
+**注:**由于 EMChatConfig 对象创建时会指定日志输出路径,日志对象的创建一般放到 EMChatConfig 创建之后。
+
+Windows 桌面端日志生成在 c:/用户/{user}/AppData/Roaming/{ProcessName}/easemob-desktop/easemobLog 路径下的`easemob.log`,{user}为操作系统用户名,{ProcessName}为进程名称,热启动时为**electron**,安装后启动时为**IM-SDK桌面端Demo**。
+
+Mac 桌面端日志生成在 /Users/{user}/Library/Application Support/{ProcessName}/easemob-desktop/easemobLog 路径下的`easemolog.log`,{user}为操作系统用户名,{ProcessName}为进程名称,热启动时为**electron**,安装后启动时为**IM-SDK桌面端Demo**。
\ No newline at end of file
diff --git a/docs/document/v1/electron/releasenote.md b/docs/document/v1/electron/releasenote.md
new file mode 100644
index 000000000..cb44c8b6e
--- /dev/null
+++ b/docs/document/v1/electron/releasenote.md
@@ -0,0 +1,59 @@
+# 桌面端SDK 更新日志
+
+## 版本 V3.8.4 2021-12-09
+
+新增
+
+- 增加支持自定义消息的收发
+
+## 版本 V3.8.0 2021-03-13
+
+修复
+
+- 去掉音视频功能
+- 修复部分Demo bug
+
+## 版本 V3.6.0 2019-07-16
+
+新增
+
+- 1v1音视频会话功能
+
+修复
+
+- 修复了上传附件token过期时,重新获取的token在重试过程中未应用的bug
+- 修复了音视频消息体中remotePath路径为空的问题
+- 修复Demo UI层的bug
+
+## 版本 V3.5.5 2019-05-09
+
+新增
+
+- sdk 新增私有化部署的接口
+
+修复
+
+- 修复 Demo 在 mac 系统某些版本(如10.12)上,存在兼容性问题,无法启动的问题
+- 修改 sdk 收到消息后 ack 确认的发送为消息存储到数据库之后,防止突然崩溃导致的消息丢失
+- 修复 Demo UI 层的部分 bug
+
+优化
+
+- 离线消息的下载存储由单条存储改为多条批量存储,提升效率
+
+## 版本:V3.5.4 2019-03-26
+
+实现功能:
+
+- 账户的登录、登出、注册。
+
+- 聊天:单聊、群聊消息收发。
+
+- 消息类型:
+
+1. 可发送:文本、emoji表情、图片、文件。
+2. 可接收:文本、emoji表情、图片、文件、位置、语音消息。
+
+- 好友管理:添加好友、删除好友。
+
+- 群管理:创建群、退出群、解散群、修改群标题、邀请加入群、搜索公开群、申请加入公开群。
\ No newline at end of file
diff --git a/docs/document/v1/electron/room_manage.md b/docs/document/v1/electron/room_manage.md
new file mode 100644
index 000000000..dc437efbd
--- /dev/null
+++ b/docs/document/v1/electron/room_manage.md
@@ -0,0 +1,106 @@
+# 聊天室管理
+
+环信桌面端 SDK 支持聊天室功能的集成,集成后可以进行如下操作:
+
+- 查询聊天室信息
+
+- 加入聊天室
+
+- 退出聊天室
+
+- 监听回调
+
+通过这些操作,可以组合帮助您完成多种场景下的 IM 需求。
+
+**注意:**聊天室只能有服务端创建,客户端只可以查询、加入和退出聊天室
+
+------
+
+## 查询聊天室信息
+
+```
+// 获取聊天室控制对象
+var chatroomManager = emclient.getChatroomManager();
+// 获取所有聊天室
+var chatroomlist = chatroomManager.fetchAllChatrooms(error);
+// 获取聊天室属性
+chatroomlist.map((chatroom) => {
+ console.log("chatroom id:"+chatroom.chatroomId());
+ console.log("chatroom chatroomSubject:"+chatroom.chatroomSubject());
+ console.log("chatroom chatroomDescription:"+chatroom.chatroomDescription());
+ console.log("chatroom owner:"+chatroom.owner());
+ console.log("chatroom chatroomMemberCount:"+chatroom.chatroomMemberCount());
+ console.log("chatroom chatroomMemberMaxCount:"+chatroom.chatroomMemberMaxCount());
+ console.log("chatroom chatroomAnnouncement:"+chatroom.chatroomAnnouncement());
+ var adminlist = chatroom.chatroomAdmins();
+ var memberlist = chatroom.chatroomMembers();
+ var banslist = chatroom.chatroomBans();
+});
+```
+
+------
+
+## 加入聊天室
+
+接口 API 说明如下:
+
+```
+/**
+ * 加入聊天室
+ * param chatroomid 聊天室 ID
+ * param error 操作结果
+ * return Promise 对象,该对象的 response 参数 EMChatroom 对象
+ */
+joinChatroom(chatroomid,error);
+```
+
+调用方法如下:
+
+```
+chatroomManager.joinChatroom(chatroomId, error).then((res)=>{},(error) => {});
+```
+
+------
+
+## 退出聊天室
+
+接口 API 说明如下:
+
+```
+/**
+ * 离开聊天室
+ * param chatroomid 聊天室 ID
+ * param error 操作结果
+ * return Promise 对象,该对象的 response 参数为空
+ */
+leaveChatroom(chatroomid,error);
+```
+
+调用方法如下:
+
+```
+chatroomManager.leaveChatroom(chatroomId, error).then((res)=>{},(error) => {});
+```
+
+------
+
+## 回调监听
+
+```
+// 添加消息回调
+var emchatroomlistener = new easemob.EMChatroomManagerListener();
+console.log(emchatroomlistener);
+
+emchatroomlistener.onMemberJoinedChatroom((chatroom,member) => {
+ console.log("onMemberJoinedChatroom" + chatroom.chatroomSubject());
+ console.log("onMemberJoinedChatroom" + member);
+});
+emchatroomlistener.onMemberLeftChatroom((chatroom,member) => {
+ console.log("onMemberLeftChatroom" + chatroom.chatroomSubject());
+ console.log("onMemberLeftChatroom" + member);
+});
+//注册监听
+chatroomManager.addListener(emchatroomlistener);
+// 移除监听
+chatroomManager.removeListener(emchatroomlistener);
+```
\ No newline at end of file
diff --git a/docs/document/v1/electron/user_relationship.md b/docs/document/v1/electron/user_relationship.md
new file mode 100644
index 000000000..3d1afc810
--- /dev/null
+++ b/docs/document/v1/electron/user_relationship.md
@@ -0,0 +1,338 @@
+# 好友管理
+
+环信桌面端 SDK 支持好友功能的集成,集成后可以进行如下操作:
+
+- 好友处理
+
+- 黑名单处理
+
+- 监听联系人变更
+
+通过这些操作,可以组合帮助您完成多种场景下的 IM 需求。
+
+好友管理模块为 EMContactManager ,由 EMClient 模块加载时主动创建,可以使用 EMClient 模块的 getContactManager 方法获取,代码如下:
+
+```
+var contactManager = emclient.getContactManager();
+```
+
+------
+
+## 好友处理
+
+好友处理包含以下处理操作:
+
+- 获取好友列表
+
+- 添加好友
+
+- 删除好友
+
+- 同意好友申请
+
+- 拒绝好友申请
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 获取好友列表
+
+好友列表可以从**本地**和**服务器**获取,各接口说明如下:
+
+#### 从本地中获取
+
+接口 API 如下:
+
+```
+/**
+ * 获取当前缓存中的好友列表,若缓存中没有则从数据库中获取
+ * return 返回 ContactListResult
+ */
+allContacts()
+```
+
+调用方法如下:
+
+```
+let res = contactManager.allContacts();
+console.log()
+```
+
+#### 从服务器获取
+
+接口API如下:
+
+```
+/**
+ * 从服务端拉取好友列表,异步操作
+ * return 返回 Promise 对象,response 参数为 ContactListResult
+ */
+getContactsFromServer();
+```
+
+调用方法如下:
+
+```
+contactManager.getContactsFromServer().then(ContactListResult => {
+ },(error) => {});
+```
+
+------
+
+### 添加好友
+
+接口API如下:
+
+```
+/**
+ * 添加好友 api,异步操作
+ * param String,username 为对方用户名,输入参数
+ * param String,message 为欢迎信息,输入参数,对方收到好友申请时可以看到
+ * return Promise 对象,response 参数为 Result
+ */
+inviteContact(username, message);
+```
+
+调用方法如下:
+
+```
+contactManager.inviteContact("jwfan1", "welcome").then((res) => {
+ },(error) => {})
+```
+
+------
+
+### 删除好友
+
+接口API如下:
+
+```
+/**
+ * 从好友列表移除好友 api,异步操作
+ * param username 移除目标好友的用户名,输入参数
+ * param keepConversation 移除好友后,是否保留会话,输入参数,布尔型,true 为保留,false 为不保留
+ * return Promise 对象,response 参数 Result
+ */
+deleteContact(username,keepConversation);
+```
+
+调用方法如下:
+
+```
+contactManager.deleteContact("jwfan1", true).then((res) => {
+ },(error) => {})
+```
+
+------
+
+### 同意好友申请
+
+接口 API 如下:
+
+```
+/**
+ * 用户收到好友申请后的操作,同意好友申请,异步操作
+ * param username 发起好友申请的用户名,输入参数
+ * return Promise 对象,response 参数为 Result
+ */
+acceptInvitation(username);
+```
+
+调用方法如下:
+
+```
+contactManager.acceptInvitation(username).then((res) => {
+ },(error) => {})
+```
+
+------
+
+### 拒绝好友申请
+
+接口 API 如下:
+
+```
+/**
+ * 用户收到好友申请后的操作,拒绝好友申请,异步操作
+ * param username 发起好友申请的用户名,输入参数
+ * return Promise 对象,response 参数为 Result
+ */
+declineInvitation(username)
+```
+
+调用方法如下:
+
+```
+contactManager.declineInvitation(username).then((res) => {
+ },(error) => {})
+```
+
+------
+
+## 黑名单
+
+黑名单包含以下处理操作:
+
+- 获取黑名单
+
+- 设置黑名单
+
+- 移入黑名单
+
+- 从黑名单移除
+
+所有处理操作的示例下面会一一说明。
+
+------
+
+### 获取黑名单
+
+黑名单列表可以从**本地**和**服务器**获取,各接口说明如下:
+
+#### 从本地中获取
+
+接口 API 如下:
+
+```
+/**
+ * 从本地获取用户的黑名单列表,黑名单的用户无法发送消息
+ * return ContactListResult 黑名单列表,data 为 String 数组
+ */
+blacklist();
+```
+
+调用方法如下:
+
+```
+let res = contactManager.blacklist()
+```
+
+#### 从服务器获取
+
+接口 API 如下:
+
+```
+/**
+ * 从服务器获取用户的黑名单列表,黑名单的用户无法发送消息
+ * return Promise 对象,response 参数为 ContactListResult
+ */
+getBlackListFromServer();
+```
+
+调用方法如下:
+
+```
+contactManager.getBlackListFromServer().then((res) => {},(error) => {})
+```
+
+------
+
+### 设置黑名单
+
+接口 API 如下:
+
+```
+/**
+ * 设置用户的黑名单列表,异步操作
+ * param blacklist 输入参数,黑名单列表,StringArray,["ID1","ID2"]
+ * return Promise 对象,response 参数为 Result
+ */
+saveBlackList(blacklist);
+```
+
+调用方法如下:
+
+```
+contactManager.saveBlackList(['jwfan2', 'jwfan3']).then((res)=>{},(error) => {});
+```
+
+### 移入黑名单
+
+接口 API 如下:
+
+```
+/**
+ * 添加用户到黑名单列表,异步操作
+ * param username 输入参数,要添加的黑名单用户名,String
+ * return Promise 对象,response 参数为 Result
+ */
+addToBlackList(username);
+```
+
+调用方法如下:
+
+```
+contactManager.addToBlackList('jwfan2').then((res)=>{},(error) => {});
+```
+
+------
+
+### 从黑名单移除
+
+接口 API 如下:
+
+```
+/**
+ * 从黑名单列表移除用户,异步操作
+ * param username 输入参数,要从黑名单移除的用户名,String
+ * return Promise 对象,response 参数为 Result
+ */
+removeFromBlackList(username);
+```
+
+调用方法如下:
+
+```
+contactManager.removeFromBlackList('jwfan2').then((res)=>{},(error) => {});
+```
+
+------
+
+## 监听联系人变更
+
+通过注册回调函数,监听联系人的变动,代码如下:
+
+```
+// 实例化监听对象
+var listener = new easemob.EMContactListener();
+
+// 有好友添加的回调
+listener.onContactAdded((username) => {
+console.log("onContactAdded username: " + username);
+});
+
+// 有好友删除的回调
+listener.onContactDeleted((username) => {
+console.log("onContactDeleted username: " + username);
+});
+
+// 收到好友申请的回调,用户可以在这里同意或拒绝好友申请
+listener.onContactInvited((username, reason) => {
+console.log("onContactInvited username: " + username + " reason: " + reason);
+if (username == "jwfan1") {
+ let res = contactManager.acceptInvitation(username);
+} else {
+ let res = contactManager.declineInvitation(username);
+}
+});
+
+// 群组邀请成员同意
+listener.onContactAgreed((username) => {
+console.log("onContactAgreed username: " + username);
+});
+
+// 群组邀请成员拒绝
+listener.onContactRefused((username) => {
+console.log("onContactRefused username: " + username);
+});
+
+// 注册回调函数
+contactManager.registerContactListener(listener);
+
+
+===== 结束联系人监听 =====
+
+// 移除回调监听
+contactManager.removeContactListener(listener);
+```
\ No newline at end of file