diff --git a/docs/.vuepress/navbar/index.ts b/docs/.vuepress/navbar/index.ts index 2b1f45cdc..db8b2aaaa 100644 --- a/docs/.vuepress/navbar/index.ts +++ b/docs/.vuepress/navbar/index.ts @@ -4,13 +4,13 @@ export const zhNavbar = navbar([ // { text: '产品简介', link: '/product/introduction.html' }, { text: '即时通讯', children: [ - // { - // text: 'V1.0', - // link: '/document/v1/privatization/uc_deploy.html' - // }, + /**{ + text: 'V1.0', + link: '/document/v1/privatization/uc_introduction.html' + },**/ { text: 'V2.0', - link: '/document/v2/privatization/uc_deploy.html' + link: '/document/v2/privatization/uc_introduction.html' }, ] }, // { diff --git a/docs/.vuepress/sidebar/document_v1.ts b/docs/.vuepress/sidebar/document_v1.ts index 79dbc25f5..c800c6332 100644 --- a/docs/.vuepress/sidebar/document_v1.ts +++ b/docs/.vuepress/sidebar/document_v1.ts @@ -8,26 +8,26 @@ const platformList = getSubDirectories(DOC_PATH) const privateSidebar = { '/document/v1/privatization/': [ { - text: '服务部署', + text: '产品简介', children: [ - { text: '私有化服务部署', link: 'uc_deploy.html' }, + { text: '产品概述', link: 'uc_introduction.html' }, + { text: '产品使用限制', link: 'uc_limitation.html' }, + { text: '术语表', link: 'uc_glossary.html' }, ] - }, + } , { - text: '配置说明', - children: [ - { text: 'Console配置说明', link: 'uc_configure.html' }, - { text: 'Android私有化配置', link: 'uc_android_private.html' }, - { text: 'iOS私有化配置', link: 'uc_iOS_private.html' }, - { text: 'Web私有化配置', link: 'uc_Web_private.html' }, - ] - }, - { - text: 'SDK下载', - children: [ - { text: 'SDK 及 Demo 下载', link: 'uc_private.html' }, - ] - }, + text: '快速开始', + children: [ + /**{ text: '服务部署', link: 'uc_deploy.html' }, + { text: '客户端下载', link: 'uc_private.html' },**/ + { text: 'Console指南', link: 'uc_configure.html' }, + { text: 'App Token 鉴权', link: 'easemob_app_token.html' }, + { text: 'User Token 鉴权', link: 'easemob_user_token.html' }, + { text: '快速开始(不使用 UIKIT) Android', link: '/document/v1/android/overview.html' }, + { text: '快速开始(不使用 UIKIT)iOS', link: '/document/v1/ios/quickstart.html' }, + { text: '快速开始(不使用 UIKIT) Web', link: '/document/v1/web/quickstart.html' }, + ] + } , ] } @@ -46,9 +46,9 @@ const documentSidebar = [ */ text: '快速开始', children: [ - { text: 'React Demo(WebIM)体验', link: 'demo_react.html', only: ['web'] }, + /** { text: 'React Demo(WebIM)体验', link: 'demo_react.html', only: ['web'] }, { text: 'Vue Demo(WebIM)体验', link: 'demo_vue.html', only: ['web'] }, - { text: 'Demo(EaseIM App)体验', link: 'demo.html', except: ['web', 'windows', 'react-native', 'flutter', 'unity', 'server-side'] }, + { text: 'Demo(EaseIM App)体验', link: 'demo.html', except: ['web', 'windows', 'react-native', 'flutter', 'unity', 'server-side'] },*/ { text: '快速开始(不使用 EaseIMKIT)', link: 'quickstart.html', except: ['windows', 'react-native', 'flutter', 'unity', 'server-side'] }, { text: '快速开始 (不使用 UIKit)', link: 'quickstart.html', only: ['windows', 'react-native', 'flutter', 'unity'] }, { text: 'SDK 集成概述(不使用 EaseIMKIT)', link: 'overview.html', only: ['android', 'ios', 'web', 'flutter'] }, @@ -60,15 +60,16 @@ const documentSidebar = [ { text: '使用环信 App Token 鉴权', link: 'easemob_app_token.html', only: ['server-side'] }, { text: '使用环信 User Token 鉴权', link: 'easemob_user_token.html', only: ['server-side'] }, { text: 'IM 产品使用限制', link: 'limitation.html', only: ['server-side'] }, - { text: '接口频率限制', link: 'limitationapi.html', only: ['server-side'] }, + /** { text: '接口频率限制', link: 'limitationapi.html', only: ['server-side'] },**/ ], - except: ['applet'] + except: ['applet','linux','electron'] }, { text: '基础功能', children: [ - { - text: '消息管理', + {text: '消息管理', link: 'message.html' }, + /** + {text: '消息管理', collapsible: true, children: [ { text: '消息概述', link: 'message_overview.html' }, @@ -80,10 +81,10 @@ const documentSidebar = [ { text: '修改消息', link: 'message_modify.html' }, { text: '翻译', link: 'message_translation.html' }, ] - }, - { text: '管理用户属性', link: 'userprofile.html' }, - { text: '管理用户关系', link: 'user_relationship.html' }, - { + },**/ + /** { text: '管理用户属性', link: 'userprofile.html' },**/ + { text: '好友管理', link: 'user_relationship.html' }, + /**{ text: '群组管理', collapsible: true, children: [ @@ -92,8 +93,12 @@ const documentSidebar = [ { text: '管理群组成员', link: 'group_members.html' }, { text: '管理群组属性', link: 'group_attributes.html' }, ] - }, - { + },**/ + { text: '群组管理', link: 'group.html' }, + { text: '聊天室管理', link: 'chatroom.md' }, + { text: '多设备管理', link: 'multidevices.md' }, + { text: '导入第三方表情包', link: 'sticker.md' , only: ['web'] }, + /**{ text: '聊天室管理', collapsible: true, children: [ @@ -102,35 +107,37 @@ const documentSidebar = [ { text: '管理聊天室成员', link: 'room_members.html' }, { text: '管理聊天室属性', link: 'room_attributes.html' }, ] - }, + },**/ ], - except: ['applet', 'server-side'] + except: ['applet', 'server-side', 'electron'] }, { - text: '进阶功能', + text: '消息推送', children: [ - { text: '设置推送', link: 'push.html', except: ['windows', 'react-native', 'flutter', 'unity'] }, - { text: '登录多个设备', link: 'multi_device.html' }, - { text: '管理在线状态订阅', link: 'presence.html' }, - { text: '消息表情回复', link: 'reaction.html' }, - { - text: '子区管理', - collapsible: true, - children: [ - { text: '管理子区', link: 'thread.html' }, - { text: '管理子区消息', link: 'thread_message.html' } - ] - }, - { text: '消息审核(举报)', link: 'moderation.html'}, + { text: '第三方推送集成', link: 'thirdpartypush.html' }, + { text: '第三方推送异常情况说明', link: 'exceptions.html' }, + { text: '设置当前登录用户的推送昵称', link: 'nickname.html' }, + { text: '离线推送问题排查', link: 'troubleshooting.html' }, ], - except: ['applet','server-side'] + only: ['android'] + }, + { + text: 'APNs消息推送', + children: [ + { text: 'APNs推送配置', link: 'deploy.html' }, + { text: 'APNs离线推送', link: 'offline.html' }, + { text: 'APNs内容解析', link: 'content.md' }, + /*{ text: '离线推送问题排查', link: '../android/troubleshooting.html' },*/ + ], + only: ['ios'] }, { text: '其他', children: [ { text: '错误码', link: 'error.html' }, + { text: '工具类说明', link: 'toolrelated.md' , only: ['web'] }, { text: 'EaseIMKit 使用指南', link: 'easeimkit.html', except: ['web', 'windows', 'react-native', 'flutter', 'unity'] }, - { text: 'EaseCallKit 使用指南', link: 'easecallkit.html', except: ['web', 'windows', 'react-native', 'flutter', 'unity'] }, + /**{ text: 'EaseCallKit 使用指南', link: 'easecallkit.html', except: ['web', 'windows', 'react-native', 'flutter', 'unity'] },**/ ], except: ['applet', 'server-side'] }, @@ -167,8 +174,8 @@ const documentSidebar = [ { text: '发送和接收消息', link: 'message_send_receive.html' }, { text: '管理服务端消息', link: 'message_retrieve.html' }, { text: '管理消息回执', link: 'message_receipt.html' }, - { text: '修改消息', link: 'message_modify.html' }, - { text: '翻译', link: 'message_translation.html' }, + /** { text: '修改消息', link: 'message_modify.html' }, + { text: '翻译', link: 'message_translation.html' },**/ ] }, { text: '用户属性', link: 'userprofile.html' }, @@ -199,9 +206,9 @@ const documentSidebar = [ { text: '进阶功能', children: [ + { text: '登录多个设备', link: 'multi_device.md' }, { text: '设置推送', link: 'push.html', except: ['windows', 'react-native', 'flutter', 'unity'] }, - { text: '登录多个设备', link: 'multi_device.html' }, - { text: '管理在线状态订阅', link: 'presence.html' }, + /**{ text: '管理在线状态订阅', link: 'presence.html' }, { text: '消息表情回复', link: 'reaction.html' }, { text: '子区管理', @@ -211,7 +218,7 @@ const documentSidebar = [ { text: '管理子区消息', link: 'thread_message.html' } ] }, - { text: '消息审核(举报)', link: 'moderation.html'}, + { text: '消息审核(举报)', link: 'moderation.html'},**/ ], only: ['applet'] }, @@ -229,7 +236,7 @@ const documentSidebar = [ children: [ { text: '即时通讯 REST API 概览', link: 'overview.html' }, { text: '用户体系管理', link: 'account_system.html' }, - { text: '推送设置', link: 'push.html' }, + /**{ text: '推送设置', link: 'push.html' },**/ { text: '消息管理', children: [ @@ -238,19 +245,18 @@ const documentSidebar = [ { text: '发送聊天室消息', link: 'message_chatroom.html' }, { text: '上传和下载文件', link: 'message_download.html' }, { text: '获取历史消息记录', link: 'message_historical.html' }, - { text: '撤回消息和单向删除会话', link: 'message_recall.html' }, - { text: '导入消息', link: 'message_import.html' } + /**{ text: '导入消息', link: 'message_import.html' }**/ ] }, { text: '用户属性', link: 'userprofile.html' }, { text: '用户关系管理', link: 'user_relationship.html' }, { text: '群组', link: 'group.html' }, { text: '聊天室', link: 'chatroom.html' }, - { text: '在线状态订阅', link: 'presence.html' }, - { text: '消息表情回复', link: 'reaction.html' }, + /**{ text: '在线状态订阅', link: 'presence.html' }, + { text: '消息表情回复', link: 'reaction.html' },**/ ], only: ['server-side'] - }, + },/** { text: 'Server SDK', children: [ @@ -258,7 +264,7 @@ const documentSidebar = [ { text: 'PHP Server SDK', link: 'php_server_sdk.html' }, ], only: ['server-side'] - }, + }, **/ { text: '错误码', children: [ @@ -274,7 +280,45 @@ const documentSidebar = [ { text: '发送后回调-事件回调', link: 'callback_configurations.html' } ], only: ['server-side'] - } + }, + { + text: 'Linux开发文档', + children: [ + { text: '集成说明', link: 'overview.html' }, + { text: '技术参数', link: 'techspec.html' }, + { text: 'SDK更新日志', link: 'releasenote.html' }, + ], + only: ['linux'] + }, + { + text: '快速开始', + children: [ + { text: 'Demo下载体验', link: 'demo.html' }, + { text: '快速开始', link: 'quickstart.html' }, + { text: '集成概述', link: 'overview.html' }, + { text: 'SDK更新日志', link: 'releasenote.html' }, + ], + only: ['electron'] + }, + { + text: '基础功能', + children: [ + { text: '消息管理', link: 'message.html' }, + { text: '会话管理', link: 'chatmanage.html' }, + { text: '好友管理', link: 'user_relationship.html' }, + { text: '群组管理', link: 'group_manage.html' }, + { text: '聊天室管理', link: 'room_manage.html' }, + ], + only: ['electron'] + }, + { + text: '进阶功能', + children: [ + { text: '多设备监听', link: 'multi_device.html' }, + { text: '附录', link: 'appendix.html' }, + ], + only: ['electron'] + }, ] function buildDocSidebar() { diff --git a/docs/document/v1/android/chatroom.md b/docs/document/v1/android/chatroom.md new file mode 100644 index 000000000..1ecf154f0 --- /dev/null +++ b/docs/document/v1/android/chatroom.md @@ -0,0 +1,384 @@ +# 聊天室管理 + + +环信聊天室模型支持默认最大成员数为 5000,和群组不同,聊天室内成员离线后,服务器当监听到此成员不在线后不再会给此成员再发推送。聊天室成员数可调整,请联系商务。 + +- 默认支持最大成员数 5000,调整请联系商务; +- 环信的聊天室内有所有者,管理员和游客三种身份; +- 支持禁言,黑名单,踢人等操作; +- 不支持客户端邀请; +- 不支持 REST 邀请。 +- 聊天室 API 通常是同步操作,需要在单独的线程中执行,如需使用异步 API,请使用 async 前缀对应的 API + +环信聊天室客户端的主要特性包括: + +- 支持查询所有 APP 聊天室; +- 支持查询聊天室详情; +- 加入聊天室; +- 退出聊天室; +- 客户端的 API 都是通过 `EMChatroomManager(EMClient.getInstance().chatroomManager())` 操作。 + +### 服务器端API + +服务器端聊天室有关的 REST 操作请参考[聊天室管理](/document/v1/server-side/chatroom.html)。 + +### 加入聊天室 + +``` +//roomId为聊天室ID +EMClient.getInstance().chatroomManager().joinChatRoom(roomId, new EMValueCallBack() { + + @Override + public void onSuccess(EMChatRoom value) { + //加入聊天室成功 + } + + @Override + public void onError(final int error, String errorMsg) { + //加入聊天室失败 + } + }); +``` + +**注意**对于聊天室模型,请一定要等到 Join 回调成功后再去初始化 conversation。 + +### 离开聊天室 + +``` +EMClient.getInstance().chatroomManager().leaveChatRoom(toChatUsername); +``` + +此方法是异步方法,不会阻塞当前线程。此方法没有回调,原因是在任何场景下退出聊天室,SDK 保证退出成功,无论有网出错,还是无网退出。对于聊天室模型,一般退出会话页面,就会调用此 leave 方法。 + +### 创建聊天室 + +``` +/** + * \~chinese + * 创建聊天室,聊天室最大人数上限10000。只有特定用户有权限创建聊天室。 + * @param subject 名称 + * @param description 描述 + * @param welcomeMessage 邀请成员加入聊天室的消息 + * @param maxUserCount 允许加入聊天室的最大成员数 + * @param members 邀请加入聊天室的成员列表 + * @return EMChatRoom 聊天室 + * @throws HyphenateException + */ +EMClient.getInstance().chatroomManager().createChatRoom(String subject, String description, String welcomeMessage, + int maxUserCount, List members); +``` + +### 销毁聊天室 + +``` +/** + * 销毁聊天室,需要owner权,同步方法 + * @param chatRoomId + * @throws HyphenateException + */ +EMClient.getInstance().chatroomManager().destroyChatRoom(String chatRoomId); +``` + + +### 获取聊天室列表 + +``` +/** + * pageSize: 此次获取的条目 + * cursor: 后台需要的cursor ID,根据此ID再次获取pageSize的条目,首次传null即可 + */ +EMCursorResult result = EMClient.getInstance().chatroomManager().fetchPublicChatRoomsFromServer(pageSize, cursor) +``` + +返回值: + +``` +EMCursorResult 内部包含返回的cursor和List +``` + +### 获取聊天室详情 + +``` +/** + * roomId 聊天室id + * fetchMembers 是否要获取聊天室成员,可不传 + */ +//EMClient.getInstance().chatroomManager().fetchChatRoomFromServer(roomId, fetchMembers) +EMClient.getInstance().chatroomManager().fetchChatRoomFromServer(roomId) +room.getName();//聊天室名称 +room.getId();//聊天室id +room.getDescription();//聊天室描述 +room.getOwner();//聊天室创建者 + +``` +参考[API文档](http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_chat_room.html) + + + \ No newline at end of file diff --git a/docs/document/v1/android/demo.md b/docs/document/v1/android/demo.md index e675ba063..0b8f7fc8a 100644 --- a/docs/document/v1/android/demo.md +++ b/docs/document/v1/android/demo.md @@ -4,23 +4,22 @@ 环信即时通讯 IM Android 端提供示例应用可供体验。 -1. [下载 Demo](https://www.easemob.com/download/demo)。 +1. [下载 Demo](https://downloadsdk.easemob.com/mp/downloads/sdk/imsdkdemo_android-4.1.2.apk)。 -2. 输入你的手机号,获取验证码,然后输入。 +2. 输入你的登录账号和密码。 3. 选择同意《环信服务条款》与《环信隐私协议》,然后点击 **登录** 登录 Demo。 -![img](@static/images/demo/android_login.png) + ## 代码下载 您可以通过以下两种方式获取到源代码: -- 下载代码压缩包:[IM SDK 及 Demo 下载](https://www.easemob.com/download/im) -- 下载源代码:[github源码地址](https://github.com/easemob/chat-android) +- 下载代码压缩包:[IM SDK 及 Demo 下载](https://downloadsdk.easemob.com/downloads/easemob-sdk-4.1.2.zip) 欢迎大家提交 PR 改进和修复 EaseIM 和 EaseIMKit 中的问题。 ## 导入 EaseIM -从 [IM SDK 及 Demo 下载](https://www.easemob.com/download/im) 下载 Android SDK 压缩包,然后解压。解压后在 examples 文件夹下,即为 EaseIM 的工程目录。 +下载 Android SDK 压缩包,然后解压。解压后在 examples 文件夹下,即为 EaseIM 的工程目录。 ### 导入到 Android Studio 打开 Android Studio,点击 File > Open,打开 EaseIm3.0 根目录即可。 :::notice @@ -58,6 +57,14 @@ - **ContactListFragment**:继承自 EaseIMKit 中的 EaseContactListFragment,展示了添加头布局,添加条目长按功能及实现条目点击事件等; - **GroupDetailActivity**:实现了如下功能:添加群成员,修改群公告及群介绍,上传共享文件,进行群组管理,设置消息免打扰及解散或者退出群组等。 ## 部分 UI 展示 -![会话列表](@static/images/android/app-demo-ui-1.jpeg) -![联系人列表](@static/images/android/app-demo-ui-2.jpeg) -![聊天页面](@static/images/android/app-demo-ui-3.jpeg) \ No newline at end of file + +   +   + + \ No newline at end of file diff --git a/docs/document/v1/android/easecallkit.md b/docs/document/v1/android/easecallkit.md index 7af7401b8..b05b483c7 100644 --- a/docs/document/v1/android/easecallkit.md +++ b/docs/document/v1/android/easecallkit.md @@ -14,7 +14,7 @@ ## 跑通 Demo -EaseCallKit 集成在环信开源 IM Demo 中,你可以通过进入 [环信 Demo 及源码](https://www.easemob.com/download/im) 下载页面,选择 Android 端进行下载,直接下载: [Android IM 源码](https://github.com/easemob/chat-android)。 +EaseCallKit 集成在环信开源 IM Demo 中,你可以直接下载 Android 端源码 [Android IM 源码](https://downloadsdk.easemob.com/downloads/easemob-sdk-4.1.2.zip)。 环境准备: @@ -32,7 +32,7 @@ EaseCallKit 集成在环信开源 IM Demo 中,你可以通过进入 [环信 De 集成该库之前,你需要满足以下条件: -- 分别创建 [环信应用](/product/enable_and_configure_IM.html) 及 [声网应用](https://docportal.shengwang.cn/cn/video-legacy/run_demo_video_call_ios?platform=iOS#1-创建声网项目); +- 分别创建 [环信应用](/document/v1/privatization/uc_configure.html) 及 [声网应用](https://docportal.shengwang.cn/cn/video-legacy/run_demo_video_call_ios?platform=iOS#1-创建声网项目); - 已完成环信 IM 的基本功能,包括登录、好友、群组以及会话等的集成; - 上线之前开通声网 Token 验证时,用户需要实现自己的 [App Server](https://github.com/easemob/easemob-im-app-server/tree/master/agora-app-server),用于生成 Token。具体请参见 [创建 Token 服务及使用 App Server 生成 Token](https://docportal.shengwang.cn/cn/video-call-4.x/token_server_ios_ng)。 @@ -65,7 +65,7 @@ implementation 'io.hyphenate:ease-call-kit:3.8.9' #### 源码集成 -- 下载 [EaseCallKit 源码](https://github.com/easemob/easecallkitui-android); +- 下载 [EaseCallKit 源码](https://github.com/easemob/easecallkitui-android/tree/EaseCallKit_4.1.0); - 在 `build.gradle` 中增加以下内容,重新 build 你的项目即可。 ```gradle @@ -201,7 +201,7 @@ public void startInviteMultipleCall(final String[] users,final String ext){} 发起通话后的 UI 界面如下: -![img](@static/images/android/sendcall.png) + ### 被叫收到通话邀请 @@ -221,7 +221,7 @@ void onRevivedCall(EaseCallType callType, String userId,String ext){} 收到通话邀请后的界面如下: -![img](@static/images/android/called.jpeg) + ### 多人通话中邀请 diff --git a/docs/document/v1/android/easeimkit.md b/docs/document/v1/android/easeimkit.md index 572314c07..4235dd546 100644 --- a/docs/document/v1/android/easeimkit.md +++ b/docs/document/v1/android/easeimkit.md @@ -12,11 +12,11 @@ EaseIMKit 是什么? EaseIMKit 源码地址 -- [EaseIMKit](https://github.com/easemob/easeui/tree/EaseIMKit) +- [EaseIMKit](https://github.com/easemob/easeui/tree/EaseIMKit_4.1.0) 使用 EaseIMKIt 的环信 IM APP 源码地址: -- [环信 IM](https://github.com/easemob/chat-android) +- [环信 IM](https://downloadsdk.easemob.com/downloads/easemob-sdk-4.1.2.zip) ## 导入 EaseIMKit @@ -100,7 +100,8 @@ EaseIMKit 封装了常用 IM 功能,提供了会话,聊天及联系人等基 EaseIMKit 提供了 EaseConversationListFragment,需要将其或者其子类添加到 Activity 中。开发者需要对刷新事件(新消息,删除消息,删除会话等)进行处理。 -![img](@static/images/android/easeim.jpeg) + + :::notice 要实现自定义头像及昵称,请参考 [设置头像和昵称](userprofile.html#设置当前用户的属性)。 @@ -136,13 +137,13 @@ public class ChatActivity extends BaseActivity { } ``` -![img](@static/images/android/easeim1.jpeg) + ### 添加联系人界面 EaseIMKit 提供了 EaseContactListFragment,添加其及其子类到 Activity 中。开发者需要对刷新事件(添加联系人,删除联系人等)进行处理。 -![img](@static/images/android/easeim2.jpeg) + ## 设置样式 @@ -150,7 +151,7 @@ EaseIMKit 提供了 EaseContactListFragment,添加其及其子类到 Activity EaseIMKit 提供了自定义的标题栏控件 EaseTitleBar。 -![img](@static/images/android/easeim-titlebar.jpeg) + 标题栏除了做为 View 所具有的属性功能外,还可以设置标题的位置等。 @@ -215,10 +216,10 @@ conversationListLayout.hideUnreadDot(false); conversationListLayout.showUnreadDotPosition(EaseConversationSetStyle.UnreadDotPosition.LEFT); ``` -效果如下图: +效果如下图,更多样式请参考 EaseContactListLayout 控件。 + + -![img](@static/images/android/easeim3.jpeg) -更多样式请参考 EaseContactListLayout 控件。 #### 增加长按菜单项 @@ -262,7 +263,7 @@ public boolean onMenuItemClick(MenuItem item, int position) { 聊天窗口包括标题栏(不包含在 EaseChatFragment 中),聊天区,输入区及扩展展示区,如下图所示: -![img](@static/images/android/easeim4.png) + 标题区 EaseTitleBar 的具体布局及实现不在 EaseIMKit 库的聊天控件及 fragment 中,需要你自己去实现。 开发者可以在 EaseChatFragment 中获取到 EaseChatLayout 这个控件,然后通过这个控件进一步获取到获取其他控件,代码如下: @@ -295,7 +296,7 @@ messageListLayout.setBackground(new ColorDrawable(Color.parseColor("#DA5A4D"))); 效果如下图: -![img](@static/images/android/easeim5.jpeg) + #### 修改头像属性 @@ -312,7 +313,7 @@ messageListLayout.setAvatarShapeType(1); 效果如下图: -![img](@static/images/android/easeim6.jpeg) + #### 修改聊天文本 @@ -329,7 +330,7 @@ messageListLayout.setItemTextColor(ContextCompat.getColor(mContext, R.color.red) 效果如下图: -![img](@static/images/android/easeim7.jpeg) + #### 修改时间线样式 @@ -348,7 +349,7 @@ messageListLayout.setTimeTextColor(ContextCompat.getColor(mContext, R.color.blac 效果如下图: -![img](@static/images/android/easeim8.jpeg) + #### 修改聊天列表展示样式 @@ -363,7 +364,7 @@ messageListLayout.setItemShowType(EaseChatMessageListLayout.ShowType.LEFT); 效果如下图: -![img](@static/images/android/easeim9.jpeg) + #### 修改输入区样式 @@ -395,25 +396,26 @@ if(primaryMenu != null) { 效果(EaseInputMenuStyle.DISABLE_VOICE)如下图: -![img](@static/images/android/easeim10.jpeg) + + 其他样式为: 完整模式(EaseInputMenuStyle.All): -![img](@static/images/android/easeim11.jpeg) + 不可用表情模式(EaseInputMenuStyle.DISABLE_EMOJICON): -![img](@static/images/android/easeim12.jpeg) + 不可用语音和表情模式(EaseInputMenuStyle.DISABLE_VOICE_EMOJICON): -![img](@static/images/android/easeim13.jpeg) + 只有文本输入模式(EaseInputMenuStyle.ONLY_TEXT): -![img](@static/images/android/easeim14.jpeg) + #### 增加自定义消息类型及其布局 @@ -768,7 +770,7 @@ contactList.setHeaderBackGround(ContextCompat.getDrawable(mContext, R.color.whit 效果如图: -![img](@static/images/android/easeim15.jpeg) + 设置简洁模式 @@ -779,7 +781,8 @@ contactLayout.showSimple(); 效果如图: -![img](@static/images/android/easeim16.jpeg) + + #### 增加长按菜单项 diff --git a/docs/document/v1/android/exceptions.md b/docs/document/v1/android/exceptions.md new file mode 100644 index 000000000..08931fda8 --- /dev/null +++ b/docs/document/v1/android/exceptions.md @@ -0,0 +1,30 @@ +# 第三方推送异常情况说明 + + +IM 推送服务支持第三方厂商推送通道,包含苹果 APNS 推送、小米推送、华为推送、魅族推送、vivo 推送、OPPO 推送以及 Google FCM 推送。 + +:::tip +当第三方推送通道返回证书不可用相关报错时,环信 IM 推送服务会对相应证书进行禁用处理,封禁后会向 console 后台注册账号(超级管理员)的邮箱和手机号发送通知,重新上传可用证书后即可正常使用。 +::: + +本文档主要说明各第三方通道的因异常报错会导致证书被禁用的情况、以及建议的处理方案。 + +## 异常说明以及处理建议 + +可能导致证书被禁用的异常原因如下: + +| 第三方厂商 | 异常禁用原因 | 第三方错误码 | 处理建议 | +| --------------- | ---------------------------------------- | ------------ | --------------------------------------------- | +| vivo 推送 | appId 不存在 | 10205 | 证书名称上传错误,请核对证书信息。 | +| 小米推送 | 认证失败 | 21301 | 证书密钥上传错误,请核对密钥。 | +| OPPO 推送 | 无效的 App Key 参数 | 14 | 证书名称上传错误,请核对证书信息。 | +| OPPO 推送 | 无效的签名 | 16 | 证书密钥上传错误,请核对密钥。 | +| 魅族推送 | appId 不合法 | 110000 | 证书名称上传错误,请核对证书信息。 | +| 魅族推送 | 签名认证失败 | 1006 | 证书密钥上传错误,请核对密钥。 | +| 华为推送 | 参数无效 | 1101 | 证书名称或证书密钥上传错误,请核对证书信息。 | +| Google FCM 推送 | 无效的 token | 无 | 证书密钥无效,请核对证书信息以及证书可用性。 | +| 苹果 APNS 推送 | keystore password was incorrect | 无 | 证书密钥上传错误,请核对密钥。 | +| 苹果 APNS 推送 | certificate_revoked | 无 | 证书被撤销,请重新申请证书。 | +| 苹果 APNS 推送 | certificate_expired | 无 | 证书过期,请重新申请证书。 | +| 苹果 APNS 推送 | InvalidProviderToken | 无 | P8 证书无效,请重新申请证书。 | +| 苹果 APNS 推送 | Could not find private key header/footer | 无 | P8 证书文件内容识别错误,请重新上传正确证书。 | \ No newline at end of file diff --git a/docs/document/v1/android/group.md b/docs/document/v1/android/group.md new file mode 100644 index 000000000..a6e4e8f1a --- /dev/null +++ b/docs/document/v1/android/group.md @@ -0,0 +1,521 @@ +# 群组管理 + + +许多群组操作前需要鉴别权限,包括当前用户是否在群里面,是否拥有管理员或者所有者权限。 建议用户登录成功后,调用 EMClient.getInstance().groupManager().getJoinedGroupsFromServer(); 刷新本地群组列表,确保鉴别权限正常工作。 + + +**注意**:`1、群主+管理员 一起一共不超过 100 个,也就是不超过 99 个管理员。2、群组成员最大数(包括群主)取决于所选择的版本,不同版本最大数不同。` + +------ + +## 收发消息 + +收发消息及聊天记录相关内容等详见 [消息](message)。 + +## 新建群组 + +``` +/** + * 创建群组 + * @param groupName 群组名称 + * @param desc 群组简介 + * @param allMembers 群组初始成员,如果只有自己传空数组即可(最多可以传100个成员) + * @param reason 邀请成员加入的reason + * @param option 群组类型选项,可以设置群组最大用户数(取决于所选择的版本,不同版本最大数不同)及群组类型@see {@link EMGroupStyle} + * option.inviteNeedConfirm表示邀请对方进群是否需要对方同意,默认是被邀请方自动进群。 + * option.extField创建群时可以为群组设定扩展字段,方便个性化订制。 + * @return 创建好的group + * @throws HyphenateException + */ +EMGroupOptions option = new EMGroupOptions(); +option.maxUsers = 200; +option.style = EMGroupStyle.EMGroupStylePrivateMemberCanInvite; + +EMClient.getInstance().groupManager().createGroup(groupName, desc, allMembers, reason, option); +``` + +注:如果option.inviteNeedConfirm设置为false,即直接加被邀请人进群。在此情况下,被邀请人设置非自动进群是不起作用的。 + +option里的GroupStyle分别为: + +- `EMGroupStylePrivateOnlyOwnerInvite`——私有群,只有群主可以邀请人; +- `EMGroupStylePrivateMemberCanInvite`——私有群,群成员也能邀请人进群; +- `EMGroupStylePublicJoinNeedApproval`——公开群,加入此群除了群主邀请,只能通过申请加入此群; +- `EMGroupStylePublicOpenJoin` ——公开群,任何人都能加入此群。 + +## 添加管理员权限 + +``` +/** + * 增加群组管理员,需要owner权限 + * @param groupId + * @param admin + * @return + * @throws HyphenateException + */ +EMClient.getInstance().groupManager().addGroupAdmin(final String groupId, final String admin);//需异步处理 +``` + +## 移除管理员权限 + +``` +/** + * 删除群组管理员,需要owner权限 + * @param groupId + * @param admin + * @return + * @throws HyphenateException + */ +EMClient.getInstance().groupManager().removeGroupAdmin(String groupId, String admin);//需异步处理 +``` + +## 变更群组所有者 + +``` +/** + * 群组所有权给他人 + * @param groupId + * @param newOwner + * @return + * @throws HyphenateException + */ +EMClient.getInstance().groupManager().changeOwner(String groupId, String newOwner);//需异步处理 +``` + +## 群组加人 + +``` +//群主加人调用此方法 +EMClient.getInstance().groupManager().addUsersToGroup(groupId, newmembers);//需异步处理 +//私有群里,如果开放了群成员邀请,群成员邀请调用下面方法 +EMClient.getInstance().groupManager().inviteUser(groupId, newmembers, null);//需异步处理 +``` + +## 群组踢人 + +``` +//把username从群组里删除 +EMClient.getInstance().groupManager().removeUserFromGroup(groupId, username);//需异步处理 +``` + +## 加入某个群组 + +只能用于加入公开群。 + +``` +//如果群开群是自由加入的,即group.isMembersOnly()为false,直接join +EMClient.getInstance().groupManager().joinGroup(groupid);//需异步处理 +//需要申请和验证才能加入的,即group.isMembersOnly()为true,调用下面方法 +EMClient.getInstance().groupManager().applyJoinToGroup(groupid, "求加入");//需异步处理 +``` + +## 退出群组 + +``` +EMClient.getInstance().groupManager().leaveGroup(groupId);//需异步处理 +``` + +## 解散群组 + +``` +EMClient.getInstance().groupManager().destroyGroup(groupId);//需异步处理 +``` + +## 获取完整的群成员列表 + +``` +//如果群成员较多,需要多次从服务器获取完成 + +List memberList = new ArrayList<>; +EMCursorResult result = null; +final int pageSize = 20; +do { + result = EMClient.getInstance().groupManager().fetchGroupMembers(groupId, + result != null ? result.getCursor() : "", pageSize); + memberList.addAll(result.getData()); +} while (!TextUtils.isEmpty(result.getCursor()) && result.getData().size() == pageSize); +``` + +## 获取群组列表 + +``` +//从服务器获取自己加入的和创建的群组列表,此api获取的群组sdk会自动保存到内存和db。 +List grouplist = EMClient.getInstance().groupManager().getJoinedGroupsFromServer();//需异步处理 + +//从本地加载群组列表 +List grouplist = EMClient.getInstance().groupManager().getAllGroups(); + +//获取公开群列表 +//pageSize为要取到的群组的数量,cursor用于告诉服务器从哪里开始取 +EMCursorResult result = EMClient.getInstance().groupManager().getPublicGroupsFromServer(pageSize, cursor);//需异步处理 +List groupsList = List returnGroups = result.getData(); +String cursor = result.getCursor(); +``` + +## 修改群组名称|描述 + +``` +//修改群名称 +EMClient.getInstance().groupManager().changeGroupName(groupId,changedGroupName);//需异步处理 + +//修改群描述 +EMClient.getInstance().groupManager().changeGroupDescription(groupId, description);//需异步处理 +``` + +## 群组信息 + +获取单个群组信息。getGroupFromServer(groupId)返回结果包含群组名称,群描述,群主,管理员列表,不包含群成员。 + +getGroupFromServer(String groupId, boolean fetchMembers),如果fetchMembers为true,取群组信息的时候也会获取群成员,最大数200人。 + +``` +//根据群组ID从本地获取群组基本信息 +EMGroup group = EMClient.getInstance().groupManager().getGroup(groupId); +//根据群组ID从服务器获取群组基本信息 +EMGroup group = EMClient.getInstance().groupManager().getGroupFromServer(groupId); + +group.getOwner();//获取群主 +List members = group.getMembers();//获取内存中的群成员 +List adminList = group.getAdminList();//获取管理员列表 +boolean isMsgBlocked = group.isMsgBlocked();//获取是否已屏蔽群组消息 +... +``` + +其它方法详见[环信接口文档](http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_group_manager.html)。 + +## 屏蔽群消息 + +``` +/** +* 屏蔽群消息后,就不能接收到此群的消息(还是群里面的成员,但不再接收消息) +* @param groupId, 群ID +* @throws EasemobException +*/ +EMClient.getInstance().groupManager().blockGroupMessage(groupId);//需异步处理 +``` + +## 解除屏蔽群 + +``` +/** +* 取消屏蔽群消息,就可以正常收到群的所有消息 +* @param groupId +* @throws EaseMobException +*/ +EMClient.getInstance().groupManager().unblockGroupMessage(groupId);//需异步处理 +``` + +## 群组黑名单 + +### 将群成员拉入群组的黑名单 + +``` +/** +* 将用户加到群组的黑名单,被加入黑名单的用户无法加入群,无法收发此群的消息 +* (只有群主才能设置群的黑名单) +* @param groupId, 群组的ID +* @param username, 待屏蔽的用户名 +* @exception EaseMobException 出错会抛出 +*/ +EMClient.getInstance().groupManager().blockUser(groupId, username);//需异步处理 +``` + +### 将用户移除出群黑名单 + +``` +/** +* 将用户从群组的黑名单移除(只有群主才能调用此函数) +* @param groupId, 群组的ID +* @param username, 待解除屏蔽的用户名 +*/ +EMClient.getInstance().groupManager().unblockUser(groupId, username);//需异步处理 +``` + +### 获取群组的黑名单用户列表 + +``` +/** +* 获取群组的黑名单用户列表 +* (只有群主才能调用此函数) +* @return List +* @throws EaseMobException 获取失败 +*/ +EMClient.getInstance().groupManager().getBlockedUsers(groupId);//需异步处理 +``` + +## 群组禁言操作 + +### 将群成员加入禁言列表中 + +``` +/** + * 禁止某些群组成员发言, 需要群组拥有者或者管理员权限 + * @param groupId + * @param muteMembers 禁言的用户列表 + * @param duration 禁言的时间,单位是毫秒 + * @return + * @throws HyphenateException + */ +EMClient.getInstance().groupManager().muteGroupMembers(String groupId, List muteMembers, long duration);//需异步处理 +``` + +### 将群成员移出禁言列表 + +``` +/** + * 解除禁言, 需要群组拥有者或者管理员权限 + * @param groupId + * @param members + * @return + * @throws HyphenateException + */ + +EMClient.getInstance().groupManager().unMuteGroupMembers(String groupId, List members);//需异步处理 +``` + +### 获取群成员禁言列表 + +``` +/** + * 获取群组的禁言列表,需要群组拥有者或者管理员权限 + * @param groupId + * @param pageNum + * @param pageSize + * @return Map.entry.key 是禁言的成员id,Map.entry.value是禁言动作存在的时间,单位是毫秒。 + * @throws HyphenateException + */ +EMClient.getInstance().groupManager().fetchGroupMuteList(String groupId, int pageNum, int pageSize) +``` + +### 开启和关闭全员禁言 + +owner和管理员可以开启和关闭全员禁言。 + +``` +/** + * \~chinese + * 禁言所有成员 + * @param groupId 群组id + */ + public void muteAllMembers(final String groupId, final EMValueCallBack callBack) + + /** + * \~chinese + * 解除所有成员禁言 + * @param groupId 群组id + */ + public void unmuteAllMembers(final String groupId, final EMValueCallBack callBack) +``` + +### 白名单管理 + +可以将用户添加到白名单中,用户白名单在管理员开启了全员禁言时生效,可以运行白名单用户发出消息。 另外可以将用户移出白名单,检查自己是否在白名单中以及获取白名单列表。 + +``` +/** + * \~chinese + * 添加用户到白名单 + * @param groupId 群组id + * @param members 成员id列表 + */ + public void addToGroupWhiteList(final String groupId, final List members, final EMCallBack callBack) + + /** + * \~chinese + * 将用户从白名单移除 + * @param groupId 群组id + * @param members 成员id列表 + */ + public void removeFromGroupWhiteList(final String groupId, final List members, final EMCallBack callBack) + + /** + * \~chinese + * 检查自己是否在白名单中 + * @param groupId 群组id + */ + public void checkIfInGroupWhiteList(final String groupId, EMValueCallBack callBack) + + /** + * \~chinese + * 从服务器获取白名单成员列表 + * @param groupId 群组id + */ + public void fetchGroupWhiteList(final String groupId, final EMValueCallBack> callBack) +``` + +## 设置/更新群公告 + +``` +/** + * 更新群公告 + * @param groupId 群id + * @param announcement 公告内容 + * @throws HyphenateException + */ +EMClient.getInstance().groupManager().updateGroupAnnouncement(groupId, announcement); +``` + +## 获取群公告 + +``` +EMClient.getInstance().groupManager().fetchGroupAnnouncement(groupId) +``` + +## 上传共享文件 + +``` +/** + * 上传共享文件至群组,注意callback只做进度回调用 + * @param groupId 群id + * @param filePath 文件本地路径 + * @param callBack 回调 + */ +EMClient.getInstance().groupManager().uploadGroupSharedFile(groupId, filePath, callBack) +``` + +## 删除群共享文件 + +``` +/** + * 从群组里删除这个共享文件 + * @param groupId 群id + * @param fileId 文件id + */ +EMClient.getInstance().groupManager().deleteGroupSharedFile(groupId, fileId); +``` + +## 获取群共享文件列表 + +``` +/** + * 从服务器获取群组的共享文件列表 + * @param groupId 群id + * @param pageNum 分页号 + * @param pageSize 分页大小 + * + */ +EMClient.getInstance().groupManager().fetchGroupSharedFileList(groupId, pageNum, pageSize) +``` + +## 下载群共享文件 + +``` +/** + * 下载群里的某个共享文件,注意callback只做进度回调用 + * @param groupId 群id + * @param fileId 文件id + * @param savePath 文件保存路径 + * @param callBack 回调 + */ +EMClient.getInstance().groupManager().downloadGroupSharedFile(groupId, fileId, savePath, callBack); +``` + +## 更新群扩展字段 + +``` +EMClient.getInstance().groupManager().updateGroupExtension(groupId, extension); +``` + +## 群组事件监听 + +``` +EMClient.getInstance().groupManager().addGroupChangeListener(new EMGroupChangeListener() { +@Override + public void onInvitationReceived(String groupId, String groupName, String inviter, String reason) { + //接收到群组加入邀请 + } + + @Override + public void onRequestToJoinReceived(String groupId, String groupName, String applyer, String reason) { + //用户申请加入群 + } + + @Override + public void onRequestToJoinAccepted(String groupId, String groupName, String accepter) { + //加群申请被同意 + } + + @Override + public void onRequestToJoinDeclined(String groupId, String groupName, String decliner, String reason) { + //加群申请被拒绝 + } + + @Override + public void onInvitationAccepted(String groupId, String inviter, String reason) { + //群组邀请被同意 + } + + @Override + public void onInvitationDeclined(String groupId, String invitee, String reason) { + //群组邀请被拒绝 + } + + @Override + public void onAutoAcceptInvitationFromGroup(String groupId, String inviter, String inviteMessage) { + //接收邀请时自动加入到群组的通知 + } + + @Override + public void onMuteListAdded(String groupId, final List mutes, final long muteExpire) { + //成员禁言的通知 + } + + @Override + public void onMuteListRemoved(String groupId, final List mutes) { + //成员从禁言列表里移除通知 + } + + @Override + public void onWhiteListAdded(String groupId, List whitelist) { + //成员被加到白名单中 + } + + @Override + public void onWhiteListRemoved(String groupId, List whitelist) { + //成员从白名单中被移除 + } + + @Override + public void onAllMemberMuteStateChanged(String groupId, boolean isMuted) { + //全员禁言是否开启 + } + + @Override + public void onAdminAdded(String groupId, String administrator) { + //增加管理员的通知 + } + + @Override + public void onAdminRemoved(String groupId, String administrator) { + //管理员移除的通知 + } + + @Override + public void onOwnerChanged(String groupId, String newOwner, String oldOwner) { + //群所有者变动通知 + } + @Override + public void onMemberJoined(final String groupId, final String member){ + //群组加入新成员通知 + } + @Override + public void onMemberExited(final String groupId, final String member) { + //群成员退出通知 + } + + @Override + public void onAnnouncementChanged(String groupId, String announcement) { + //群公告变动通知 + } + + @Override + public void onSharedFileAdded(String groupId, EMMucSharedFile sharedFile) { + //增加共享文件的通知 + } + + @Override + public void onSharedFileDeleted(String groupId, String fileId) { + //群共享文件删除通知 + } +}); +``` diff --git a/docs/document/v1/android/group_attributes.md b/docs/document/v1/android/group_attributes.md index ec13e6e4a..bd92af111 100644 --- a/docs/document/v1/android/group_attributes.md +++ b/docs/document/v1/android/group_attributes.md @@ -18,8 +18,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -- 了解群组和群成员的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 diff --git a/docs/document/v1/android/group_manage.md b/docs/document/v1/android/group_manage.md index 9e755fae8..514412c75 100644 --- a/docs/document/v1/android/group_manage.md +++ b/docs/document/v1/android/group_manage.md @@ -13,17 +13,16 @@ - 创建、解散群组 - 获取群组详情 - 获取群成员列表 -- 获取群组列表 - 屏蔽、解除屏蔽群消息 - 监听群组事件 + ## 前提条件 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -- 了解群组和群成员的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 @@ -170,7 +169,7 @@ do { memberList.addAll(group.getAdminList());//加上管理员 memberList.add(group.getOwner());//加上群主 ``` - + ### 屏蔽和解除屏蔽群消息 群成员可以屏蔽群消息和解除屏蔽群消息。 diff --git a/docs/document/v1/android/group_members.md b/docs/document/v1/android/group_members.md index c1bd623e5..e3e24119a 100644 --- a/docs/document/v1/android/group_members.md +++ b/docs/document/v1/android/group_members.md @@ -8,8 +8,8 @@ 环信即时通讯 IM Android SDK 提供 `EMGroupManager` 类和 `EMGroup` 类用于群组管理,支持你通过调用 API 在项目中实现如下功能: + - 加入、退出群组 -- 管理群成员的自定义属性 - 管理群主及群管理员 - 管理群组白名单 - 管理群组黑名单 @@ -19,10 +19,9 @@ 开始前,请确保满足以下条件: -- 完成 SDK 初始化,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html); +- 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 - 了解群成员角色,详见 [群组概述](group_overview.html); -- 了解群组和群成员的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 ## 实现方法 @@ -157,7 +156,7 @@ EMClient.getInstance().groupManager().leaveGroup(groupId); // 异步方法为 asyncRemoveUserFromGroup(String, String, EMCallBack)。 EMClient.getInstance().groupManager().removeUserFromGroup(groupId, username); ``` - + ### 管理群主和群管理员 #### 变更群主 diff --git a/docs/document/v1/android/group_overview.md b/docs/document/v1/android/group_overview.md index 5bf01cb7f..f67331936 100644 --- a/docs/document/v1/android/group_overview.md +++ b/docs/document/v1/android/group_overview.md @@ -20,7 +20,7 @@ | 功能
| 群组
| 聊天室 | | :----------- | :----------------------------------------------------------- | :----------------------------------------------------------- | | 使用场景 | 类似于 Signal,Skype 里的群聊,所有加入的用户拥有固定的关系。 | 类似 Twitch 的直播间,成员间没有固定关系,离开即退出。 | -| 创建方式 | 所有 app 用户都可以创建群组。 | 仅 [超级管理员](/document/server-side/chatroom.html#管理超级管理员) 有权限创建聊天室。 | +| 创建方式 | 所有 app 用户都可以创建群组。 | 仅 [超级管理员](/document/v1/server-side/chatroom.html#管理超级管理员) 有权限创建聊天室。 | | 类型 | 分为公开群和私有群,创建群组时可设置入群是否需获得群主和群管理员的同意,支持不同使用场景。 | 没有公开和私有之分,所有用户均可自由加入或退出。 | | 最大成员数 | 成员数支持取决于所选择的版本,最高版本支持 8,000 人。 | 成员数支持取决于所选择的版本,最高版本支持 10,000 人。如需提升该上限,请联系商务。 | | 离线推送消息 | 离线时,会收到推送消息。 | 离线时,不会收到推送消息;成员离线超过 2 分钟会自动退出聊天室。 | @@ -50,7 +50,7 @@ | 功能 | 描述 | | :----------------- | :----------------------------------------------------------- | -| 创建群组 | 群组分为公开群和私有群,可以对加群的方式进行设置。任何用户都可以创建群组。群组创建者为群组。群组数量和群成员数量根据套餐版本有所不同。详见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im)。 | +| 创建群组 | 群组分为公开群和私有群,可以对加群的方式进行设置。任何用户都可以创建群组。群组创建者为群组。 | | 解散群组 | 只有群主才能解散群组。群组一旦解散,所有本地群组数据都会被删除,所有群成员都被强制退出群。 | | 获取群成员列表 | 所有群组用户都可以从服务器获取群组成员的分页列表。成员按加入群组时的时间戳降序显示。 | | 获取群组列表 | 用户可以获取公开群列表和自己创建或加入的群组列表。 | @@ -80,4 +80,4 @@ ### 群组人数限制 -群成员的数量根据不同的套餐版本而不同,免费版 100 人/群,专业版 300 人/群, 旗舰版 3,000 人/群,尊享版 8,000 人/群。 +群成员的数量可按需设置,默认群成员数:2000人/群,可支持调整至8000人/群 diff --git a/docs/document/v1/android/message.md b/docs/document/v1/android/message.md new file mode 100644 index 000000000..260bdbfce --- /dev/null +++ b/docs/document/v1/android/message.md @@ -0,0 +1,695 @@ +# 消息管理 + +## 发送消息 + +发送文本、语音、图片、位置等消息(单聊/群聊通用)。 + +### 发送文本消息 + +``` +//创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此 +EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername); +//如果是群聊,设置chattype,默认是单聊 +if (chatType == CHATTYPE_GROUP) + message.setChatType(ChatType.GroupChat); +//发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 发送表情消息 + +发表情消息实质上是发文本消息。接收方收到文本消息后,首先查询文本消息是否是表情消息,如果是,则显示该文本消息为对应的表情图片。可以参考[emoji列表](https://unicode.org/emoji/charts/full-emoji-list.html)来做表情图片和对应的文本字符串的映射。也可以自行维护表情图片和文本字符串的映射。 + +``` +//创建一条表情消息。表情消息实质上是一个文字消息。emojiCode是表情图片对应的文本字符串,toChatUsername为对方用户或者群聊的id,后文皆是如此 +EMMessage message = EMMessage.createTxtSendMessage(emojiCode, toChatUsername); +//如果是群聊,设置chattype,默认是单聊 +if (chatType == CHATTYPE_GROUP) + message.setChatType(ChatType.GroupChat); +//发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 发送语音消息 + +``` +//voiceUri 为语音文件本地资源标志符,length 为录音时间(秒) +EMMessage message = EMMessage.createVoiceSendMessage(voiceUri, length, toChatUsername); +//如果是群聊,设置 chattype,默认是单聊 +if (chatType == CHATTYPE_GROUP) + message.setChatType(ChatType.GroupChat); +EMClient.getInstance().chatManager().sendMessage(message); +``` + +发送成功后,获取语音消息附件: + +``` +EMVoiceMessageBody voiceBody = (EMVoiceMessageBody) msg.getBody(); +//获取语音文件在服务器的地址 +String voiceRemoteUrl = voiceBody.getRemoteUrl(); +//本地语音文件的资源路径 +Uri voiceLocalUri = voiceBody.getLocalUri(); +适配 AndroidQ 及以上手机时,获取本地资源请调用 voiceBody.getLocalUri(),相应的 voiceBody.getLocalUrl() 方法已经被废弃! +``` + +### 发送视频消息 + +``` +//videoLocalUri 为视频本地资源标志符,thumbLocalUri 为视频预览图路径,videoLength 为视频时间长度 +EMMessage message = EMMessage.createVideoSendMessage(videoLocalUri, thumbLocalUri, videoLength, toChatUsername); +//如果是群聊,设置 chattype,默认是单聊 +if (chatType == CHATTYPE_GROUP) + message.setChatType(ChatType.GroupChat); +EMClient.getInstance().chatManager().sendMessage(message); +``` + +发送成功后,获取视频消息缩略图及附件 + +``` +EMVideoMessageBody videoBody = (EMVideoMessageBody) message.getBody(); +//获取视频文件在服务器的路径 +String videoRemoteUrl = videoBody.getRemoteUrl(); +//获取缩略图在服务器的路径 +String thumbnailUrl = videoBody.getThumbnailUrl(); +//本地视频文件的资源路径 +Uri videoLocalUri = videoBody.getLocalUri(); +//本地视频缩略图资源路径 +Uri localThumbUri = videoBody.getLocalThumbUri(); +适配 AndroidQ 及以上手机时,获取本地资源请调用 videoBody.getLocalUri(),相应的 videoBody.getLocalUrl() 方法已经被废弃! +``` + +### 发送图片消息 + +``` +//imageUri 为图片本地资源标志符,false 为不发送原图(默认超过 100k 的图片会压缩后发给对方),需要发送原图传 true +EMMessage.createImageSendMessage(imageUri, false, toChatUsername); +//如果是群聊,设置 chattype,默认是单聊 +if (chatType == CHATTYPE_GROUP) + message.setChatType(ChatType.GroupChat); +EMClient.getInstance().chatManager().sendMessage(message); +``` + +发送成功后,获取图片消息缩略图及附件 + +``` +EMImageMessageBody imgBody = (EMImageMessageBody) message.getBody(); +//获取图片文件在服务器的路径 +String imgRemoteUrl = imgBody.getRemoteUrl(); +//获取图片缩略图在服务器的路径 +String thumbnailUrl = imgBody.getThumbnailUrl(); +//本地图片文件的资源路径 +Uri imgLocalUri = imgBody.getLocalUri(); +//本地图片缩略图资源路径 +Uri thumbnailLocalUri = imgBody.thumbnailLocalUri(); +适配 AndroidQ 及以上手机时,获取本地资源请调用 imgBody.getLocalUri(),相应的 imgBody.getLocalUrl() 方法已经被废弃! +``` + +### 发送地理位置消息 + +``` +//latitude为纬度,longitude为经度,locationAddress为具体位置内容 +EMMessage message = EMMessage.createLocationSendMessage(latitude, longitude, locationAddress, toChatUsername); +//如果是群聊,设置chattype,默认是单聊 +if (chatType == CHATTYPE_GROUP) + message.setChatType(ChatType.GroupChat); +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 发送文件消息 + +``` +//fileLocalUri 为本地资源标志符 +EMMessage message = EMMessage.createFileSendMessage(fileLocalUri, toChatUsername); +// 如果是群聊,设置 chattype,默认是单聊 +if (chatType == CHATTYPE_GROUP) + message.setChatType(ChatType.GroupChat); +EMClient.getInstance().chatManager().sendMessage(message); +``` + +发送成功后,获取文件消息附件 + +``` +EMNormalFileMessageBody fileMessageBody = (EMNormalFileMessageBody) message.getBody(); +//获取文件在服务器的路径 +String fileRemoteUrl = fileMessageBody.getRemoteUrl(); +//本地文件的资源路径 +Uri fileLocalUri = fileMessageBody.getLocalUri(); +适配 AndroidQ 及以上手机时,获取本地资源请调用 fileMessageBody.getLocalUri(),相应的 fileMessageBody.getLocalUrl() 方法已经被废弃! +``` + +### 发送透传消息 + +透传消息能做什么:头像、昵称的更新等。可以把透传消息理解为一条指令,通过发送这条指令给对方,告诉对方要做的 action,收到消息可以自定义处理的一种消息。(透传消息不会存入本地数据库中,所以在 UI 上是不会显示的)。另以 “em_” 和 “easemob::” 开头的 action 为内部保留字段,注意不要使用。 + +``` +EMMessage cmdMsg = EMMessage.createSendMessage(EMMessage.Type.CMD); + +//支持单聊和群聊,默认单聊,如果是群聊添加下面这行 +cmdMsg.setChatType(ChatType.GroupChat) +String action="action1";//action可以自定义 +EMCmdMessageBody cmdBody = new EMCmdMessageBody(action); +String toUsername = "test1";//发送给某个人 +cmdMsg.setTo(toUsername); +cmdMsg.addBody(cmdBody); +EMClient.getInstance().chatManager().sendMessage(cmdMsg); +``` + +### 发送自定义类型消息 + +用户可以在以上几种消息之外,自己定义消息类型,方便用户的业务处理。 自定义消息类型支持用户自己设置一个消息的类型名称,这样用户可以添加多种自定义消息。 自定义消息的内容部分是key,value格式的,用户需要自己添加并解析该内容。 + +``` +EMMessage customMessage = EMMessage.createSendMessage(EMMessage.Type.CUSTOM); +// event为需要传递的自定义消息事件,比如礼物消息,可以设置event = "gift" +EMCustomMessageBody customBody = new EMCustomMessageBody(event); +// params类型为Map +customBody.setParams(params); +customMessage.addBody(customBody); +// to指另一方环信id(或者群组id,聊天室id) +customMessage.setTo(to); +// 如果是群聊,设置chattype,默认是单聊 +customMessage.setChatType(chatType); +EMClient.getInstance().chatManager().sendMessage(customMessage); + +``` + +### 设置群消息是否需要已读回执 + +当消息为群消息时,消息发送方(目前为管理员和群主)可以设置此消息是否需要已读回执,如需要,则设置 EMMessage 的方法 setIsNeedGroupAck() 为 YES,之后发送。 + +``` +public EMMessage createDingMessage(String to, String content) { + EMMessage message = EMMessage.createTxtSendMessage(content, to); + message.setIsNeedGroupAck(true); + return message; + } + + +``` + +### 发送群消息已读回执 + +``` +public void sendAckMessage(EMMessage message) { + if (!validateMessage(message)) { + return; + } + + if (message.isAcked()) { + return; + } + + // May a user login from multiple devices, so do not need to send the ack msg. + if (EMClient.getInstance().getCurrentUser().equalsIgnoreCase(message.getFrom())) { + return; + } + + try { + if (message.isNeedGroupAck() && !message.isUnread()) { + String to = message.conversationId(); // do not use getFrom() here + String msgId = message.getMsgId(); + EMClient.getInstance().chatManager().ackGroupMessageRead(to, msgId, ((EMTextMessageBody)message.getBody()).getMessage()); + message.setUnread(false); + EMLog.i(TAG, "Send the group ack cmd-type message."); + } + } catch (Exception e) { + EMLog.d(TAG, e.getMessage()); + } + } +``` + +当发送群已读回执后,消息发送方对应 EMMessage 的 groupAckCount 属性会有相应变化; + +### 群消息已读回调 + +群消息已读回调在消息监听类EMMessageListener中。 + +``` +/** + * \~chinese + * 接受到群组消息体的已读回执, 消息的接收方已经阅读此消息。 + */ + void onGroupMessageRead(List groupReadAcks) { + } +``` + +### 获取群消息已读回执详情 + +如果想实现群消息已读回执的列表显示,可以通过下列接口获取到已读回执的详情。 + +``` +/** + * \~chinese + * 从服务器获取群组消息回执详情 + * @param msgId 消息id + * @param pageSize 获取的页面大小 + * @param startAckId 已读回执的id,如果为空,从最新的回执向前开始获取 + * @return 返回消息列表和用于继续获取群消息回执的Cursor + */ + public void asyncFetchGroupReadAcks(final String msgId, final int pageSize, + final String startAckId, final EMValueCallBack> callBack) { + + } +``` + +### 发送扩展消息 + +当 SDK 提供的消息类型不满足需求时,开发者可以通过扩展自 SDK 提供的文本、语音、图片、位置等消息类型,从而生成自己需要的消息类型。 + +这里是扩展自文本消息,如果这个自定义的消息需要用到语音或者图片等,可以扩展自语音、图片消息,亦或是位置消息。 + +``` +EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername); + +// 增加自己特定的属性 +message.setAttribute("attribute1", "value"); +message.setAttribute("attribute2", true); +... +EMClient.getInstance().chatManager().sendMessage(message); + +//接收消息的时候获取到扩展属性 +//获取自定义的属性,第2个参数为没有此定义的属性时返回的默认值 +message.getStringAttribute("attribute1",null); +message.getBooleanAttribute("attribute2", false); +... +``` + +## 接收消息 + +通过注册消息监听来接收消息。 + +``` +EMMessageListener msgListener = new EMMessageListener() { + + @Override + public void onMessageReceived(List messages) { + //收到消息 + } + + @Override + public void onCmdMessageReceived(List messages) { + //收到透传消息 + } + + @Override + public void onMessageRead(List messages) { + //收到已读回执 + } + + @Override + public void onMessageDelivered(List message) { + //收到已送达回执 + } + @Override + public void onMessageRecalled(List messages) { + //消息被撤回 + } + + @Override + public void onMessageChanged(EMMessage message, Object change) { + //消息状态变动 + } +}; +EMClient.getInstance().chatManager().addMessageListener(msgListener); + +记得在不需要的时候移除listener,如在activity的onDestroy()时 +EMClient.getInstance().chatManager().removeMessageListener(msgListener); +``` + +## 下载缩略图及附件 + +### 下载缩略图 + +如果设置了自动下载,即EMClient.getInstance().getOptions().getAutodownloadThumbnail()为true,SDK接收到消息后会下载缩略图; +如果没有设置自动下载,需主动调用EMClient.getInstance().chatManager().downloadThumbnail(message)下载。 +下载完成后,调用相应消息body的thumbnailLocalUri()去获取缩略图路径。 +例如: + +``` +EMImageMessageBody imgBody = (EMImageMessageBody) message.getBody(); +//本地图片缩略图资源路径 +Uri thumbnailLocalUri = imgBody.thumbnailLocalUri(); +``` + +### 下载附件 + +下载附件的方法为:EMClient.getInstance().chatManager().downloadAttachment(message); +下载完成后,调用相应消息body的getLocalUri()去获取附件路径。 +例如: + +``` +EMImageMessageBody imgBody = (EMImageMessageBody) message.getBody(); +//本地图片文件的资源路径 +Uri imgLocalUri = imgBody.getLocalUri(); +``` + +## 监听消息状态 + +通过 message 设置消息的发送及接收状态。 **注意:** 需在sendMessage之前去设置此回调监听 + +``` +message.setMessageStatusCallback(new EMCallBack(){}); +``` + +## 获取聊天记录 + +``` +EMConversation conversation = EMClient.getInstance().chatManager().getConversation(username); +//获取此会话的所有消息 +List messages = conversation.getAllMessages(); +//SDK初始化每个会话加载的聊天记录为1条,可以去DB里获取更多 +//获取startMsgId之前的pagesize条消息,此方法获取的messages SDK会自动存入到此会话中,APP中无需再次把获取到的messages添加到会话中 +List messages = conversation.loadMoreMsgFromDB(startMsgId, pagesize); +``` + +## 获取会话未读消息数量 + +``` +EMConversation conversation = EMClient.getInstance().chatManager().getConversation(username); +conversation.getUnreadMsgCount(); +``` + +## 获取所有未读消息数量 + +``` +EMClient.getInstance().chatManager().getUnreadMessageCount(); +``` + +## 未读消息数清零 + +``` +EMConversation conversation = EMClient.getInstance().chatManager().getConversation(username); +//指定会话消息未读数清零 +conversation.markAllMessagesAsRead(); +//把一条消息置为已读 +conversation.markMessageAsRead(messageId); +//所有未读消息数清零 +EMClient.getInstance().chatManager().markAllConversationsAsRead(); +``` + +## 获取会话消息总数 + +``` +EMConversation conversation = EMClient.getInstance().chatManager().getConversation(username); +//获取此会话在本地的所有的消息数量 +conversation.getAllMsgCount(); +//如果只是获取当前在内存的消息数量,调用 +conversation.getAllMessages().size(); +``` + +## 消息漫游 + +环信sdk 在3.3.4版本增加了一个消息漫游接口,即可以从服务器拉取历史消息到本地,方便用户切换设备同步消息。 + +此方法属于`EMChatManager` 类,通过`EMClient.getInstance().chatManager()`调用,使用方法参考 Demo 中 `EaseChatFragment` 类的 `loadMoreRoamingMessages()` 方法 + +``` +/** + * 从服务器获取历史消息 + * + * @param conversationId 会话名称 + * @param type 会话类型 + * @param pageSize 获取的页面大小(一次最多50条) + * @param startMsgId 漫游消息的开始消息id,如果为空,从最新的消息向前开始获取 + * @return 返回消息列表和用于继续获取历史消息的Cursor + */ + public EMCursorResult fetchHistoryMessages(String conversationId, EMConversationType type, int pageSize,String startMsgId); + + /** + * 从服务器获取历史消息 + * + * @param conversationId 会话名称 + * @param type 会话类型 + * @param pageSize 获取的页面大小 + * @param startMsgId 漫游消息的开始消息id,如果为空,从最新的消息向前开始获取 + * @param callBack 返回消息列表和用于继续获取历史消息的Cursor + */ + public void asyncFetchHistoryMessage(String conversationId, EMConversationType type, int pageSize, String startMsgId, EMValueCallBack> callBack) +``` + +## 从服务器获取会话列表 + +该功能开通后默认用户可以拉取 7 天内的 10 个会话和每个会话中最新一条聊天记录,如需调整会话数量请联系环信商务经理。 + + +建议此 API 在首次安装应用时或者本地没有会话的时候调用,其他时候使用本地的会话 API 即可。 + +``` +EMClient.getInstance().chatManager().asyncFetchConversationsFromServer(new EMValueCallBack>() { + @Override + public void onSuccess(Map value) { + // 获取会话成功后的处理逻辑 + } + @Override + public void onError(int error, String errorMsg) { + // 获取会话失败处理逻辑 + } +}); +``` + +## 撤回消息功能 + +消息撤回功能可以撤回一定时间内发送出去的消息,消息撤回时限默认2分钟,可根据开发者需求以AppKey为单位进行单独设置。 + + +``` +EMClient.getInstance().chatManager().recallMessage(contextMenuMessage); +``` + +## 消息已读回执 + +消息已读回执功能目前仅适用于单聊(ChatType.Chat),推荐使用方案为会话已读回执(conversation ack)+单条消息已读回执(read ack)结合实现,可减少发送read ack消息量。 + +### 发送已读回执消息 + +推荐进入会话首先发送会话已读回执(conversation ack)。 + +``` +try { + EMClient.getInstance().chatManager().ackConversationRead(conversationId); +} catch (HyphenateException e) { + e.printStackTrace(); +} +``` + +在会话页面,可以在接收到消息时,根据消息类型发送消息已读回执(read ack),如下所示 + +``` +EMClient.getInstance().chatManager().addMessageListener(new EMMessageListener() { + ...... + + @Override + public void onMessageReceived(List messages) { + ...... + sendReadAck(message); + ...... + } + + ...... +}); + +/** +* 发送已读回执 +* @param message +*/ +public void sendReadAck(EMMessage message) { + //是接收的消息,未发送过read ack消息且是单聊 + if(message.direct() == EMMessage.Direct.RECEIVE + && !message.isAcked() + && message.getChatType() == EMMessage.ChatType.Chat) { + EMMessage.Type type = message.getType(); + //视频,语音及文件需要点击后再发送,这个可以根据需求进行调整 + if(type == EMMessage.Type.VIDEO || type == EMMessage.Type.VOICE || type == EMMessage.Type.FILE) { + return; + } + try { + EMClient.getInstance().chatManager().ackMessageRead(message.getFrom(), message.getMsgId()); + } catch (HyphenateException e) { + e.printStackTrace(); + } + } +} +``` + +### 监听已读回执回调 + +(1)设置会话已读回执的监听 + +``` +EMClient.getInstance().chatManager().addConversationListener(new EMConversationListener() { + ...... + + @Override + public void onConversationRead(String from, String to) { + //添加刷新页面通知等逻辑 + } +}); +``` + +接收到会话已读回执(channel ack)回调后,SDK会在内部将会话相关消息置为对方已读,开发者需要在接收到此回调后,进行页面刷新等操作。 + +(2)设置消息已读回执的监听 + +``` +EMClient.getInstance().chatManager().addMessageListener(new EMMessageListener() { + ...... + + @Override + public void onMessageRead(List messages) { + //添加刷新消息等逻辑 + } + + ...... +}); +``` + +接收到read ack回调后,SDK会在内部将消息置为对方已读,开发者需要在接收到此回调后,进行消息刷新等操作。 + +**注:判断是否对方已读根据消息的`isAcked()`方法进行判断,返回true为对方已读,开发者可以根据此字段进行UI界面的展示及刷新。** + +## 会话已读回执 + +会话已读回执用于需要获知接收方是否阅读消息的场景,目前仅适用于单聊(ChatType.Chat)。 + + +### 发送已读回执消息 + +推荐进入会话页面,根据会话是否有未读消息,发送会话已读回执(conversation ack),有则发送,没有则不再发送。 + +``` +try { + EMClient.getInstance().chatManager().ackConversationRead(conversationId); +} catch (HyphenateException e) { + e.printStackTrace(); +} +``` + +注:该方法为异步方法,需要捕捉异常。 + +### 监听已读回执回调 + +``` +EMClient.getInstance().addConversationListener(new EMConversationListener() { + …… + + @Override + public void onConversationRead(String from, String to) { + //添加刷新页面通知等逻辑 + } +}); +``` + +注:onConversationRead中的from和to与消息(EMMessage)中的定义相同。 + +会回调onConversationRead的场景: +(1)消息被接收方阅读,且发送了已读回执(conversation ack); +(2)多端多设备登录场景下,一端发送会话已读回执(conversation ack),服务器端会将未读消息数置为0,同时其他端会回调此方法; + +### 最佳实践 + +推荐使用方案为会话已读回执(conversation ack)+[单条消息已读回执(read ack)](message#消息已读回执)结合实现,可减少发送read ack消息量。 +(1)未启动聊天页面的情况下,有未读消息,点击进入聊天页面,调用会话已读回执(conversation ack); +(2)已经启动聊天页面内的情况下,接收到消息,即发送单条消息已读回执 (read ack) ,具体实现可参考:[发送 read ack 消息](message#发送已读回执消息)。 + +## 分页获取历史消息记录 + +``` +try { + EMClient.getInstance().chatManager().fetchHistoryMessages( + toChatUsername, EaseCommonUtils.getConversationType(chatType), pagesize, ""); + final List msgs = conversation.getAllMessages(); + int msgCount = msgs != null ? msgs.size() : 0; + if (msgCount < conversation.getAllMsgCount() && msgCount < pagesize) { + String msgId = null; + if (msgs != null && msgs.size() > 0) { + msgId = msgs.get(0).getMsgId(); + } + conversation.loadMoreMsgFromDB(msgId, pagesize - msgCount); + } + messageList.refreshSelectLast(); +} catch (HyphenateException e) { + e.printStackTrace(); +} +``` + +## 获取本地所有会话 + +``` +Map conversations = EMClient.getInstance().chatManager().getAllConversations(); +``` + +如果出现偶尔返回的conversations的sizi为0,那很有可能是没有调用`EMClient.getInstance().chatManager().loadAllConversations()`,或者调用顺序不对,具体用法请参考[登录](overview.html#登录)章节。 + +## 从服务器获取会话列表 + + +该功能开通后,用户默认可拉取 7 天内的 10 个会话(每个会话包含最新一条历史消息),如需调整会话数量请联系环信商务经理。 + + +建议此 API 在首次安装应用时或者本地没有会话的时候调用,其他时候使用本地的会话 API 即可。 + + +``` +EMClient.getInstance().chatManager().asyncFetchConversationsFromServer(new EMValueCallBack>() { + @Override + public void onSuccess(Map value) { + // 获取会话成功后的处理逻辑 + } + @Override + public void onError(int error, String errorMsg) { + // 获取会话失败处理逻辑 + } +}); +``` + +## 删除会话及聊天记录 + +``` +//删除和某个user会话,如果需要保留聊天记录,传false +EMClient.getInstance().chatManager().deleteConversation(username, true); +//删除当前会话的某条聊天记录 +EMConversation conversation = EMClient.getInstance().chatManager().getConversation(username); +conversation.removeMessage(deleteMsg.msgId); +``` + +## 根据关键字搜索会话消息 + +``` +List messages = conversation.searchMsgFromDB(keywords, timeStamp, maxCount, from, EMConversation.EMSearchDirection.UP); +``` + +## 导入消息到数据库 + +如果有从2.x SDK或者其他第三方SDK升级到目前3.x SDK的需要,可以使用下面的接口,构造EMMessage 对象,将历史消息导入到本地数据库中。 + +``` +EMClient.getInstance().chatManager().importMessages(msgs); +``` + +## 插入消息 + +``` +//根据会话插入消息 +EMConversation conversation = EMClient.getInstance().chatManager().getConversation(username); +conversation.insertMessage(message); + +//直接插入消息 +EMClient.getInstance().chatManager().saveMessage(message); +``` + +## 更新消息到 SDK 本地数据库 + +``` +/** + * 更新消息到 SDK 本地数据库。 + * 消息更新后,会话的 latestMessage 等属性进行相应更新,不能更新消息 ID。 + * + * @param msg 要更新的消息。 + */ + public boolean updateMessage(EMMessage msg) +``` + + +## Demo 及 SDK 下载 + +[下载Demo及SDK](https://download-sdk.oss-cn-beijing.aliyuncs.com/mp/downloads/easemob-sdk-3.7.6.3.zip) diff --git a/docs/document/v1/android/message_manage.md b/docs/document/v1/android/message_manage.md index aa756a7d7..78440954a 100644 --- a/docs/document/v1/android/message_manage.md +++ b/docs/document/v1/android/message_manage.md @@ -9,8 +9,8 @@ ## 技术原理 环信即时通讯 IM Android SDK 支持管理用户设备上存储的消息会话数据,其中包含如下主要方法: - -- `EMChatManager.getAllConversationsBySort` 获取本地所有会话; + - `EMConversation.getAllMessages` 从数据库中读取指定会话的消息; - `EMConversation.getUnreadMsgCount` 获取指定会话的未读消息数; - `EMChatManager.getUnreadMessageCount` 获取所有会话的未读消息数; @@ -24,19 +24,21 @@ - `EMChatManager.importMessages` 批量导入消息到数据库; - `EMChatManager.insertMessage` 在指定会话中插入消息; - `EMConversation.updateMessage` 更新消息到本地数据库; + ## 前提条件 开始前,请确保满足以下条件: -- 完成 SDK 初始化并连接到服务器,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 - + ### 获取指定会话的未读消息数 你可以调用接口获取特定会话的未读消息数,示例代码如下: @@ -197,7 +199,7 @@ EMClient.getInstance().chatManager().updateMessage(message); EMConversation conversation = EMClient.getInstance().chatManager().getConversation(conversationId); conversation.updateMessage(message); ``` - + \ No newline at end of file diff --git a/docs/document/v1/android/message_modify.md b/docs/document/v1/android/message_modify.md index 73984ffa9..6a9ac5425 100644 --- a/docs/document/v1/android/message_modify.md +++ b/docs/document/v1/android/message_modify.md @@ -9,7 +9,7 @@ 若使用该功能,需将 SDK 升级至 4.1.0 或以上版本。 ::: -你可以调用 `com.hyphenate.chat.EMChatManager#asyncModifyMessage` 方法修改已经发送成功的消息。一条消息默认最多可修改 10 次,若要提升修改次数,需联系商务。 +你可以调用 `com.hyphenate.chat.EMChatManager#asyncModifyMessage` 方法修改已经发送成功的消息。一条消息默认最多可修改 10 次。 示例代码如下: diff --git a/docs/document/v1/android/message_overview.md b/docs/document/v1/android/message_overview.md index b6672c58d..7fe9817fd 100644 --- a/docs/document/v1/android/message_overview.md +++ b/docs/document/v1/android/message_overview.md @@ -59,7 +59,7 @@ Web 和小程序端无本地消息存储。 环信即时通讯 IM 在消息服务器保存历史消息,方便用户在新设备上获取历史消息。 -历史消息存储时间与套餐版本相关:专业版 7 天,旗舰版 90 天, 尊享版 180 天。 +私有部署历史消息存储时间支持自定义,请在部署服务前约定存储时间。 | 功能 | 描述 | 适用的平台/框架| | :---------- | :----------- |:----------------------------------- | @@ -81,7 +81,7 @@ Web 和小程序端无本地消息存储。 #### 消息重发机制 -- 对于 Android、iOS 、Windows 端和三个跨平台框架 Unity、React Native 和 Flutter 来说,消息重发机制如下: +- 对于 Android、iOS 来说,消息重发机制如下: 客户端调用发送消息的方法后,会等待服务器返回响应,超时时间为 10 秒。若因响应超时导致发送失败,客户端会再次尝试发送消息,即通过长连接重连服务器,然后发送消息。如果再次失败,SDK 认为消息发送失败,返回服务器不可达的错误消息,即错误码 300,Android 为 `EMErrorServerNotReachable`,iOS 和 Windows 为 `SERVER_NOT_REACHABLE`。 diff --git a/docs/document/v1/android/message_receipt.md b/docs/document/v1/android/message_receipt.md index 56038fd77..520ba615e 100644 --- a/docs/document/v1/android/message_receipt.md +++ b/docs/document/v1/android/message_receipt.md @@ -4,7 +4,7 @@ 单聊会话支持消息送达回执、会话已读回执和消息已读回执,发送方发送消息后可及时了解接收方是否及时收到并阅读了信息,也可以了解整个会话是否已读。 -群聊会话只支持消息已读回执。群主和群管理员在发送消息时,可以设置该消息是否需要已读回执。仅旗舰版及以上版本支持群消息已读回执功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +群聊会话只支持消息已读回执。群主和群管理员在发送消息时,可以设置该消息是否需要已读回执,私有部署即时通讯服务默认支持并开通该功能。 本文介绍如何使用环信即时通讯 IM Android SDK 实现单聊和群聊的消息回执功能。 @@ -39,9 +39,9 @@ 开始前,请确保满足以下条件: -- 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -- 群消息已读回执功能仅在环信 IM 旗舰版及以上版本支持该功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +- 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 + ## 实现方法 @@ -200,7 +200,7 @@ EMClient.getInstance().chatManager().addMessageListener(new EMMessageListener() 对于群聊,群主和群管理员发送消息时,可以设置该消息是否需要已读回执。若需要,每个群成员在阅读消息后,SDK 均会发送已读回执,即阅读该消息的群成员数量即为已读回执的数量。 -仅旗舰版及以上版本支持群消息已读回执功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +私有部署即时通讯服务默认支持并开通群消息已读回执功能。 1. 群主或群管理员发送消息时若需已读回执,需设置 `EMMessage` 的方法 `setIsNeedGroupAck()` 为 `YES`。 diff --git a/docs/document/v1/android/message_retrieve.md b/docs/document/v1/android/message_retrieve.md index e5ac77703..42b9e7789 100644 --- a/docs/document/v1/android/message_retrieve.md +++ b/docs/document/v1/android/message_retrieve.md @@ -4,30 +4,29 @@ 环信即时通讯 IM 提供消息漫游功能,即将用户的所有会话的历史消息保存在消息服务器,用户在任何一个终端设备上都能获取到历史信息,使用户在多个设备切换使用的情况下也能保持一致的会话场景。本文介绍用户如何获取和删除服务端的会话和消息。 -:::tip -本文介绍的功能均为增值服务,需在[环信即时通讯 IM 管理后台](https://console.easemob.com/user/login)开通。 -::: ## 技术原理 使用环信即时通讯 IM SDK 可以从服务器获取历史消息。 - + +- `asyncFetchHistoryMessage` 从服务端分页获取指定会话的历史消息; + ## 前提条件 开始前,请确保满足以下条件: -- 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 - + ### 分页获取指定会话的历史消息 对于单聊或群聊,用户发消息时,会自动将对方添加到用户的会话列表。 @@ -154,13 +153,14 @@ EMClient.getInstance().chatManager().asyncFetchHistoryMessage( } ); ``` - + \ No newline at end of file diff --git a/docs/document/v1/android/message_send_receive.md b/docs/document/v1/android/message_send_receive.md index 0b1551778..a1e955e21 100644 --- a/docs/document/v1/android/message_send_receive.md +++ b/docs/document/v1/android/message_send_receive.md @@ -9,9 +9,10 @@ - 位置消息。 - 透传消息。 - 自定义消息。 + 针对聊天室消息并发量较大的场景,即时通讯服务提供消息分级功能。你可以通过设置消息优先级,将消息划分为高、普通和低三种级别。你可以在创建消息时,将指定消息类型,或指定成员的所有消息设置为高优先级,确保此类消息优先送达。这种方式可以确保在聊天室内消息并发量较大或消息发送频率过高的情况下,服务器首先丢弃低优先级消息,将资源留给高优先级消息,确保重要消息(如打赏、公告等)优先送达,以此提升重要消息的可靠性。请注意,该功能并不保证高优先级消息必达。在聊天室内消息并发量过大的情况下,为保证用户实时互动的流畅性,即使是高优先级消息仍然会被丢弃。 本文介绍如何使用即时通讯 IM Android SDK 实现发送和接收这些类型的消息。 @@ -40,7 +41,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 @@ -117,7 +118,7 @@ EMClient.getInstance().chatManager().removeMessageListener(msgListener); ### 撤回消息 -发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在[环信即时通讯云控制台](https://console.easemob.com/user/login)的**功能配置** > **功能配置总览** > **基础功能** 页面设置消息撤回时长,该时长不超过 7 天。 +发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在 环信即时通讯云控制台的**服务管理** > **服务概览** 页面设置消息撤回时长,该时长不超过 7 天。 ```java try { @@ -568,6 +569,25 @@ customMessage.setChatType(chatType); EMClient.getInstance().chatManager().sendMessage(customMessage); ``` + +### 使用消息的扩展字段 + +当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型。 + +当目前消息类型不满足用户需求时,可以在扩展部分保存更多信息,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```java +EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername); +// 增加自定义属性。 +message.setAttribute("attribute1", "value"); +message.setAttribute("attribute2", true); +// 接收消息的时候获取扩展属性。 +EMClient.getInstance().chatManager().sendMessage(message); +// 获取自定义属性,第 2 个参数为没有此定义的属性时返回的默认值。 +message.getStringAttribute("attribute1",null); +message.getBooleanAttribute("attribute2", false) +``` + \ No newline at end of file diff --git a/docs/document/v1/android/moderation.md b/docs/document/v1/android/moderation.md index c9a7e1677..2fe5c143e 100644 --- a/docs/document/v1/android/moderation.md +++ b/docs/document/v1/android/moderation.md @@ -13,8 +13,8 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html)。 -- 已在 [环信即时通讯云控制台](https://console.easemob.com/user/login) 开通消息审核服务。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 已在 环信即时通讯云控制台开通消息审核服务。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 diff --git a/docs/document/v1/android/multi_device.md b/docs/document/v1/android/multi_device.md index 2aaa8e140..e67ca174d 100644 --- a/docs/document/v1/android/multi_device.md +++ b/docs/document/v1/android/multi_device.md @@ -11,7 +11,7 @@ 多端登录时,即时通讯 IM 每端默认最多支持 4 个设备同时在线。如需增加支持的设备数量,可以联系环信即时通讯 IM 的商务经理。 -你可以在环信控制台的**功能配置** > **功能配置总览**页面的**基础功能**页签下点击**多端多设备在线**操作栏中的**设置**,在弹出的对话框中设置设置各端设备的数量: +你可以在环信控制台的**服务管理** > **服务概览**页面的下点击**多端多设备在线**操作栏中的**设置**,在弹出的对话框中设置设置各端设备的数量: ![img](@static/images/common/multidevice_device_count.png) @@ -24,7 +24,7 @@ - +
@@ -37,8 +37,8 @@ - - + +
单端/多端登录设备支持自动登录时,若设备下线后自动重连时需要判断是否踢掉当前在线的最早登录设备,请联系环信商务。
多端登录若一端的登录设备数量达到了上限,最新登录的设备会将该端最早登录的设备踢下线。<br/>即时通讯 IM 仅支持同端互踢,不支持各端之间互踢。多端登录若一端的登录设备数量达到了上限,最新登录的设备会将该端最早登录的设备踢下线。即时通讯 IM 仅支持同端互踢,不支持各端之间互踢。
@@ -51,11 +51,13 @@ Android SDK 初始化时会生成登录 ID 用于在多设备登录和消息推 - 获取当前用户的其他已登录设备的登录 ID 列表; - 获取指定账号的在线登录设备列表; -- 设置登录设备的名称; -- 设置登录设备的平台; - 强制指定账号从单个设备下线; - 强制指定账号从所有设备下线; - 获取其他设备的好友或者群组操作。 + + ## 前提条件 @@ -82,7 +84,7 @@ EMClient.getInstance().chatManager().sendMessage(message); ### 获取指定账号的在线登录设备列表 -你可以调用 `getLoggedInDevicesFromServer` 或 `getLoggedInDevicesFromServerWithToken` 方法通过传入用户 ID 和登录密码或用户 token 从服务器获取指定账号的在线登录设备的列表。调用该方法后,在 SDK 返回的信息中,`EMDeviceInfo` 中的 `mDeviceName` 属性表示自定义设备名称,若未自定义设备名称,返回设备型号。 +你可以调用 `getLoggedInDevicesFromServer` 方法通过传入用户 ID 和登录密码从服务器获取指定账号的在线登录设备的列表。调用该方法后,在 SDK 返回的信息中,`EMDeviceInfo` 中的 `mDeviceName` 属性表示自定义设备名称,若未自定义设备名称,返回设备型号。 ```java try { @@ -91,13 +93,8 @@ EMClient.getInstance().chatManager().sendMessage(message); e.printStackTrace(); } - try { - List deviceInfos = EMClient.getInstance().getLoggedInDevicesFromServerWithToken("username","token"); - } catch (HyphenateException e) { - e.printStackTrace(); - } ``` - + ### 强制指定账号从单个设备下线 -你可以调用 `kickDevice` 或 `kickDeviceWithToken` 方法通过传入用户 ID 和登录密码或用户 token 将指定账号从单个登录设备踢下线。调用这两种方法前,你需要首先通过 `EMClient#getLoggedInDevicesFromServer` 和 `EMDeviceInfo#getResource` 方法获取设备 ID。 +你可以调用 `kickDevice` 方法通过传入用户 ID 和登录密码将指定账号从单个登录设备踢下线。调用这两种方法前,你需要首先通过 `EMClient#getLoggedInDevicesFromServer` 和 `EMDeviceInfo#getResource` 方法获取设备 ID。 :::notice 不登录也可以使用该接口。 @@ -168,12 +165,12 @@ EMClient.getInstance().chatManager().sendMessage(message); List deviceInfos = EMClient.getInstance().getLoggedInDevicesFromServer(username, password); // username:账户名称,password:账户密码, resource:设备 ID。需要在异步线程中执行。 EMClient.getInstance().kickDevice(username, password, deviceInfos.get(selectedIndex).getResource()); -//EMClient.getInstance().kickDeviceWithToken(username, token, deviceInfos.get(selectedIndex).getResource()); + ``` ### 强制指定账号从所有设备下线 -你可以调用 `kickAllDevices` 或 `kickAllDevicesWithToken` 方法通过传入用户 ID 和登录密码或用户 token 将指定账号从所有登录设备踢下线。 +你可以调用 `kickAllDevices` 方法通过传入用户 ID 和登录密码将指定账号从所有登录设备踢下线。 :::notice 不登录也可以使用该接口。 @@ -186,11 +183,6 @@ EMClient.getInstance().kickDevice(username, password, deviceInfos.get(selectedIn e.printStackTrace(); } - try { - EMClient.getInstance().kickAllDevicesWithToken("username","token"); - } catch (HyphenateException e) { - e.printStackTrace(); - } ``` ### 获取其他设备上的操作 diff --git a/docs/document/v1/android/multidevices.md b/docs/document/v1/android/multidevices.md new file mode 100644 index 000000000..8784a086a --- /dev/null +++ b/docs/document/v1/android/multidevices.md @@ -0,0 +1,190 @@ +# 多设备管理 + + +## 其他端登录的设备ID + +当PC端和手机端登录同一个账号时,在手机端可以通过特定方法获取到PC端的设备ID,该设备ID相当于特殊的好友Username,可以直接使用于聊天,使用方法与好友类似。 + +#### 接口 + +``` +class EMContactManager: + + /** + * 从服务器获取登录用户在其他设备上登录的ID + * + * @return 其它设备登陆的ID列表 + * @throws HyphenateException + */ + public List getSelfIdsOnOtherPlatform() throws HyphenateException + + /** + * 异步操作,从服务器获取登录用户在其他设备上登录的ID + * + * @param callback 包含用户在其他设备上登录的ID + */ + public void aysncGetSelfIdsOnOtherPlatform(final EMValueCallBack> callback); +``` + +#### 使用示例 + +``` +List selfIds = EMClient.getInstance().contactManager().getSelfIdsOnOtherPlatform(); +``` + +## 多设备事件回调 + +账号A同时在设备A和设备B上登录,账号A在设备A上进行一些操作,设备B上会收到这些操作对应的通知,具体说明如下: + +#### 接口 EMMultiDeviceListener + +``` +interface EMMultiDeviceListener { + /** + * 好友已经在其他设备上被移除 + */ + int CONTACT_REMOVE = 2; + + /** + * 好友请求已经在其他设备上被同意 + */ + int CONTACT_ACCEPT = 3; + + /** + * 好友请求已经在其他设备上被拒绝 + */ + int CONTACT_DECLINE = 4; + + /** + * 当前用户在其他设备加某人进入黑名单 + */ + int CONTACT_BAN = 5; + + /** + * 好友在其他设备被移出黑名单 + */ + int CONTACT_ALLOW = 6; + + + + /** + * 创建了群组 + */ + int GROUP_CREATE = 10; + + /** + * 销毁了群组 + */ + int GROUP_DESTROY = 11; + + /** + * 已经加入群组 + */ + int GROUP_JOIN = 12; + + /** + * 已经离开群组 + */ + int GROUP_LEAVE = 13; + + /** + * 发起群组申请 + */ + int GROUP_APPLY = 14; + + /** + * 同意群组申请 + */ + int GROUP_APPLY_ACCEPT = 15; + + /** + * 拒绝群组申请 + */ + int GROUP_APPLY_DECLINE = 16; + + /** + * 邀请群成员 + */ + int GROUP_INVITE = 17; // + + /** + * 同意群组邀请 + */ + int GROUP_INVITE_ACCEPT = 18; // + + /** + * 拒绝群组邀请 + */ + int GROUP_INVITE_DECLINE = 19; + + /** + * 将某人踢出群 + */ + int GROUP_KICK = 20; + + /** + * 加入群组黑名单 + */ + int GROUP_BAN = 21; //加入群组黑名单 + + /** + * 移除群组黑名单 + */ + int GROUP_ALLOW = 22; + + /** + * 屏蔽群组 + */ + int GROUP_BLOCK = 23; + + /** + * 取消群组屏蔽 + */ + int GROUP_UNBLOCK = 24; + + /** + * 转移群主 + */ + int GROUP_ASSIGN_OWNER = 25; + + /** + * 添加管理员 + */ + int GROUP_ADD_ADMIN = 26; + + /** + * 移除管理员 + */ + int GROUP_REMOVE_ADMIN = 27; + + /** + * 禁言用户 + */ + int GROUP_ADD_MUTE = 28; + + /** + * 移除禁言 + */ + int GROUP_REMOVE_MUTE = 29; + + /** + * 多设备联系人事件 + */ + void onContactEvent(int event, String target, String ext); + + /** + * 多设备群组事件 + */ + void onGroupEvent(int event, String target, List usernames); +} +``` + +#### 使用示例 + +``` +//注册监听 +EMClient.getInstance().addMultiDeviceListener(new MyMultiDeviceListener()); // class MyMultiDeviceListener implements EMMultiDeviceListener + +//撤销监听 +EMClient.getInstance().removeMultiDeviceListener(myMultiDeviceListener); +``` \ No newline at end of file diff --git a/docs/document/v1/android/nickname.md b/docs/document/v1/android/nickname.md new file mode 100644 index 000000000..81dbeceda --- /dev/null +++ b/docs/document/v1/android/nickname.md @@ -0,0 +1,17 @@ +# 设置当前登录用户的推送昵称 + + +**注意**:如果集成了 GCM 等第三方推送,昵称的设置也适用于此类推送消息。 + +当 Android 手机向 iPhone 手机发消息的时候,如果 iPhone 手机不在线,则需要通过苹果的 APNS 做消息推送,这时候如果不设置昵称,就会使用默认的环信 ID 作为用户名显示在 iPhone 手机上影响用户体验,推荐使用这里提到的方法设置昵称。 + +## 更新当前用户的在苹果 APNS 推送的昵称 + +此方法主要为了在苹果推送时能够显示用户昵称(`nickname`)而不是 `userid`,一般可以在登录成功后从自己服务器获取到个人信息,然后拿到用户个人信息的昵称更新到环信服务器。 + +**如果个人信息的昵称被更改,也要去环信服务器更新下 `nickname` 防止显示差异。** + +``` +//此方法传入一个字符串 String 类型的参数,返回成功或失败的一个 Boolean 类型的返回值 +EMClient.getInstance().updateCurrentUserNick(nickname); +``` \ No newline at end of file diff --git a/docs/document/v1/android/overview.md b/docs/document/v1/android/overview.md index a0e284094..b693aa576 100644 --- a/docs/document/v1/android/overview.md +++ b/docs/document/v1/android/overview.md @@ -1,225 +1,245 @@ # SDK 集成概述 - +## SDK 中相关异步/同步处理方法介绍 -介绍 Android 集成相关内容。 +- 同步方法:SDK 里大部分方法都为同步方法,即这个方法执行完毕,才会走后面的代码。 +- 异步方法:带有 callback 以及 API 注释里明确写明异步方法的方法,即不需要等这个方法走完,后边的代码就已经在执行了,通过 callback 得到方法执行的结果。 -## 前提条件 +## 取本地log -开始前,请注册有效的环信即时通讯 IM 开发者账号并取得 App key,见 [环信即时通讯云管理后台](https://console.easemob.com/user/login)。 +以Demo为例,获取本地的log -## 集成环境 - -详见 [开发环境要求](quickstart.html#前提条件)。 - -## 添加权限 - -1. 找到文件 `AndroidManifest.xml` -2. SDK 最少需要添加的权限如下: - -```xml - - - - - - +``` +adb pull /sdcard/Android/data/com.hyphenate.chatuidemo/easemob-demo#chatdemoui/core_log/easemob.log ``` -## SDK 初始化 - -初始化是使用 SDK 的必要步骤,需在所有接口方法调用前完成。 +其中com.hyphenate.chatuidemo是packagename, easemob-demo#chatdemoui是appkey,需要替换成自己对应的路径。 -如果进行多次初始化操作,只有第一次初始化以及相关的参数生效。 +## 初始化 SDK -初始化示例代码: +**要求在 application 的`oncreate`方法中做初始化**,初始化的时候需要传入设置好的 options。 -```java +``` EMOptions options = new EMOptions(); -options.setAppKey("Your appkey"); -......// 其他 EMOptions 配置。 -EMClient.getInstance().init(context, options); +// 默认添加好友时,是不需要验证的,改成需要验证 +options.setAcceptInvitationAlways(false); +// 是否自动将消息附件上传到环信服务器,默认为True是使用环信服务器上传下载,如果设为 false,需要开发者自己处理附件消息的上传和下载 +options.setAutoTransferMessageAttachments(true); +// 是否自动下载附件类消息的缩略图等,默认为 true 这里和上边这个参数相关联 +options.setAutoDownloadThumbnail(true); +... +//初始化 +EMClient.getInstance().init(applicationContext, options); +//在做打包混淆时,关闭debug模式,避免消耗不必要的资源 +EMClient.getInstance().setDebugMode(true); ``` -:::notice -需要在主进程中进行初始化。 -::: +注:如果你的 APP 中有第三方的服务启动,请在初始化 SDK(`EMClient.getInstance().init(applicationContext, options)`)方法的前面添加以下相关代码(相应代码也可参考 Demo 的 application),使用 EaseUI 库的就不用理会这个。 -## 注册用户 +``` +appContext = this; +int pid = android.os.Process.myPid(); +String processAppName = getAppName(pid); +// 如果APP启用了远程的service,此application:onCreate会被调用2次 +// 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次 +// 默认的APP会在以包名为默认的process name下运行,如果查到的process name不是APP的process name就立即返回 + +if (processAppName == null ||!processAppName.equalsIgnoreCase(appContext.getPackageName())) { + Log.e(TAG, "enter the service process!"); + + // 则此application::onCreate 是被service 调用的,直接返回 + return; +} +``` -可以使用如下代码创建账号: +如何获取`processAppName`请参考以下方法。 -```java -// 注册失败会抛出 HyphenateException。 -EMClient.getInstance().createAccount(mAccount, mPassword);// 同步方法。 +``` +private String getAppName(int pID) { + String processName = null; + ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE); + List l = am.getRunningAppProcesses(); + Iterator i = l.iterator(); + PackageManager pm = this.getPackageManager(); + while (i.hasNext()) { + ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next()); + try { + if (info.pid == pID) { + processName = info.processName; + return processName; + } + } catch (Exception e) { + // Log.d("Process", "Error>> :"+ e.toString()); + } + } + return processName; +} ``` -:::notice - -- 以上注册模式为在客户端注册,旨在方便测试,并不推荐在正式环境中使用; -- 正式环境应使用服务器端调用 REST API 接口[注册用户](/document/server-side/account_system.html#注册用户)。 - ::: +## 注册 -## 用户登录 +注册模式分两种,开放注册和授权注册。只有开放注册时,才可以客户端注册。 -目前登录服务器支持手动和自动登录。手动登录有两种方式: +- 开放注册是为了测试使用,正式环境中不推荐使用该方式注册环信账号; +- 授权注册的流程应该是您服务器通过环信提供的 REST API 注册,之后保存到您的服务器或返回给客户端。 -- 用户 ID + 密码 -- 用户 ID + token +注册用户名会自动转为小写字母,所以建议用户名均以小写注册。 -手动登录时传入的用户 ID 必须为 String 类型,支持的字符集详见[用户注册的 RESTful 接口](/document/server-side/account_system.html#注册用户)。 +``` +强烈建议开发者通过后台调用 REST 接口去注册环信 ID,客户端注册方法不建议使用。 +//注册失败会抛出HyphenateException +EMClient.getInstance().createAccount(username, pwd);//同步方法 +``` -调用登录接口后,收到 `onConnected` 回调表明 SDK 与环信服务器连接成功。 +## 登录 -### 手动登录 +**注意:** -**用户 ID + 密码** 登录是传统的登录方式。用户名和密码均由你的终端用户自行决定,密码需要符合密码规则要求。 +- 除了注册监听,其他的 SDK 操作均需在登陆之后才能进行。 -```java -EMClient.getInstance().login(mAccount, mPassword, new EMCallBack() { - // 登录成功回调 - @Override - public void onSuccess() { +- 登录成功后需要调用`EMClient.getInstance().chatManager().loadAllConversations();`和`EMClient.getInstance().groupManager().loadAllGroups();`。 - } +- 以上两个方法是为了保证进入主页面后本地会话和群组都 load 完毕。 - // 登录失败回调,包含错误信息 - @Override - public void onError(int code, String error) { - - } +- 另外如果之前登录过,APP 长期在后台再进的时候也可能会导致加载到内存的群组和会话为空,可以在主页面的 oncreate 里也加上这两句代码,当然,更好的办法应该是放在程序的开屏页,可参考 Demo 的 SplashActivity。 +``` +EMClient.getInstance().login(userName,password,new EMCallBack() {//回调 + @Override + public void onSuccess() { + EMClient.getInstance().groupManager().loadAllGroups(); + EMClient.getInstance().chatManager().loadAllConversations(); + Log.d("main", "登录聊天服务器成功!"); + } + + @Override + public void onProgress(int progress, String status) { + + } + + @Override + public void onError(int code, String message) { + Log.d("main", "登录聊天服务器失败!"); + } }); ``` -**用户 ID + token** 是更加安全的登录方式。token 可以通过调用 REST API 获取。详见 [环信用户 token 的获取](/document/server-side/easemob_user_token.html)。 - -:::notice -使用 token 登录时需要处理 token 过期的问题,比如在每次登录时更新 token 等机制。 -::: +## 使用token登录 -```java -EMClient.getInstance().loginWithToken(mAccount, mToken, new EMCallBack() { - // 登录成功回调 - @Override - public void onSuccess() { - - } +SDK也支持使用token登录,比如在app的服务器获取token,然后交给应用使用token登录。 - // 登录失败回调,包含错误信息 - @Override - public void onError(int code, String error) { +**`请注意: 使用token 登录时需要处理token过期的问题,比如在每次登录时更新token 等机制。`** - } -}); +``` +public void loginWithToken(String username, String token, final EMCallBack callback) ``` -登录重试机制如下: +## 自动登录 -- 登录时,若服务器返回明确的失败原因,例如,token 不正确,SDK 不会重试登录。 -- 若登录因超时失败,SDK 会重试登录。 +即首次登录成功后,不需要再次调用登录方法,在下次 APP 启动时,SDK 会自动为您登录。并且如果您自动登录失败,也可以读取到之前的会话信息(以上情况是在未调用登出的情况下实现的)。 -### 自动登录 +SDK 中自动登录属性默认是 true 打开的,如果不需要自动登录,在初始化 SDK 初始化的时候,调用`options.setAutoLogin(false);`设置为 false 关闭。 -初始化时可以设置是否自动登录。如果设置为自动登录,则登录成功之后,后续启动初始化的时候会自动登录。 +自动登录在以下几种情况下会被取消: -自动登录时,SDK 尝试连接服务器失败后,延时随机一段时间后自动重连。 +- 用户调用了 SDK 的登出动作; +- 用户在别的设备上更改了密码,导致此设备上自动登录失败; +- 用户的账号被从服务器端删除; +- 用户从另一个设备登录,把当前设备上登录的用户踢出。 ## 退出登录 -同步方法: +同步方法 -```java +``` EMClient.getInstance().logout(true); ``` -异步方法: +异步方法 -```java +``` EMClient.getInstance().logout(true, new EMCallBack() { - - @Override - public void onSuccess() { - - } - - @Override - public void onError(int code, String message) { - - } + + @Override + public void onSuccess() { + // TODO Auto-generated method stub + + } + + @Override + public void onProgress(int progress, String status) { + // TODO Auto-generated method stub + + } + + @Override + public void onError(int code, String message) { + // TODO Auto-generated method stub + + } }); ``` -## 连接状态相关 - -你可以通过注册连接监听确认连接状态。 - -```java -EMConnectionListener connectionListener = new EMConnectionListener() { - @Override - public void onConnected() { - - } - @Override - public void onDisconnected(int errorCode) { - - } - - @Override - public void onLogout(int errorCode) { - - } - - @Override - public void onTokenWillExpire() { - - } - - @Override - public void onTokenExpired() { - - } -}; -// 注册连接状态监听 -EMClient.getInstance().addConnectionListener(connectionListener); -// 移除连接状态监听 -EMClient.getInstance().removeConnectionListener(connectionListener); -``` - -### 断网自动重连 - -如果由于网络信号弱、切换网络等引起的连接终端,SDK 会自动尝试重连。重连成功或者失败的结果分别会收到通知 `onConnected` 和 `onDisconnected`。 +如果集成了FCM等第三方推送,方法里第一个参数需要设为`true`,这样退出的时候会解绑设备token,否则可能会出现退出了,还能收到消息的现象。 +有时候可能会碰到网络问题而解绑失败,app处理时可以弹出提示框让用户选择,是否继续退出(弹出框提示继续退出能收到消息的风险),如果用户选择继续退出,传`false`再调用logout方法退出成功; +当然也可以失败后还是返回退出成功,然后在后台起个线程不断调用logout方法直到成功,这样有个风险是:用户kill了app,然后网络恢复,用户还是会继续收到消息。 -### 被动退出登录 +还有一个需要注意的是:如果调用异步退出方法,在收到onsucess的回调后才去调用IM相关的方法,比如login -你可以通过监听回调 `EMConnectionListener#onLogout(int)` 后,调用 `EMClient#logout(boolean, EMCallBack)` 进行退出并返回登录界面。 +## 用户被封禁后的提示 -`EMConnectionListener#onLogout(int)` 返回的 `errorCode` 有如下: +在[IM管理后台](/document/v1/privatization/uc_configure.html#用户管理)可以对用户进行管理,例如可以在后台封禁用户。 用户被封禁后会提示SDK登录会返回 SERVER_SERVING_DISABLED(305), 可以根据用户这个返回值来进行相应的提示或者处理。 -- `USER_LOGIN_ANOTHER_DEVICE=206`: 用户已经在其他设备登录 -- `USER_REMOVED=207`: 用户账户已经被移除 -- `USER_BIND_ANOTHER_DEVICE=213`: 用户已经绑定其他设备 -- `USER_LOGIN_TOO_MANY_DEVICES=214`: 用户登录设备超出数量限制 -- `USER_KICKED_BY_CHANGE_PASSWORD=216`: 由于密码变更被踢下线 -- `USER_KICKED_BY_OTHER_DEVICE=217`: 由于其他设备登录被踢下线 -- `USER_DEVICE_CHANGED=220`: 和上次设备不同导致下线 -- `SERVER_SERVING_DISABLED=305`: 服务器服务停止 +需要注意的是app整个被禁用时也会返回上述错误码,由于app一般不会被禁用,所以可以用来提示用户被封禁。 -以上参数具体可以参考 [EMError](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html) 对应说明。 +## 注册连接状态监听 -## 输出信息到日志文件 +当掉线时,Android SDK 会自动重连,无需进行任何操作,通过注册连接监听来知道连接状态。 -开发者可以在开发阶段开启 `DEBUG` 模式,获取更多的调试信息。 +- 在聊天过程中难免会遇到网络问题,在此 SDK 为您提供了网络监听接口,实时监听 -```java -// 需要在 SDK 初始化后调用 -EMClient.getInstance().setDebugMode(true); -``` +- 可以根据 disconnect 返回的 error 判断原因。若服务器返回的参数值为`EMError.USER_LOGIN_ANOTHER_DEVICE`,则认为是有同一个账号异地登录;若服务器返回的参数值为`EMError.USER_REMOVED`,则是账号在后台被删除。 -### 获取本地日志 +- 被踢下线,被封禁等错误发生后,SDK不会尝试重新连接,之后需要调用`logout`退出登录,之后才能进行重新登录。 -```shell -adb pull /sdcard/android/data/{应用包名}/{App Key}/core_log/easemob.log ``` +//注册一个监听连接状态的listener +EMClient.getInstance().addConnectionListener(new MyConnectionListener()); -获取本地日志,需要将 `{应用包名}` 替换为应用的包名,例如 `com.hyphenate.chatuidemo`;`{App Key}` 需要替换为应用设置的环信 App Key。 +//实现ConnectionListener接口 +private class MyConnectionListener implements EMConnectionListener { + @Override + public void onConnected() { + } + @Override + public void onDisconnected(int error) { + EMLog.d("global listener", "onDisconnect" + error); + if (error == EMError.USER_REMOVED) { + onUserException(Constant.ACCOUNT_REMOVED); + } else if (error == EMError.USER_LOGIN_ANOTHER_DEVICE) { + onUserException(Constant.ACCOUNT_CONFLICT); + } else if (error == EMError.SERVER_SERVICE_RESTRICTED) { + onUserException(Constant.ACCOUNT_FORBIDDEN); + } else if (error == EMError.USER_KICKED_BY_CHANGE_PASSWORD) { + onUserException(Constant.ACCOUNT_KICKED_BY_CHANGE_PASSWORD); + } else if (error == EMError.USER_KICKED_BY_OTHER_DEVICE) { + onUserException(Constant.ACCOUNT_KICKED_BY_OTHER_DEVICE); + } + } +} + + + /** + * user met some exception: conflict, removed or forbidden, goto login activity + */ + protected void onUserException(String exception){ + EMLog.e(TAG, "onUserException: " + exception); + Intent intent = new Intent(appContext, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + intent.putExtra(exception, true); + appContext.startActivity(intent); + + showToast(exception); + } +``` \ No newline at end of file diff --git a/docs/document/v1/android/overview_v.md b/docs/document/v1/android/overview_v.md new file mode 100644 index 000000000..b4178aa99 --- /dev/null +++ b/docs/document/v1/android/overview_v.md @@ -0,0 +1,225 @@ +# SDK 集成概述 + + + +介绍 Android 集成相关内容。 + +## 前提条件 + +开始前,请注册有效的环信即时通讯 IM 开发者账号并取得 App key,见 [环信即时通讯云管理后台](/document/v1/privatization/uc_configure.html)。 + +## 集成环境 + +详见 [开发环境要求](quickstart.html#前提条件)。 + +## 添加权限 + +1. 找到文件 `AndroidManifest.xml` +2. SDK 最少需要添加的权限如下: + +```xml + + + + + + +``` + +## SDK 初始化 + +初始化是使用 SDK 的必要步骤,需在所有接口方法调用前完成。 + +如果进行多次初始化操作,只有第一次初始化以及相关的参数生效。 + +初始化示例代码: + +```java +EMOptions options = new EMOptions(); +options.setAppKey("Your appkey"); +......// 其他 EMOptions 配置。 +EMClient.getInstance().init(context, options); +``` + +:::notice +需要在主进程中进行初始化。 +::: + +## 注册用户 + +可以使用如下代码创建账号: + +```java +// 注册失败会抛出 HyphenateException。 +EMClient.getInstance().createAccount(mAccount, mPassword);// 同步方法。 +``` + +:::notice + +- 以上注册模式为在客户端注册,旨在方便测试,并不推荐在正式环境中使用; +- 正式环境应使用服务器端调用 REST API 接口[注册用户](/document/v1/server-side/account_system.html#注册用户)。 + ::: + +## 用户登录 + +目前登录服务器支持手动和自动登录。手动登录有两种方式: + +- 用户 ID + 密码 +- 用户 ID + token + +手动登录时传入的用户 ID 必须为 String 类型,支持的字符集详见[用户注册的 RESTful 接口](/document/v1/server-side/account_system.html#注册用户)。 + +调用登录接口后,收到 `onConnected` 回调表明 SDK 与环信服务器连接成功。 + +### 手动登录 + +**用户 ID + 密码** 登录是传统的登录方式。用户名和密码均由你的终端用户自行决定,密码需要符合密码规则要求。 + +```java +EMClient.getInstance().login(mAccount, mPassword, new EMCallBack() { + // 登录成功回调 + @Override + public void onSuccess() { + + } + + // 登录失败回调,包含错误信息 + @Override + public void onError(int code, String error) { + + } + +}); +``` + +**用户 ID + token** 是更加安全的登录方式。token 可以通过调用 REST API 获取。详见 [环信用户 token 的获取](/document/v1/server-side/easemob_user_token.html)。 + +:::notice +使用 token 登录时需要处理 token 过期的问题,比如在每次登录时更新 token 等机制。 +::: + +```java +EMClient.getInstance().loginWithToken(mAccount, mToken, new EMCallBack() { + // 登录成功回调 + @Override + public void onSuccess() { + + } + + // 登录失败回调,包含错误信息 + @Override + public void onError(int code, String error) { + + } +}); +``` + +登录重试机制如下: + +- 登录时,若服务器返回明确的失败原因,例如,token 不正确,SDK 不会重试登录。 +- 若登录因超时失败,SDK 会重试登录。 + +### 自动登录 + +初始化时可以设置是否自动登录。如果设置为自动登录,则登录成功之后,后续启动初始化的时候会自动登录。 + +自动登录时,SDK 尝试连接服务器失败后,延时随机一段时间后自动重连。 + +## 退出登录 + +同步方法: + +```java +EMClient.getInstance().logout(true); +``` + +异步方法: + +```java +EMClient.getInstance().logout(true, new EMCallBack() { + + @Override + public void onSuccess() { + + } + + @Override + public void onError(int code, String message) { + + } +}); +``` + +## 连接状态相关 + +你可以通过注册连接监听确认连接状态。 + +```java +EMConnectionListener connectionListener = new EMConnectionListener() { + @Override + public void onConnected() { + + } + @Override + public void onDisconnected(int errorCode) { + + } + + @Override + public void onLogout(int errorCode) { + + } + + @Override + public void onTokenWillExpire() { + + } + + @Override + public void onTokenExpired() { + + } +}; +// 注册连接状态监听 +EMClient.getInstance().addConnectionListener(connectionListener); +// 移除连接状态监听 +EMClient.getInstance().removeConnectionListener(connectionListener); +``` + +### 断网自动重连 + +如果由于网络信号弱、切换网络等引起的连接终端,SDK 会自动尝试重连。重连成功或者失败的结果分别会收到通知 `onConnected` 和 `onDisconnected`。 + +### 被动退出登录 + +你可以通过监听回调 `EMConnectionListener#onLogout(int)` 后,调用 `EMClient#logout(boolean, EMCallBack)` 进行退出并返回登录界面。 + +`EMConnectionListener#onLogout(int)` 返回的 `errorCode` 有如下: + +- `USER_LOGIN_ANOTHER_DEVICE=206`: 用户已经在其他设备登录 +- `USER_REMOVED=207`: 用户账户已经被移除 +- `USER_BIND_ANOTHER_DEVICE=213`: 用户已经绑定其他设备 +- `USER_LOGIN_TOO_MANY_DEVICES=214`: 用户登录设备超出数量限制 +- `USER_KICKED_BY_CHANGE_PASSWORD=216`: 由于密码变更被踢下线 +- `USER_KICKED_BY_OTHER_DEVICE=217`: 由于其他设备登录被踢下线 +- `USER_DEVICE_CHANGED=220`: 和上次设备不同导致下线 +- `SERVER_SERVING_DISABLED=305`: 服务器服务停止 + +以上参数具体可以参考 [EMError](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html) 对应说明。 + +## 输出信息到日志文件 + +开发者可以在开发阶段开启 `DEBUG` 模式,获取更多的调试信息。 + +```java +// 需要在 SDK 初始化后调用 +EMClient.getInstance().setDebugMode(true); +``` + +### 获取本地日志 + +```shell +adb pull /sdcard/android/data/{应用包名}/{App Key}/core_log/easemob.log +``` + +获取本地日志,需要将 `{应用包名}` 替换为应用的包名,例如 `com.hyphenate.chatuidemo`;`{App Key}` 需要替换为应用设置的环信 App Key。 diff --git a/docs/document/v1/android/presence.md b/docs/document/v1/android/presence.md index b1c430652..2399f9035 100644 --- a/docs/document/v1/android/presence.md +++ b/docs/document/v1/android/presence.md @@ -35,8 +35,8 @@ 使用在线状态功能前,请确保满足以下条件: 1. 完成 `3.9.1 或以上版本` SDK 初始化,详见 [快速开始](quickstart.html)。 -2. 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -3. 已联系商务开通在线状态订阅功能。 +2. 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +3. 私有部署已开通在线状态订阅功能。 ## 实现方法 @@ -44,7 +44,7 @@ ### 订阅指定用户的在线状态 -默认情况下,你不关注任何其他用户的在线状态。你可以通过调用 `com.hyphenate.chat.EMPresenceManager#subscribePresences` 方法订阅指定用户的在线状态,示例代码如下: +默认情况下,你不关注任何其他用户的在线状态。你可以通过调用方法订阅指定用户的在线状态, `com.hyphenate.chat.EMPresenceManager#subscribePresences` 示例代码如下: ```java EMClient.getInstance().presenceManager().subscribePresences(contactsFromServer, 1 * 24 * 3600, new EMValueCallBack>() { diff --git a/docs/document/v1/android/push.md b/docs/document/v1/android/push.md index 33cab9136..12047c251 100644 --- a/docs/document/v1/android/push.md +++ b/docs/document/v1/android/push.md @@ -38,9 +38,9 @@ ## 前提条件 -- 已开启环信即时通讯服务,详见 [开启和配置即时通讯服务](/product/enable_and_configure_IM.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -- 你已在 [环信控制台](https://console.easemob.com/user/login)中激活推送高级功能。高级功能激活后,你可以设置推送通知方式、免打扰模式和自定义推送模板。如需关闭推送高级功能必须联系商务,因为该操作会删除所有相关配置。 +- 已开启环信即时通讯服务,详见 [环信控制台Console操作指南](/document/v1/privatization/uc_deploy.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 你已在 环信控制台中激活推送高级功能。高级功能激活后,你可以设置推送通知方式、免打扰模式和自定义推送模板。如需关闭推送高级功能必须联系商务,因为该操作会删除所有相关配置。 各推送使用条件: @@ -104,7 +104,7 @@ EMClient.getInstance().init(this, options); **步骤二:上传推送证书。** -注册完成后,在[环信即时通讯云控制台](https://console.easemob.com/user/login)上传推送证书,选择你的应用 > **即时通讯** > **功能配置** > **消息推送** > **证书配置**,点击 **添加推送证书**。即时通讯 IM 支持 FCM 的旧版证书和 v1 版证书。 +注册完成后,在环信即时通讯云控制台上传推送证书,选择你的应用 > **即时推送** > **配置证书**,点击 **添加推送证书**。即时通讯 IM 支持 FCM 的旧版证书和 v1 版证书。 - 若 **证书类型** 选择 **旧版**,你需要将 **证书名称** 设置为 FCM 的发送者 ID,**推送秘钥** 设置为 FCM 的服务器密钥。你需在 [Firebase 控制台](https://console.firebase.google.com/?hl=zh-cn)的 **项目设置 > 云消息传递** 页面中,在 **Cloud Messaging API(旧版)** 区域中获取发送者 ID 和服务器密钥,如下图所示。配置完毕,设置 **铃声**、**推送优先级设置** 和 **推送消息类型** 参数。 @@ -278,7 +278,7 @@ public class EMFCMMSGService extends FirebaseMessagingService { ``` 5. [华为通知消息智能分类](https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-intelligent-classification-0000001050040120)。 - + + @@ -414,7 +414,7 @@ EMPushHelper.getInstance().setPushListener(new PushListener() { - + ``` 对于注册荣耀推送服务,需自定义 Service,继承荣耀推送的 `HonorMessageService` 类,重写 `onNewToken` 方法。 @@ -508,8 +508,6 @@ EMClient.getInstance().chatManager().sendMessage(message); ``` - - @@ -550,7 +548,7 @@ private void getIntentData(Intent intent) { ``` 关于荣耀推送详情,请参见[荣耀推送官网](https://developer.hihonor.com/cn/kitdoc?category=%E5%9F%BA%E7%A1%80%E6%9C%8D%E5%8A%A1&kitId=11002&navigation=guides&docId=introduction.md&token=)。 - +--> #### 小米推送集成 @@ -900,7 +898,7 @@ OPPO 推送在 2.1.0 适配了 Android Q,在 Android Q 上接收 OPPO 推送 - 设置推送通知,包含设置推送通知方式和免打扰模式。 - 配置推送翻译和推送模板。 -其中,设置推送通知方式、免打扰模式和推送模板为推送的高级功能,使用前需要在[环信即时通讯云控制后台](https://console.easemob.com/user/login)上开通。 +其中,设置推送通知方式、免打扰模式和推送模板为推送的高级功能,使用前需要在环信即时通讯云控制后台上开通。 ![image](@static/images/android/push/push_android_enable_push.png) @@ -1139,7 +1137,7 @@ EMPushManager.DisplayStyle style = pushConfigs.getDisplayStyle(); #### 4.3 设置推送翻译 -如果用户启用 [自动翻译](message_translation.html) 功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 +如果用户启用 自动翻译 功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 推送通知与翻译功能协同工作。作为接收方,你可以设置你在离线时希望接收的推送通知的首选语言。如果翻译消息的语言符合你的设置,则翻译消息显示在推送通知中;否则,将显示原始消息。 @@ -1158,7 +1156,7 @@ EMClient.getInstance().pushManager().getPreferredNotificationLanguage(new EMValu 环信 IM 支持自定义推送通知模板。使用前,你可参考以下步骤在环信即时通讯云管理后台上创建推送模板: 1. 登录环信 IM Console,进入首页。 -2. 在 **应用列表** 区域中,点击对应 app 的 **操作** 一栏中的 **查看** 按钮。 +2. 在 **应用列表** 区域中,点击对应 app 的 **操作** 一栏中的 **管理** 按钮。 3. 在环信 IM 配置页面的左侧导航栏,选择 **即时通讯 > 功能配置 > 消息推送 > 模板管理**,进入推送模板管理页面。 ![image](@static/images/android/push/push_android_template_mgmt.png) 4. 点击 **添加推送模板**。弹出以下页面,进行参数配置。 diff --git a/docs/document/v1/android/quickstart.md b/docs/document/v1/android/quickstart.md index f630ddf92..e43aa06fd 100644 --- a/docs/document/v1/android/quickstart.md +++ b/docs/document/v1/android/quickstart.md @@ -1,76 +1,104 @@ -# 快速开始 +# Android SDK 快速集成 - -本文介绍如何快速集成环信即时通讯 IM Android SDK 实现单聊。 +## Android SDK 介绍 -:::notice -最近遇到因 app 隐私问题下架的开发者需注意: +环信 SDK 为用户开发 IM 相关的应用提供的一套完善的开发框架。包括以下几个部分: -- 请在点击获取隐私权限以后启动环信 SDK 初始化。 -- `EMChatService` 和 `EMJobService` 为早期 SDK 内在应用退到后台后,对应用进行保活的程序,可以不进行注册。 -- `EMMonitorReceiver` 为监听开机自启动服务,可以不注册,同时请移除对应的权限申请:``。 - ::: +![img](@static/images/privitization/development-framework.png) -## 实现原理 +- SDK_Core 为核心的消息同步协议实现,完成与服务器之间的信息交换。 +- SDK 是基于核心协议实现的完整的 IM 功能,实现了不同类型消息的收发、会话管理、群组、好友、聊天室等功能。 +- EaseIMKit 是一组 IM 相关的 UI 控件,旨在帮助开发者快速集成环信 SDK。 -下图展示在客户端发送和接收一对一文本消息的工作流程。 +开发者可以基于 EaseIMKit 或者环信 SDK 开发自己的应用,前者因为把消息的发送接送等功能封装到了内部,集成时开发者不需要太关心消息是怎么发送、怎么接收等逻辑。请查阅 [EaseIMKit 使用指南](easeimkit)。 -![img](@static/images/android/sendandreceivemsg.png) +SDK 采用模块化设计,每一模块的功能相对独立和完善,用户可以根据自己的需求选择使用下面的模块: -## 前提条件 +![img](@static/images/privitization/image005.png) -- Android Studio 3.0 或以上版本; -- Android SDK API 等级 21 或以上; -- Android 5.0 或以上版本的设备; -- 有效的环信即时通讯 IM 开发者账号和 App key,见 [环信即时通讯云控制台](https://console.easemob.com/user/login)。 +- EMClient: SDK 的入口,主要完成登录、退出、连接管理等功能。也是获取其他模块的入口。 +- EMChatManager: 管理消息的收发,完成会话管理等功能。 +- EMContactManager: 负责好友的添加删除,黑名单的管理。 +- EMGroupManager: 负责群组的管理,创建、删除群组,管理群组成员等功能。 +- EMChatroomManager: 负责聊天室的管理。 -## 准备开发环境 -本节介绍如何创建项目,将环信即时通讯 IM Android SDK 集成到你的项目中,并添加相应的设备权限。 +## 视频教程 -### 1. 创建 Android 项目 +以下是 SDK 集成参考视频,您可以通过视频学习如何集成环信 SDK。 -参考以下步骤创建一个 Android 项目。 +- [Android_SDK 集成](https://ke.qq.com/webcourse/index.html#cid=320169&term_id=100380031&taid=2357945635758761&vid=t14287kwfgl) -1. 打开 Android Studio,点击 **Start a new Android Studio project**。 -2. 在 **Select a Project Template** 界面,选择 **Phone and Tablet > Empty Activity**,然后点击 **Next**。 -3. 在 **Configure Your Project** 界面,依次填入以下内容: - - **Name**:你的 Android 项目名称,如 HelloWorld。 - - **Package name**:你的项目包的名称,如 com.hyphenate.helloworld。 - - **Save location**:项目的存储路径。 - - **Language**:项目的编程语言,如 Java。 - - **Minimum API level**:项目的最低 API 等级。 +## Android SDK 导入 -然后点击 **Finish**。根据屏幕提示,安装所需插件。 +### 集成前准备 -上述步骤使用 **Android Studio 3.6.2** 示例。你也可以直接参考 Android Studio 官网文档 [创建首个应用](https://developer.android.com/training/basics/firstapp)。 +[注册并创建应用](/document/v1/privatization/uc_configure.html#创建应用) -### 2. 集成 SDK +### 手动复制 jar 包及 so 导入 -选择如下任意一种方式将环信即时通讯 IM SDK 集成到你的项目中。 +[下载环信 SDK](https://download-sdk.oss-cn-beijing.aliyuncs.com/mp/downloads/easemob-sdk-3.7.6.3.zip)。 -:::notice +在下载的 SDK 中,有个 libs 文件夹,libs 文件夹里是 jar 包和 so 文件。 -- 以下集成方式只需选择一种,同时使用多种集成方式可能会报错。 -- 请点击查看发版说明获得最新版本号。 - ::: +### 通过 gradle 远程链接导入 -#### 方法一:使用 mavenCentral 自动集成 +首先在你的项目根目录 `build.gradle` 文件的 `allprojects→repositories` 属性下加入远程库地址 -该方法仅适用于 v3.8.2 或以上版本。 +``` +repositories { + google() + mavenCentral() + maven { url 'http://developer.huawei.com/repo'} //如果需要使用华为推送HMS,则需要加上此句 + } +``` + +然后在你的 module 的 `build.gradle` 里加入以下代码 + +``` +android { + //use legacy for android 6.0(3.6.8版本之后移除apache library) + //useLibrary 'org.apache.http.legacy' + + //自 3.6.0 开始需要 java8 的支持 + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} +dependencies { + //其他必要依赖 + ...... + implementation 'io.hyphenate:hyphenate-chat:xxx版本号' +} +``` -1. 在项目的 `build.gradle` 中添加 `mavenCentral()`仓库。 +SDK 版本号参考[Release Note](releasenote) + +**请注意:** 如果使用 3.8.0 之前的版本,gradle 依赖需要按照下面格式添加: + +``` +implementation 'io.hyphenate:hyphenate-sdk:3.7.5' //完整版本,包含音视频功能 +//implementation 'io.hyphenate:hyphenate-sdk-lite:3.7.5' //精简版,只包含IM功能 +**重大变动** +``` -```gradle +因 JFrog 在 2021 年 2 月份宣布 2021 年 3 月 31 日后 JCenter 不再提供依赖库的更新,且到 2022 年 2 月 1 日后不再支持远程库的下载,详见[JFrog 声明](https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/)。 + +IM SDK 从 3.8.1 版本后只支持从 mavenCentral 仓库下载,开发者在使用 mavenCentral() 仓库时,需要做如下配置: + +1、在项目的 build.gradle 中添加 mavenCentral() 仓库。 + +``` buildscript { repositories { ... mavenCentral() } - ... } + allprojects { repositories { ... @@ -79,59 +107,75 @@ allprojects { } ``` -2. 在 `module` 的 `build.gradle` 中添加如下依赖: +2、修改 SDK 依赖的域名,由 “com.hyphenate” 修改为 “io.hyphenate”,如下: -```gradle -... -dependencies { - ... - // x.y.z 请填写具体版本号,如:3.9.4。 - // 可通过 SDK 发版说明获得最新版本号。 - implementation 'io.hyphenate:hyphenate-chat:x.x.x' -} +``` +implementation 'io.hyphenate:hyphenate-chat:xxx' ``` -获取最新 SDK 的版本号:[SDK 更新日志](releasenote.html) +SDK 3.8.0 之前的版本也可以从 mavenCentral 中下载,因 IM SDK3.8.0 之前 SDK 分为含音视频版和不含音视频版,添加依赖略有不同,如下: -:::notice -如果使用 3.8.0 之前的版本,gradle 依赖需要按照下面格式添加: -::: +1、含音视频版 -```gradle -implementation 'io.hyphenate:hyphenate-sdk:3.7.5' // 完整版本,包含音视频功能 +``` +implementation 'io.hyphenate:hyphenate-sdk:xxx' +``` + +注:hyphenate-sdk 支持 3.8.0 之前的版本。 + +2、不含音视频版 -implementation 'io.hyphenate:hyphenate-sdk-lite:3.7.5' // 精简版,只包含IM功能 ``` +implementation 'io.hyphenate:hyphenate-sdk-lite:xxx' +``` + +注:hyphenate-sdk-lite 支持 3.8.0 之前的版本。 + +### SDK 目录讲解 -#### 方法二:手动复制 SDK 文件 +从官网上下载下来的包,解压后内容如下: -打开 SDK 下载页面,获取最新版的环信即时通讯 IM Android SDK,然后解压。 +![img](@static/images/privitization/upload.png) -![img](@static/images/android/sdk-files.png) +在这里主要介绍后面四个文件夹内容: -将 SDK 包内 libs 路径下的如下文件,拷贝到你的项目路径下: +- doc 文件夹:SDK 相关 API 文档 +- examples 文件夹:EaseIm3.0 +- libs 文件夹:包含 IM 功能所需要的 jar 和 so 文件 -| 文件或文件夹 | 项目路径 | -| :------------------- | :--------------------- | -| easemob_xxx.jar 文件 | /app/libs/ | -| arm64-v8a 文件夹 | /app/src/main/jniLibs/ | -| armeabi-v7a 文件夹 | /app/src/main/jniLibs/ | -| x86 文件夹 | /app/src/main/jniLibs/ | -| x86_64 文件夹 | /app/src/main/jniLibs/ | +### 第三方库介绍 -如果对生成的 `apk` 大小比较敏感,我们建议使用 `jar` 方式,并且手工拷贝 `so`,而不是使用 `Aar`,因为 `Aar` 方式会把各个平台的 `so` 文件都包含在其中。采用 `jar` 方式,可以仅保留一个 `ARCH` 目录,建议仅保留 `armeabi-v7a`,这样虽然在对应平台执行的速度会降低,但是能有效减小 `apk` 的大小。 +#### SDK 中用到的第三方库 -### 3. 添加项目权限 +- android-support-v4.jar:这个可以说是每个 APP 中都是不可缺少的 jar 包,这里不多赘述 +- org.apache.http.legacy.jar:在 3.6.8 版本以后 SDK 移除了这个 jar 包;在 3.6.8 之前的版本用这个库兼容,建议不要删除,否则在 6.0 系统中,SDK 会有问题 -根据场景需要,在 `/app/src/main/AndroidManifest.xml` 文件中添加如下行,获取相应的设备权限: +#### EaseIMKit 中用到的第三方库 -```xml +- glide-4.9.0:图片处理库,显示用户头像时用到 +- BaiduLBS_Android.jar:百度地图的 jar 包,在 3.8.5 版本中移除地图的相关 so 文件,jar 包仅用于编译。依赖本地 EaseIMKit 库时,如果不用百度地图,可以不在 module 中添加百度地图的相关 jar 包及 so 文件,并移除地图的相关扩展功能(具体可参考[增加更多扩展功能](easeimkit.html#功能扩))。 + +### 配置工程 + +#### 导入 SDK + +在自行开发的应用中,集成环信聊天需要把 libs 文件夹下的 jar 及 so 文件复制到你的项目的 libs 文件夹相应位置。 + +[![img](https://docs-im.easemob.com/_media/im/android/sdk/f1a7b52fe99d623bd798b05566c46f3.png?w=200&tok=ed406e)](https://docs-im.easemob.com/_detail/im/android/sdk/f1a7b52fe99d623bd798b05566c46f3.png?id=im%3Aandroid%3Asdk%3Aimport) + +#### 配置信息 + +在清单文件 AndroidManifest.xml 里加入以下权限,以及写上你注册的 AppKey。 + +权限配置(实际开发中可能需要更多的权限,可参考 Demo): + +``` - - + @@ -142,116 +186,104 @@ implementation 'io.hyphenate:hyphenate-sdk-lite:3.7.5' // 精简版,只包含I - - - - - - + + + + + - - - - - - - - + + + + + + + - ``` -关于 App Key 对应的 value 获取,在 [环信即时通讯 IM 管理后台](https://console.easemob.com/user/login) 创建应用后,申请 App Key 并进行相关配置。 - -### 4. 防止代码混淆 +关于 EASEMOB_APPKEY 对应的 value 获取,在创建应用后,申请 AppKey 并进行相关配置。 -在 app/proguard-rules.pro 文件中添加如下行,防止混淆 SDK 的代码: +如果对生成的 apk 大小比较敏感,我们建议使用 jar 方式,并且手工拷贝 so,而不是使用 Aar,因为 Aar 方式会把各个平台的 so 文件都包含在其中。采用 jar 方式,可以仅保留一个 ARCH 目录,如果对大小非常敏感,建议仅保留 armeabi-v7a,这样虽然在对应平台执行的速度会降低,但是能有效减小 apk 的大小。 -```java --keep class com.hyphenate.** {*;} --dontwarn com.hyphenate.** -``` +### 常见问题汇总 -## 实现单聊 +1. 用户集成 SDK 后使用 HttpClient 报错 -本节介绍如何实现单聊。 +``` +建议将 SDK 升级到 3.6.8 以上版本,SDK3.6.8 以后版本移除了 apache library。 +``` -### 1. SDK 初始化 +3.6.8 版本之前的版本请按照下面进行配置: -在主进程中进行初始化: +\- Android 6.0 及以上版本需要在 `module-level/build.gradle` android block 中添加: -```java -EMOptions options = new EMOptions(); -options.setAppKey("Your appkey"); -......// 其他 EMOptions 配置。 -EMClient.getInstance().init(context, options); ``` - -### 2. 创建账号 - -可以使用如下代码创建账户: - -```java -try { - // 注册失败会抛出 HyphenateException。 - // 同步方法,会阻塞当前线程。 - EMClient.getInstance().createAccount(userName, pwd); - //成功 - //callBack.onSuccess(createLiveData(userName)); - } catch (HyphenateException e) { - //失败 - //callBack.onError(e.getErrorCode(), e.getMessage()); - } +android { + //use legacy for android > 6.0 + useLibrary 'org.apache.http.legacy' + } ``` -:::notice -该注册模式为在客户端注册,主要用于测试,简单方便,但不推荐在正式环境中使用;正式环境中应使用服务器端调用 Restful API 注册,具体见[注册单个用户](/document/server-side/account_system.html#注册单个用户)。 -::: - -### 3. 登录账号 +\- Android 9.0 还需在 `AndroidManifest.xml` 的 `application` 标签中添加: -使用如下代码实现用户登录: +``` + + + +``` -```java -EMClient.getInstance().login(mAccount, mPassword, new EMCallBack() { - // 登录成功回调 - @Override - public void onSuccess() { +2. Android 9.0 上强制使用 https 的问题 - } +表现:会出现出现 `UnknownServiceException: CLEARTEXT communication to localhost not permitted by network security policy` 或者 `IOException java.io.IOException: Cleartext HTTP traffic to * not permitted` 报错 - // 登录失败回调,包含错误信息 - @Override - public void onError(final int code, final String error) { +解决办法可以参考:[StackOverFlow](https://stackoverflow.com/questions/45940861/android-8-cleartext-http-traffic-not-permitted),也可以直接在 `AndroidManifest.xml` 文件的 `application` 标签中设置 android:usesCleartextTraffic=“true” - } +``` + + +``` - @Override - public void onProgress(int i, String s) { +3. 升级到 AndroidX 且使用 3.7.3 版本以上 SDK 报找不到 LocalBroadcastManager 的问题 - } +报错详情如下: -}); +``` +java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/localbroadcastmanager/content/LocalBroadcastManager; + at com.hyphenate.chat.core.EMAdvanceDebugManager.h(Unknown Source:13) + at com.hyphenate.chat.core.EMAdvanceDebugManager.a(Unknown Source:2) + at com.hyphenate.chat.EMClient.onNewLogin(Unknown Source:62) + at com.hyphenate.chat.EMClient$7.run(Unknown Source:197) + ...... + Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.localbroadcastmanager.content.LocalBroadcastManager" on path: DexPathList[[zip file "/data/app/com.hyphenate.easeim-3yS1c2quwGEzgNmhDyf7dA==/base.apk"],nativeLibraryDirectories=[/data/app/com.hyphenate.easeim-3yS1c2quwGEzgNmhDyf7dA==/lib/arm64, /data/app/com.hyphenate.easeim-3yS1c2quwGEzgNmhDyf7dA==/base.apk!/lib/arm64-v8a, /system/lib64, /product/lib64]] + ...... + at com.hyphenate.chat.core.EMAdvanceDebugManager.h(Unknown Source:13) + at com.hyphenate.chat.core.EMAdvanceDebugManager.a(Unknown Source:2) + at com.hyphenate.chat.EMClient.onNewLogin(Unknown Source:62) + at com.hyphenate.chat.EMClient$7.run(Unknown Source:197) + ...... ``` -:::notice -1. 除了注册监听器,其他的 SDK 操作均需在登录之后进行。 -2. 登录成功后需要调用 `EMClient.getInstance().chatManager().loadAllConversations();` 和 `EMClient.getInstance().groupManager().loadAllGroups();`,确保进入主页面后本地会话和群组均加载完毕。 -3. 如果之前登录过,App 长期在后台运行后切换到前台运行可能会导致加载到内存的群组和会话为空。为了避免这种情况,可在主页面的 `oncreate` 里也添加这两种方法,不过,最好将这两种方法放在程序的开屏页。 -::: +解决办法: 含音视频:将 SDK 升级到 3.7.6 版本; -### 4. 发送一条单聊消息 +## APP 打包混淆 + +在 ProGuard 文件中加入以下 keep。 -```java -// `content` 为要发送的文本内容,`toChatUsername` 为对方的账号。 -EMMessage message = EMMessage.createTextSendMessage(content, toChatUsername); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(message); ``` +-keep class com.hyphenate.** {*;} +-dontwarn com.hyphenate.** +//3.6.8 版本之后移除 apache,无需再添加 +-keep class internal.org.apache.http.entity.** {*;} +//如果使用了实时音视频功能 +-keep class com.superrtc.** {*;} +-dontwarn com.superrtc.** +``` \ No newline at end of file diff --git a/docs/document/v1/android/quickstart_v.md b/docs/document/v1/android/quickstart_v.md new file mode 100644 index 000000000..4f9d92f72 --- /dev/null +++ b/docs/document/v1/android/quickstart_v.md @@ -0,0 +1,257 @@ +# 快速开始 + + + +本文介绍如何快速集成环信即时通讯 IM Android SDK 实现单聊。 + +:::notice +最近遇到因 app 隐私问题下架的开发者需注意: + +- 请在点击获取隐私权限以后启动环信 SDK 初始化。 +- `EMChatService` 和 `EMJobService` 为早期 SDK 内在应用退到后台后,对应用进行保活的程序,可以不进行注册。 +- `EMMonitorReceiver` 为监听开机自启动服务,可以不注册,同时请移除对应的权限申请:``。 + ::: + +## 实现原理 + +下图展示在客户端发送和接收一对一文本消息的工作流程。 + +![img](@static/images/android/sendandreceivemsg.png) + +## 前提条件 + +- Android Studio 3.0 或以上版本; +- Android SDK API 等级 21 或以上; +- Android 5.0 或以上版本的设备; +- 有效的环信即时通讯 IM 开发者账号和 App key,见 [环信即时通讯云控制台](/document/v1/privatization/uc_configure.html)。 + +## 准备开发环境 + +本节介绍如何创建项目,将环信即时通讯 IM Android SDK 集成到你的项目中,并添加相应的设备权限。 + +### 1. 创建 Android 项目 + +参考以下步骤创建一个 Android 项目。 + +1. 打开 Android Studio,点击 **Start a new Android Studio project**。 +2. 在 **Select a Project Template** 界面,选择 **Phone and Tablet > Empty Activity**,然后点击 **Next**。 +3. 在 **Configure Your Project** 界面,依次填入以下内容: + - **Name**:你的 Android 项目名称,如 HelloWorld。 + - **Package name**:你的项目包的名称,如 com.hyphenate.helloworld。 + - **Save location**:项目的存储路径。 + - **Language**:项目的编程语言,如 Java。 + - **Minimum API level**:项目的最低 API 等级。 + +然后点击 **Finish**。根据屏幕提示,安装所需插件。 + +上述步骤使用 **Android Studio 3.6.2** 示例。你也可以直接参考 Android Studio 官网文档 [创建首个应用](https://developer.android.com/training/basics/firstapp)。 + +### 2. 集成 SDK + +选择如下任意一种方式将环信即时通讯 IM SDK 集成到你的项目中。 + +:::notice + +- 以下集成方式只需选择一种,同时使用多种集成方式可能会报错。 +- 请点击查看发版说明获得最新版本号。 + ::: + +#### 方法一:使用 mavenCentral 自动集成 + +该方法仅适用于 v3.8.2 或以上版本。 + +1. 在项目的 `build.gradle` 中添加 `mavenCentral()`仓库。 + +```gradle +buildscript { + repositories { + ... + mavenCentral() + } + ... +} + +allprojects { + repositories { + ... + mavenCentral() + } +} +``` + +2. 在 `module` 的 `build.gradle` 中添加如下依赖: + +```gradle +... +dependencies { + ... + // x.y.z 请填写具体版本号,如:3.9.4。 + // 可通过 SDK 发版说明获得最新版本号。 + implementation 'io.hyphenate:hyphenate-chat:x.x.x' +} +``` + +获取最新 SDK 的版本号:[SDK 更新日志](releasenote.html) + +:::notice +如果使用 3.8.0 之前的版本,gradle 依赖需要按照下面格式添加: +::: + +```gradle +implementation 'io.hyphenate:hyphenate-sdk:3.7.5' // 完整版本,包含音视频功能 + +implementation 'io.hyphenate:hyphenate-sdk-lite:3.7.5' // 精简版,只包含IM功能 +``` + +#### 方法二:手动复制 SDK 文件 + +打开 SDK 下载页面,获取最新版的环信即时通讯 IM Android SDK,然后解压。 + +![img](@static/images/android/sdk-files.png) + +将 SDK 包内 libs 路径下的如下文件,拷贝到你的项目路径下: + +| 文件或文件夹 | 项目路径 | +| :------------------- | :--------------------- | +| easemob_xxx.jar 文件 | /app/libs/ | +| arm64-v8a 文件夹 | /app/src/main/jniLibs/ | +| armeabi-v7a 文件夹 | /app/src/main/jniLibs/ | +| x86 文件夹 | /app/src/main/jniLibs/ | +| x86_64 文件夹 | /app/src/main/jniLibs/ | + +如果对生成的 `apk` 大小比较敏感,我们建议使用 `jar` 方式,并且手工拷贝 `so`,而不是使用 `Aar`,因为 `Aar` 方式会把各个平台的 `so` 文件都包含在其中。采用 `jar` 方式,可以仅保留一个 `ARCH` 目录,建议仅保留 `armeabi-v7a`,这样虽然在对应平台执行的速度会降低,但是能有效减小 `apk` 的大小。 + +### 3. 添加项目权限 + +根据场景需要,在 `/app/src/main/AndroidManifest.xml` 文件中添加如下行,获取相应的设备权限: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +关于 App Key 对应的 value 获取,在 [环信即时通讯 IM 管理后台](/document/v1/privatization/uc_configure.html) 创建应用后,申请 App Key 并进行相关配置。 + +### 4. 防止代码混淆 + +在 app/proguard-rules.pro 文件中添加如下行,防止混淆 SDK 的代码: + +```java +-keep class com.hyphenate.** {*;} +-dontwarn com.hyphenate.** +``` + +## 实现单聊 + +本节介绍如何实现单聊。 + +### 1. SDK 初始化 + +在主进程中进行初始化: + +```java +EMOptions options = new EMOptions(); +options.setAppKey("Your appkey"); +......// 其他 EMOptions 配置。 +EMClient.getInstance().init(context, options); +``` + +### 2. 创建账号 + +可以使用如下代码创建账户: + +```java +try { + // 注册失败会抛出 HyphenateException。 + // 同步方法,会阻塞当前线程。 + EMClient.getInstance().createAccount(userName, pwd); + //成功 + //callBack.onSuccess(createLiveData(userName)); + } catch (HyphenateException e) { + //失败 + //callBack.onError(e.getErrorCode(), e.getMessage()); + } +``` + +:::notice +该注册模式为在客户端注册,主要用于测试,简单方便,但不推荐在正式环境中使用;正式环境中应使用服务器端调用 Restful API 注册,具体见[注册单个用户](/document/v1/server-side/account_system.html#注册用户)。 +::: + +### 3. 登录账号 + +使用如下代码实现用户登录: + +```java +EMClient.getInstance().login(mAccount, mPassword, new EMCallBack() { + // 登录成功回调 + @Override + public void onSuccess() { + + } + + // 登录失败回调,包含错误信息 + @Override + public void onError(final int code, final String error) { + + } + + @Override + public void onProgress(int i, String s) { + + } + +}); +``` + +:::notice +1. 除了注册监听器,其他的 SDK 操作均需在登录之后进行。 +2. 登录成功后需要调用 `EMClient.getInstance().chatManager().loadAllConversations();` 和 `EMClient.getInstance().groupManager().loadAllGroups();`,确保进入主页面后本地会话和群组均加载完毕。 +3. 如果之前登录过,App 长期在后台运行后切换到前台运行可能会导致加载到内存的群组和会话为空。为了避免这种情况,可在主页面的 `oncreate` 里也添加这两种方法,不过,最好将这两种方法放在程序的开屏页。 +::: + +### 4. 发送一条单聊消息 + +```java +// `content` 为要发送的文本内容,`toChatUsername` 为对方的账号。 +EMMessage message = EMMessage.createTextSendMessage(content, toChatUsername); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` diff --git a/docs/document/v1/android/reaction.md b/docs/document/v1/android/reaction.md index ed399f6dc..ea76fc2c7 100644 --- a/docs/document/v1/android/reaction.md +++ b/docs/document/v1/android/reaction.md @@ -7,7 +7,6 @@ :::notice 1. 目前 Reaction 仅适用于单聊和群组。聊天室暂不支持 Reaction 功能。 -2. 私有化版本不支持 Reaction 功能。 ::: ## 技术原理 @@ -31,8 +30,8 @@ Reaction 场景示例如下: 开始前,请确保满足以下条件: 1. 完成 `3.9.2.1 或以上版本` SDK 初始化,详见 [快速开始](quickstart.html)。 -2. 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -3. 已联系商务开通 Reaction 功能。 +2. 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +3. 私有部署已开通 Reaction 功能。 ## 实现方法 diff --git a/docs/document/v1/android/releasenote.md b/docs/document/v1/android/releasenote.md index cae5ca651..7cec298bf 100644 --- a/docs/document/v1/android/releasenote.md +++ b/docs/document/v1/android/releasenote.md @@ -1,7 +1,7 @@ # Android IM SDK 更新日志 - + + ## 版本 V3.7.6 2021-09-17 ### 修复: @@ -1071,7 +1067,7 @@ EaseUI: 新功能: 1. 增加是否使用 FCM 推送的接口 通过`EMOptions`的`setUserFCM()`方法设置 -2. 添加语音会议功能 [多人音视频会议](https://docs-im.easemob.com/im/android/basics/multiuserconference) +2. 添加语音会议功能 [多人音视频会议](/private/media/conference_android.html) 修复: @@ -1112,7 +1108,7 @@ EaseUI: 2. 使用外接音频输入源进行音视频通话时,设置音频源 3. 提供是否自己处理附件的上传和下载设置项 4. 提供是否自动下载附件类消息附件设置项(缩略图,语音文件) -5. 多人音视频会议功能,详细参考集成文档 [多人音视频会议](https://docs-im.easemob.com/im/android/basics/multiuserconference) +5. 多人音视频会议功能,详细参考集成文档 [多人音视频会议](/private/media/conference_android.html) 优化: diff --git a/docs/document/v1/android/room_attributes.md b/docs/document/v1/android/room_attributes.md index b520bc5c6..317921dfd 100644 --- a/docs/document/v1/android/room_attributes.md +++ b/docs/document/v1/android/room_attributes.md @@ -2,7 +2,7 @@ -聊天室是支持多人沟通的即时通讯系统。聊天室属性可分为聊天室名称、描述和公告等基本属性和自定义属性(key-value)。若聊天室基本属性不满足业务要求,用户可增加自定义属性并同步给所有成员。利用自定义属性可以存储直播聊天室的类型、狼人杀等游戏中的角色信息和游戏状态以及实现语聊房的麦位管理和同步等。聊天室自定义属性以键值对(key-value)形式存储,属性信息变更会实时同步给聊天室成员。 +聊天室是支持多人沟通的即时通讯系统。聊天室属性可分为聊天室名称、描述和公告等基本属性。 本文介绍如何管理聊天室属性信息。 @@ -11,17 +11,18 @@ 环信即时通讯 IM SDK 提供 `EMChatRoomManager` 类和 `EMChatRoom` 类用于聊天室管理,支持你通过调用 API 在项目中实现如下功能: - 获取和更新聊天室基本属性; + ## 前提条件 开始前,请确保满足以下条件: -- 完成 SDK 初始化,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的 [使用限制](/product/limitation.html); -- 了解聊天室的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 +- 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 @@ -76,7 +77,7 @@ EMChatRoom chatRoom = EMClient.getInstance().chatroomManager().changeChatRoomSub // 异步方法为 asyncChangeChatroomDescription(String, String, EMValueCallBack)。 EMChatRoom chatRoom = EMClient.getInstance().chatroomManager().changeChatroomDescription(chatRoomId, newDescription); ``` - + ### 监听聊天室事件 diff --git a/docs/document/v1/android/room_manage.md b/docs/document/v1/android/room_manage.md index ce40ceb80..a61069513 100644 --- a/docs/document/v1/android/room_manage.md +++ b/docs/document/v1/android/room_manage.md @@ -25,9 +25,8 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的 [使用限制](/product/limitation.html)。 -- 了解环信即时通讯 IM 不同版本的聊天室相关数量限制,详见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im)。 -- 只有超级管理员才有创建聊天室的权限,因此你还需要确保已调用 RESTful API 添加了超级管理员,详见 [添加聊天室超级管理员](/document/server-side/chatroom.html#添加超级管理员)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 只有超级管理员才有创建聊天室的权限,因此你还需要确保已调用 RESTful API 添加了超级管理员,详见 [添加聊天室超级管理员](/document/v1/server-side/chatroom.html#添加超级管理员)。 - 聊天室创建者和管理员的数量之和不能超过 100,即管理员最多可添加 99 个。 ## 实现方法 @@ -36,9 +35,9 @@ ### 创建聊天室 -仅 [超级管理员](/document/server-side/chatroom.html#管理超级管理员) 可以调用 `createChatRoom` 方法创建聊天室,并设置聊天室的名称、描述、最大成员数等信息。成功创建聊天室后,该超级管理员为该聊天室的所有者。 +仅 [超级管理员](/document/v1/server-side/chatroom.html#管理超级管理员) 可以调用 `createChatRoom` 方法创建聊天室,并设置聊天室的名称、描述、最大成员数等信息。成功创建聊天室后,该超级管理员为该聊天室的所有者。 -你也可以直接调用 REST API [从服务端创建聊天室](/document/server-side/chatroom.html#创建聊天室)。 +你也可以直接调用 REST API [从服务端创建聊天室](/document/v1/server-side/chatroom.html#创建聊天室)。 示例代码如下: diff --git a/docs/document/v1/android/room_members.md b/docs/document/v1/android/room_members.md index 8f5bdffe0..ddeab089d 100644 --- a/docs/document/v1/android/room_members.md +++ b/docs/document/v1/android/room_members.md @@ -21,8 +21,8 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的 [使用限制](/product/limitation.html)。 -- 了解环信即时通讯 IM 聊天室相关限制,详见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 + ## 实现方法 diff --git a/docs/document/v1/android/room_overview.md b/docs/document/v1/android/room_overview.md index 1635b9905..e4b189ed5 100644 --- a/docs/document/v1/android/room_overview.md +++ b/docs/document/v1/android/room_overview.md @@ -6,7 +6,7 @@ 聊天室是支持多人加入的类似 Twitch 的组织,聊天室中的成员没有固定关系,一旦离线后,不会收到聊天室中的任何消息,超过 2 分钟会自动退出聊天室。聊天室可以应用于直播、消息广播等。若需调整该时间,需联系环信商务经理。 -聊天室的使用限制视不同套餐版本而定,请参见 [使用限制](/product/limitation.html)。 +聊天室的使用限制请参见 [使用限制](/document/v1/privatization/uc_limitation.html)。 本文以及接下来几篇主要介绍聊天室管理功能,如需查看消息相关内容,参见 。 @@ -32,7 +32,7 @@ | 功能 | 描述 | | :------------- | :----------------------------------------------------------- | -| 创建聊天室 | 只有被赋予 [超级管理员](/document/server-side/chatroom.html#管理超级管理员) 权限的用户有权限创建聊天室。聊天室成员数会受到版本指定聊天室最大成员数的限制。 | +| 创建聊天室 | 只有被赋予 [超级管理员](/document/v1/server-side/chatroom.html#管理超级管理员) 权限的用户有权限创建聊天室。聊天室成员数会受到版本指定聊天室最大成员数的限制。 | | 加入聊天室 | 没有被加入黑名单的所有 app 用户可自由加入聊天室。 | | 离开聊天室 | 所有聊天室成员都可以自由退出聊天室;也可能被动离开聊天室,原因分为:被管理员移出聊天室、聊天室解散和用户账号离线。 | | 销毁聊天室 | 需要聊天室所有者权限。 | diff --git a/docs/document/v1/android/thirdpartypush.md b/docs/document/v1/android/thirdpartypush.md new file mode 100644 index 000000000..fbbd6515e --- /dev/null +++ b/docs/document/v1/android/thirdpartypush.md @@ -0,0 +1,713 @@ +# 第三方推送集成 + +## 说明 + +当 App 在后台运行时环信 IM SDK 默认通过一个后台服务保持一条连接环信服务器的长连接,但 Android 为了解决系统待机性能差的问题,随着 Android 版本的升级逐渐禁止了 App 级别的后台服务的运行。所以在一些版本比较高的 Android 系统上会有接收不到消息的情况。为了提高消息的到达率,我们 SDK 增加了对第三方推送服务的支持,包括小米推送,华为推送,OPPO 推送,魅族推送,VIVO 推送,Google FCM 推送。 + +目前小米、魅族、OPPO、VIVO 推送的主要实现集成在了环信 IM SDK 中,尽量提供给开发者最简单的集成三方推送的形式。Google FCM 和华为推送的实现仍在 Demo 层,需要开发者自己集成,详情请参考环信的 Google FCM 和华为的推送集成文档。 + +**注意:**`SDK V3.5.4 及以上版本才支持第三方各平台推送,但 SDK V3.5.4 在华为注册推送的时候会出现异常,该 Bug 在 V3.5.5 及之后的版本中已修复,这里建议未集成的用户或者已是 V3.5.4 的用户升级到更高的 SDK 版本。` + +##### 各推送使用条件: + +- Google FCM:需要 Google Play Service 和能连接 Google 服务器的网络; +- 小米推送:在小米系统上可用; +- 华为推送:在华为系统上可用; +- 魅族推送:在魅族系统上可用; +- OPPO 推送:在 OPPO 系统上可用; +- VIVO 推送:在 VIVO 系统上可用; +- SDK 内部会按照这个顺序去检测设备的推送支持情况。 +- 如果未设置第三方推送或者不满足使用第三方推送的条件,环信 IM SDK 会通过一些保活手段尽可能的保持与环信服务器的长连接,以确保消息的及时送达。 + +:::tip +建议:如果你的 App 有海外使用场景,建议开启 FCM 推送;由于各推送使用条件不同,建议尽可能同时支持小米和华为推送。 +::: + +#### 消息推送流程: + +![img](@static/images/privitization/image010.png) + +1. 判断设备支持哪种推送(App 配置了第三方推送并且满足该推送的使用条件); +2. 根据集成第三方推送 SDK 获取推送 token; +3. 上传证书名称(环信服务器用来判断使用哪种推送通道)和推送 token 到环信服务器; +4. 向某设备发送消息时,环信服务器会先判断目标设备是否在线,如果目标设备不在线,则判断目标设备使用了哪种推送通道(根据目标设备上传的证书名称),使用该推送通道通过第三方推送服务器将消息推送至目标设备。 + +##### 环信服务器应具备的能力: + +- 拥有向你的 App 发送推送消息的能力; +- 开发者通过环信后台配置 App 的推送证书,推送证书会要求填写证书名称(或者 App Key),证书名称是环信服务器用来判断目标设备使用哪种推送通道的唯一条件,所以`证书名称必须与 Android 终端设备上传的证书名称一致` +- 跟终端 Android 设备一一对应的推送 token; +- 需 Android 设备上报; +- 推送 token 属于哪个推送通道; +- 需 Android 设备上报。 + +##### Android 设备需要做的事: + +- 判断当前设备支持哪种推送通道; +- 通过集成第三方推送 SDK 获取推送 token; +- 上传证书名称(注意跟通过环信后台配置的证书名称保持一致)和推送 token 至环信服务器(该步骤必须在环信 SDK 登录成功后)。 + +## 配置推送接口 + +开发者配置推送的接口: + +``` +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); + builder.enableVivoPush() // 推送证书相关信息配置在 AndroidManifest.xml 中 + .enableMeiZuPush(String appId, String appKey) + .enableMiPush(String appId, String appKey) + .enableOppoPush(String appKey, String appSecret) + .enableHWPush() //开发者需要调用该方法来开启华为推送 + .enableFCM(String senderId); //开发者需要调用该方法来开启 FCM 推送 + +EMOptions options = new EMOptions(); +options.setPushConfig(builder.build()); +``` + +开发者需要把上述配置中的相关信息换成开发者自己申请的各平台的配置。建议开发者尽可能多的配置三方推送,以确保离线消息的到达率。 + +**请注意: 开发者需要在 SDK 初始化之前配置相关的推送信息。** + +开发者可以调用以下代码监听推送相关事件(仅支持小米、魅族、OPPO、VIVO): + +``` +EMPushHelper.getInstance().setPushListener(new PushListener() { + @Override + public void onError(EMPushType pushType, long errorCode) { + EMLog.e("PushClient", "Push client occur a error: " + pushType + " - " + errorCode); +// TODO: 开发者会在这个回调中收到使用推送的相关错误信息,各推送类型的 error code 开发者可以自己去各推送平台官网查询错误原因。 + } + + @Override + public boolean isSupportPush(EMPushType pushType, EMPushConfig pushConfig) { + return super.isSupportPush(pushType, pushConfig); +// TODO:开发者可以复写该方法控制设备是否支持某推送的判断。 + } +}); +``` + +## 关于混淆 + +- 如果您在项目中开启了混淆,请把以下规则添加到您的混淆规则中: + +``` +# 环信 push + -dontwarn com.hyphenate.push.*** + -keep class com.hyphenate.push.*** {*;} + +``` + +- 关于环信推送中集成的第三方推送的混淆规则,可以自行到各开发者推送平台查看 + +## Google FCM 推送集成 + + +SDK 3.4.2 版本开始默认优先使用 FCM 推送,在一些带 Google Play Service 的华为设备上,开发者可通过设置 EMOptions#setUseFCM(false) 关闭 FCM 推送的使用,来达到使用华为推送的目的。SDK 3.8.5 版本开始废弃了 EMOptions#setUseFCM(false),由应用层去控制是否优先使用 FCM 推送。 + + +### 说明 + +- FCM 使用主要针对海外用户; +- FCM 要求设备安装有 Google Play 服务、 Google Play 商店 和 能连接 Google 服务器的网络。 + +### 服务端 + +1.登录[Firebase管理后台](https://console.firebase.google.com/) + +2.在Firebase欢迎界面点击 **Add Project**,输入相应内容并点击 **Create Project**。 + +3.在Firebase欢迎界面选择 **Add Firebase to your Android App**。 + +4.选择应用类型后需要输入包名、项目昵称、SHA-1,然后点击 **Register App**。 + +5.进入引导页,如下图,点击按钮下载 google-services.json 文件到本地。**注意该 json 文件在 Android 项目中的放置位置。** + +![img](@static/images/privitization/3.3.5_config_download.png) + + +6.跳过引导页,点击 Cloud Messaging tab 页,复制 Server Key 和 Sender ID。 + +![img](@static/images/privitization/3.3.5_cloud_messaging.png) + + +7.登录[环信管理后台](/document/v1/privatization/uc_configure.html#配置推送证书),首页-应用列表—管理-即时推送—配置证书,证书的名称要求填上方复制 Sender ID,证书秘钥填写上方复制的 Server Key。 + +![img](@static/images/privitization/添加谷歌证书.png) + +![img](@static/images/privitization/3.3.5_certificate_add_success.png) + +### 移动端 + +:::notice +从 SDK 3.8.5 版本开始,移除了 SDK 内置的 11.4.0 的 FCM 推送的相关依赖,将 FCM 推送集成从 SDK 中转移到应用层,集成方式会有变化,参考后续的文档。 +::: + +#### SDK 3.8.5 版本之前集成方式 + +1.添加 Google Play Service 相关依赖库 + +用于检查设备是否支持 Google FCM 推送,`该步骤在 FCM 官方集成文档上不存在,由于国内特殊的使用环境,所以我们增加了该配置用于辅助检测`。 + +把 `compile 'com.google.android.gms:play-services-base:11.4.0`' 该行配置添加到项目相应的 build.gradle 文件中,SDK demo 中的配置在 easeui/build.gradle 中,如下: + +``` +dependencies { + // 添加此行 + compile 'com.google.android.gms:play-services-base:11.4.0' +} +注意:Google 推送相关依赖库版本必须对应(该文档中均为:11.4.0),否则可能会出现类冲突的错误。 +``` + +2.在 project-level 的 build.gradle 中添加 FCM 相关库文件配置: + +``` +buildscript { + repositories { + jcenter() + } + dependencies { + // 添加此行 + classpath 'com.google.gms:google-services:3.1.1' + } +} + +allprojects { + repositories { + // 添加此行 + maven { url 'https://maven.google.com' } + } +} +``` + +3.在 app-level 的 build.gradle 中添加 FCM 相关库文件配置:Push + +``` +dependencies { +// 添加此行,Google Firebase cloud messaging + compile 'com.google.firebase:firebase-messaging:11.4.0' +} + +// 此行添加在文件末尾 +apply plugin: 'com.google.gms.google-services' +注意:Google 推送相关依赖库版本必须对应(该文档中均为:11.4.0),否则可能会出现类冲突的错误。 +``` + +4.放置下载的 google-services.json 在 app-level 的根目录下 + + +![img](@static/images/privitization/3.3.5_config_location.png) + +5.实现一个继承自 FirebaseInstanceIdService 的自定义 service,该类用于监听 FCM token 的创建和更新。一个设备对应一个 FCM token,该 token 用于服务端向该设备推送消息,所以该 token 创建或更新后需及时上传至环信服务器。 + +自定义 FirebaseInstanceIdService: + +``` +public class EMFCMTokenRefreshService extends FirebaseInstanceIdService { + private static final String TAG = "FCMTokenRefreshService"; + + @Override + public void onTokenRefresh() { + super.onTokenRefresh(); + String token = FirebaseInstanceId.getInstance().getToken(); + Log.i(TAG, "onTokenRefresh: " + token); + // Important, send the fcm token to the server + EMClient.getInstance().sendFCMTokenToServer(token); + } +} +``` + +AndroidManifest.xml: + +``` + + + + + +``` + +6.实现一个继承自 FirebaseMessagingService 的自定义 service,该类用于 FCM 在后台进行接收应用推送消息的处理。并把该 service 注册到 AndroidManifest.xml 中。 + +自定义 FirebaseMessagingService: + +``` +public class EMFCMMSGService extends FirebaseMessagingService { + private static final String TAG = "EMFCMMSGService"; + + @Override + public void onMessageReceived(RemoteMessage remoteMessage) { + super.onMessageReceived(remoteMessage); + if (remoteMessage.getData().size() > 0) { + String message = remoteMessage.getData().get("alert"); + Log.i(TAG, "onMessageReceived: " + message); + } + } +} +``` + +AndroidManifest.xml: + +``` + + + + + +``` + +7.通过 EMOptions#setUseFCM(true) 接口设置允许使用 FCM 推送,SDK 会进行 FCM 推送条件的检查,并在 FCM 推送条件满足的情况下使用 FCM 推送。接口使用可参考 Demo 中的 DemoHelper。 + +8.启用 FCM 推送 + +- `SDK3.5.4 及以后版本:` + +``` +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); +builder.enableFCM(String senderId); +options.setPushConfig(builder.build()); +``` + +- SDK 3.5.3 及之前版本: + +``` +EMOptions options = new EMOptions(); +options.setFCMNumber(senderId); +``` + +### 推送服务测试 + +为了确保推送服务的成功集成,可按如下步骤进行测试: + +1. 运行 App 并进行登录 +2. 杀掉该 App 进程(通过 Android 任务列表滑动结束进程不是按 Home 键让 App 进入后台;`通过 设置→应用→强行停止 结束 App 进程,App 无法接收到 FCM 推送,详情请查阅 Google 官方对该操作的解释`。) +3. 向该登录账号发送消息,App 会收到通过推送服务送达的消息。 + +## 华为 HMS 推送集成 + +### 创建华为应用 + +首先就是去华为开发者后台创建应用,并开启 push 服务,并上传对应的证书指纹,具体可以看下华为官方介绍:[ 华为 HMS 消息推送服务集成](http://developer.huawei.com/consumer/cn/service/hms/catalog/huaweipush.html?page=hmssdk_huaweipush_devprepare) + +### 上传推送证书 + + +注册完整后,登录[环信管理后台](/document/v1/privatization/uc_configure.html#配置推送证书),首页-应用列表—管理-即时推送—配置证书-Huawei,然后输入你在[华为开发者后台](http://developer.huawei.com/consumer/cn/devunion/openPlatform/html/memberCenter.html#/appManager)创建的应用信息中的 `APPID` 和 `SecretKey` 以及程序的 `包名`; + +### 华为 4.0 推送集成 + +从华为 EMUI 10.0 版本开始华为推送将通知消息智能分成两个级别:一般与重要。[ 华为通知消息智能分类](https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-intelligent-classification-0000001050040120) + +可以参考环信最新的 demo 去集成 4.0 版本的华为推送: + +1、将华为推送后台项目应用下的 “agconnect-services.json” 文件拷贝到应用级根目录下。 + +2、在项目级根目录的 build.gradle 里配置以下: + +``` +allprojects { + repositories { + google() + mavenCentral() + maven {url 'https://developer.huawei.com/repo/'} + jcenter()//马上弃用 + } +} +buildscript { + repositories { + google() + mavenCentral() + maven {url 'https://developer.huawei.com/repo/'} + jcenter()//马上弃用 + } + dependencies { + classpath 'com.huawei.agconnect:agcp:1.3.1.300' + } +} +``` + +3、在应用级的 build.gradle 里添加如下编译依赖: + +``` +apply plugin: 'com.huawei.agconnect' + +dependencies { + //其它已存在的依赖不要删除 + implementation 'com.huawei.hms:push:4.0.2.300' +} +``` + +4、demo 中的 HMSPushHelper 里封装了华为申请 token 的代码,可以参考实现。 + +5、需要继承 HmsMessageService,重写 onNewToken,在里面去上传推送 token,可参考 demo 中的 HMSPushService,并配置到清单文件里。 + +``` + + + + + + + +``` + +6、在 SDK 初始化的时候,配置启用华为推送。 + +``` +EMOptions options = new EMOptions(); +//其他配置设置 +... +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); +builder.enableHWPush(); +//其他推送配置设置 +... +options.setPushConfig(builder.build()); +``` + +**注意**:我们默认的推送文案会被智能分类到一般,APP端收到的就是静默通知,需要给消息设置自定义推送的标题和内容,具体分类标准可咨询华为官网。 + +### 华为推送角标 + +需要在消息扩展里设置上应用入口activity,如环信demo是com.hyphenate.chatuidemo.ui.SplashActivity + +``` +// 设置自定义推送提示 +JSONObject extObject = new JSONObject(); +try { + extObject.put("em_huawei_push_badge_class", "com.hyphenate.chatuidemo.ui.SplashActivity"); +} catch (JSONException e) { + e.printStackTrace(); +} +// 将推送扩展设置到消息中 +message.setAttribute("em_apns_ext", extObject); +``` + +清空角标数参考[ 华为官方文档](http://obs.cn-north-1.myhwclouds.com/consumer/docattachment/87918b190abda6d7b7a568a7ef1dfc314cd9ad040faccf1a999dcff158ec7d79/badge.pdf) + +### SDK3.4.x - SDK3.5.4 版本 华为推送集成说明 + +为了方便用户自己升级华为推送相关 SDK,环信 SDK 在 `3.4.x` 之后的版本中将华为推送的集成从 `SDK` 中 `转移到应用层`,SDK 提供上传华为推送 token 的接口供用户调用,方便华为推送升级时用户自行升级,以后的版本就需要开发者自己去集成华为推送相关功能,然后调用下边的方法将 token 发送到环信服务器: + +``` +// 上传 token 方法,token 是通过广播接收器接收到的 +EMClient.getInstance().sendHMSPushTokenToServer("华为appId", "注册华为的 token"); +``` + +`PS:`需要注意,此方法必须是登录成功后才能调用,所以请求华为 token 需要放在登录成功之后,所以我们请求华为推送 token 一般放在 MainActivity 类中,环信 IM 的 Demo 也已经集成了华为最新推送 SDK,开发者也可以参考 demo 进行集成,token 的获去就是在广播接收器中,Demo 中有实现`HMSPushReceiver`类,可以看下 demo 的代码 + +这是华为官方集成文档,开发者可以自己根据华为官方文档进行集成华为推送 `华为消息推送服务集成官方文档` + +Demo 中将华为的 HMSAgent 做成了一个 module 进行引用(`这里没有对华为 HMSAgent 进行任何封装和修改`),开发者可以直接进行使用,也可以直接下载华为官方最新的 `HMSAgent` 自己进行集成,如果使用 demo 中的 module 需要修改以下几个地方: + +``` + + + + + + + + ... + +``` + +Demo 在集成华为推送时将调用华为推送的几个方法都放在了 `HMSPushHelper` 类中,开发者可以进行参考使用 + +配置完这些之后,在 `满足条件的华为设备` 上就可以使用华为推送接收离线推送通知了; 这里的满足条件是指:华为设备必须安装 2.6.+ 以上的华为移动服务,以及开启当前 App 的`自启动权限`; + +## 小米推送集成 + +小米推送需要在Android端导入小米推送的jar包,在清单AndroidManifest.xml里加上小米相关的权限和配置。并请参考Android端API文档对小米推送的appid和appkey进行设置。更多详情请参考小米官方文档。 + +服务器端证书配置请使用环信console后台。 + +## 魅族推送集成 + +魅族推送包含该两种推送类型:Flyme 推送和集成推送。二者的区别是:Flyme 推送是魅族自己的推送;集成推送除了有魅族自己的 Flyme 推送外还可以通过配置集成小米、华为等第三方推送。环信 SDK 内部使用的是 Flyme 推送[参考文档](http://open-wiki.flyme.cn/index.php?title=Flyme推送接入文档) + +**注意**:环信 SDK 从 **3.5.4** 版本开始支持 **魅族** 推送,如您使用的是之前版本的 SDK ,请先进行升级。 + +### 创建魅族应用 + +首先就是去魅族开发者后台创建应用,并开启 push 服务,并上传对应的证书指纹,具体可以看下魅族官方介绍:[ flyme 推送服务集成](http://open-wiki.flyme.cn/index.php?title=Flyme推送接入文档) + +### 上传推送证书 + +注册完整后,需要在[环信开发者后台](/document/v1/privatization/uc_configure.html#配置推送证书)上传推送证书,选择你的应用—>推送证书—>魅族—>新增证书,然后输入你在[ flyme 推送平台](http://push.meizu.com/#/config/app?appId=8843&_k=dnrz9k)创建的应用的`APP ID`和`APP SECRET`以及程序的`包名`; + +### 接入流程 + +1.在 app level/build.gradle 中添加 dependency : + +``` +dependencies{ +// 该aar托管在jcenter中,请确保当前项目已配置jcenter仓库。 +implementation 'com.meizu.flyme.internet:push-internal:3.7.0@aar' +} +``` + +2.在 AndroidManifest.xml 的 manifest 标签下添加: + +``` + + + + + + + + + + +``` + +3.在 AndroidManifest.xml 的 application 标签下添加: + +``` + + + + + + + + + + + + + + < /intent-filter> + + +``` + +4.启用魅族推送: + +``` +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); +builder.enableMeiZuPush(String appId,String appKey); +options.setPushConfig(builder.build()); +``` + +注意把上方的 APP ID 和 APP KEY 替换成开发者自己申请的内容。 + +注意:如果开发者自己集成了魅族Flame推送且实现了 MzPushMessageReceiver ,请把该父类替换为环信 SDK 提供的 EMMzMsgReceiver ,开发者自行判断业务逻辑,非开发者自有业务逻辑请通过 super 方法交给环信 SDK 处理。 + +## OPPO 推送集成 + +**注意**:环信 SDK 从 **3.5.4** 版本开始支持 **OPPO** 推送,如您使用的是之前版本的 SDK ,请先进行升级。`OPPO推送在2.1.0适配了android Q,在android Q上接收OPPO推送需要升级环信SDK到3.7.1以及之后的版本,并使用OPPO推送2.1.0的包。从3.9.1版本开始,升级OPPO推送版本到3.0.0` + +### 创建 OPPO 应用 + +首先就是去 OPPO 开发者后台创建应用,并开启 push 服务,并上传对应的证书指纹,具体可以看下 OPPO 官方介绍:[ OPPO 推送服务集成](https://open.oppomobile.com/wiki/doc#id=10195) + +### 上传推送证书 + +注册完整后,需要在[环信开发者后台](/document/v1/privatization/uc_configure.html#配置推送证书)上传推送证书,选择你的应用—>推送证书—>OPPO—>新增证书,然后输入你在[ OPPO 开发者后台](https://open.oppomobile.com/service/oms?service_id=1000004&app_type=app&app_id=30004346)创建的应用的`appkey`和`mastersecret`以及程序的`包名`; + +### 接入流程 + +由于申请 OPPO 推送的时候提交的环信 Android IM Demo 的包名被占用,所以更换为 com.hyphenate.chatuidemo.push ,使用环信 Android IM Demo 测试 OPPO 推送时,请更换 app level/build.gradle 中的 applicationId 。如果还配置了 Google FCM 推送,请同时替换google-services.json 中的 package_name 字段。 OPPO 设备安装应用后默认没有打开允许通知权限,测试前请先去设置中打开该应用的允许通知权限。 [OPPO推送官方文档](https://open.oppomobile.com/wiki/doc#id=10196) + +1.配置 OPPO 推送 jar 包: 去 OPPO 推送官网下载推送 SDK 包,把 jar 包放到 libs 目录下并 sync 。也可以直接使用环信 Android IM Demo 中集成的 OPPO 推送的jar 包。 + +2.在 AndroidManifest.xml 的 manifest 标签下添加: + +``` + + + + +``` + +3.在 AndroidManifest.xml 的 application 标签下添加: + +``` + + + + + + + + + + + + + + +``` + +4.启用 OPPO 推送: + +``` +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); +builder.enableOppoPush(String appKey,String appSecret); +options.setPushConfig(builder.build()); +``` + +注意把上方的 APP KEY 和 APP SECRET 替换成开发者自己申请的内容。 + +5.调用OPPO推送的初始化 + +``` +//OPPO SDK升级到2.1.0后需要进行初始化 +HeytapPushManager.init(context, true); +``` + +## VIVO 推送集成 + +**注意**:环信 SDK 从 **3.5.4** 版本开始支持 **VIVO** 推送,如您使用的是之前版本的 SDK ,请先进行升级。 Vivo 需要应用上架应用商店才能正式使用VIVO推送。`从3.9.1版本开始,升级Vivo推送版本到3.0.0.4_484。` `Vivo默认是推送运营消息,需要联系我们配置为系统消息(重新上传证书也需要重新配置)` + +### 创建 VIVO 应用 + +首先就是去 VIVO 开发者后台创建应用,并开启 push 服务,并上传对应的证书指纹,具体可以看下 VIVO 官方介绍:[ VIVO 推送服务集成](https://dev.vivo.com.cn/documentCenter/doc/281) + +### 上传推送证书 + +注册完整后,需要在[环信开发者后台](/document/v1/privatization/uc_configure.html#配置推送证书)上传推送证书,选择你的应用—>推送证书—>VIVO—>新增证书,然后输入你在[ VIVO 开发者后台](https://vpush.vivo.com.cn/#/appdetail)创建的应用的`APP ID`,`APP KEY`和`APP SECRET`以及程序的`包名`; + +### 接入流程 + +VIVO设备安装应用后默认没有打开允许通知权限,测试前请先去设置中打开该应用的允许通知权限。 [VIVO 推送官方文档](https://dev.vivo.com.cn/documentCenter/doc/158) + +1.配置 VIVO 推送 jar 包: 去 VIVO 推送官网下载推送 SDK 包,把 jar 包放到 libs 目录下并 sync 。也可以直接使用环信 Android IM Demo 中集成的 VIVO 推送的 jar 包。 + +2.在 AndroidManifest.xml 的 application 标签下添加: + +``` + + + + + + + + + + + + + + + + + + +``` + +3.启用 VIVO 推送: + +``` +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); +builder.enableVivoPush(); +options.setPushConfig(builder.build()); +``` + +注意:如果开发者自己集成了 VIVO 推送且实现了 OpenClientPushMessageReceiver ,请把该父类替换为环信 SDK 提供的 EMVivoMsgReceiver ,开发者自行判断业务逻辑,非开发者自有业务逻辑请通过 super 方法交给环信 SDK 处理。 + +## 解绑 token + +使用第三方推送时需要在退出登录时解绑设备 token,调用`EMClient#getInstance()#logout(true)`或者`EMClient#getInstance()#logout(true,callback)`方法,如果是被踢的情况下,则要求设置为 false。 + +------ + +## 推送的配置选项 + +用户可以在消息扩展中增加特定的字段来实现消息的推送配置。 + +### 发送静默消息(不推送) + +([Android 发消息](message)) + +``` +EMMessage message = EMMessage.createSendMessage(EMMessage.Type.TXT); +EMTextMessageBody txtBody = new EMTextMessageBody("test"); +message.setTo("6006"); +// 设置自定义扩展字段 +message.setAttribute("em_ignore_notification", true); +// 设置消息回调 +message.setMessageStatusCallback(new EMCallBack() {...}); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 强制推送 + +([Android 发消息](message)) + +``` +EMMessage message = EMMessage.createSendMessage(EMMessage.Type.TXT); +EMTextMessageBody txtBody = new EMTextMessageBody("test"); +message.setTo("6006"); +// 设置自定义扩展字段 +message.setAttribute("em_force_notification", true); +// 设置消息回调 +message.setMessageStatusCallback(new EMCallBack() {...}); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 自定义推送提示 + +([Android 发消息](message)) + +``` +// 这里只是一 TXT 消息为例,IMAGE FILE 等类型的消息设置方法相同 +EMMessage message = EMMessage.createSendMessage(EMMessage.Type.TXT); +EMTextMessageBody txtBody = new EMTextMessageBody("消息内容"); +message.setTo("6006"); +// 设置自定义推送提示 +JSONObject extObject = new JSONObject(); +try { + extObject.put("em_push_name", "离线推送标题"); + extObject.put("em_push_content", "离线推送内容部分"); +} catch (JSONException e) { + e.printStackTrace(); +} +// 将推送扩展设置到消息中 +message.setAttribute("em_apns_ext", extObject); +// 设置消息回调 +message.setMessageStatusCallback(new EMCallBack() {...}); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` \ No newline at end of file diff --git a/docs/document/v1/android/thread.md b/docs/document/v1/android/thread.md index 1dab017f1..8dd251a79 100644 --- a/docs/document/v1/android/thread.md +++ b/docs/document/v1/android/thread.md @@ -6,9 +6,6 @@ 如需查看消息相关内容,参见 [子区消息管理](thread_message.html)。 -:::notice -私有化版本不支持子区功能。 -::: ## 技术原理 @@ -28,9 +25,8 @@ 开始前,请确保满足以下条件: - 完成 3.9.3 或以上版本 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -- 了解子区和子区成员数量限制,详见 [使用限制](/product/limitation.html)。 -- 联系商务开通子区功能。 +- 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 私有部署已开通子区功能。 ## 实现方法 diff --git a/docs/document/v1/android/thread_message.md b/docs/document/v1/android/thread_message.md index 8feb4358a..6e3dfef20 100644 --- a/docs/document/v1/android/thread_message.md +++ b/docs/document/v1/android/thread_message.md @@ -31,8 +31,8 @@ - 已集成环信 IM 3.9.3 或以上版本的基本功能,账户登录成功。 - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -- 联系商务开通子区功能。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 私有部署已开通子区功能。 ## 实现方法 diff --git a/docs/document/v1/android/troubleshooting.md b/docs/document/v1/android/troubleshooting.md new file mode 100644 index 000000000..47e253d21 --- /dev/null +++ b/docs/document/v1/android/troubleshooting.md @@ -0,0 +1,311 @@ +# 离线推送问题排查 + +## 说明 + +开发者集成环信的 Android 离线推送时,可能会遇到离线推送收不到的问题。此文档旨在帮助开发者排查收不到离线推送的问题。环信目前提供了小米、华为、oppo、vivo、魅族,以及给海外用户使用的 FCM,下面我们来分析下集成离线推送可能出现的问题和排查的思路。 + +:::tip +集成推送前需要先在 *环信开发者后台* 上传推送证书。 +::: +## 华为推送 + +排查时先确认接入过程,华为推送首先需要开发者自己先集成好,测试调通之后再去接入环信。 + +接入环信的时候需要注意: + +1、在初始化环信之前去设置启用华为推送: + +``` +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); +builder.enableHWPush(); +options.setPushConfig(builder.build()); +``` + +2、在登录环信成功进入主界面之后再去连接华为移动服务,并获取华为推送 token。 + +3、在华为 PushReceiver 的 onToken 方法里去判断返回的推送 token 是否为空,不为空再去调用 EMClient.getInstance().sendHMSPushTokenToServer(token) 把推送 token 上传给环信。 + +:::tip +连接华为移动服务,并获取华为推送 token 这块的逻辑是必须放在环信登录成功之后再去执行,不然在登录之前就回调了 onToken 的话,后面环信账号登录成功就没法绑定推送 token 的。 +::: + +接入完成之后在 logcat 里看下登录之后的日志,通过检索 EMPushHelper 查看下华为推送 token 是否上传成功。 + +``` +//1、SDK 判断当前设备对应推送是否可用,false 代表对应推送不可用,true 代表对应推送可用。 +2019-09-02 10:50:35.972 5446-5475/? D/ONE SDK: [2019/09/02 10:50:35:971]: [EMPushHelper] isSupportPush: FCM - false +2019-09-02 10:50:35.981 5446-5475/? D/ONE SDK: [2019/09/02 10:50:35:977]: [EMPushHelper] isSupportPush: MIPUSH - false +2019-09-02 10:50:35.988 5446-5475/? D/ONE SDK: [2019/09/02 10:50:35:988]: [EMPushHelper] isSupportPush: HMSPUSH - true +2019-09-02 10:50:35.988 5446-5475/? D/ONE SDK: [2019/09/02 10:50:35:988]: [EMPushHelper] EMPushHelper register, prefer push type: HMSPUSH + +//2、获取到了华为返回的推送 token,这里的推送 token 可以在华为的推送后台去指定用户测试推送。 +2019-09-02 10:50:38.298 5446-5475/? D/ONE SDK: [2019/09/02 10:50:38:298]: [EMPushHelper] onReceiveToken: HMSPUSH - 0869379034831543200000121400CN01 + +2019-09-02 10:50:38.298 5446-5475/? D/ONE SDK: [2019/09/02 10:50:38:298]: [EMPushHelper] Retry upload after 5s if failed. +2019-09-02 10:50:38.298 5446-5475/? D/ONE SDK: [2019/09/02 10:50:38:298]: [EMPushHelper] Retry upload after 50s if failed. +2019-09-02 10:50:38.298 5446-5475/? D/ONE SDK: [2019/09/02 10:50:38:298]: [EMPushHelper] Retry upload after 262s if failed. + +//3、去上传推送 token,后面有对应的证书名称。 +2019-09-02 10:50:38.299 5446-5475/? D/ONE SDK: [2019/09/02 10:50:38:298]: [EMPushHelper] uploadTokenInternal, token=0869379034831543200000121400CN01, url=https://a4.easemob.com:443/easemob-demo/chatdemoui/users/omg4, notifier name=10492024 + +//4、推送 token 上传成功。 +2019-09-02 10:50:38.451 5446-5475/? D/ONE SDK: [2019/09/02 10:50:38:450]: [EMPushHelper] uploadTokenInternal success. +``` + +上面的是上传推送 token 成功的日志,可以对比你本地 logcat 里的日志,看下是否完整。(`需在初始化环信 SDK 的时候设置 EMClient.getInstance().setDebugMode(true) 才会有详细的日志输出`) + +1、如果在第一步判断当前设备推送,看到 HMSPUSH 是 false,那就是华为推送相关的没有配置好,需要检查下华为推送 jar 包是否依赖上,清单里是否配置好了华为相关的配置,尤其是 com.huawei.hms.client.appid,检查看看配置的格式、字段是否正确。并且要在初始化之前去设置好 EMPushConfig.Builder。 + +2、看 logcat 里的日志,如果 HMSPUSH 是 true,但是没有了之后的日志输出,那就是注册华为推送的时候出问题了,需要看下连接华为移动服务和注册华为推送 token 这块 API 返回的错误码,然后根据错误码排查。 + +这两步调试正常后,后面的上传推送 token 一般不会有问题(如果出现失败的情况,请提供手机本地的 log 文件反馈环信),之后可以去测试华为推送。测试推送的时候需要先把进程杀掉,首先在华为后台去单推消息,看 App 端是否可以收到(这里一般都是可以收到的,如果没有收到耐心等待几分钟,可能是华为那边推送有延迟,这个可以在华为的开发者群里核实下),然后再使用其他账号给当前的账号发消息测试。 + +**如果出现测试我们的离线推送没有收到,需检查以下两步:** + +1、是否有调用 EMClient.getInstance().pushManager().disableOfflinePush 设置离线推送免打扰时间。 + +2、如果是群组消息是否有调用 EMClient.getInstance().pushManager().updatePushServiceForGroup 去屏蔽群组离线推送。 + +如果以上两步都没有设置,需要提供消息内容、消息时间和接收方 ID 反馈给环信来查。 + +## 小米推送 + +首先可以检查小米的集成是否正确。小米推送的集成比较简单,导入小米推送的 jar 包,在清单 AndroidManifest.xml 里加上小米相关的权限和配置,如下为权限: + +``` + + + + + +``` + +配置: + +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +在初始化环信之前去设置上小米推送的 Appid 和 App Key: + +``` +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); +builder.enableMiPush(appid, appkey); +options.setPushConfig(builder.build()); +``` + +然后运行 App 去登录,查看 logcat 里的日志检索 EMPushHelper 确认下小米推送是否集成成功。 + +``` +//1、SDK 判断当前设备小米推送可用。 +2019-09-03 15:52:57.275 2984-3173/com.hyphenate.chatuidemo D/ONE SDK: [2019/09/03 15:52:57:275]: [EMPushHelper] isSupportPush: MIPUSH - true +2019-09-03 15:52:57.275 2984-3173/com.hyphenate.chatuidemo D/ONE SDK: [2019/09/03 15:52:57:275]: [EMPushHelper] EMPushHelper register, prefer push type: MIPUSH + +//2、获取到了小米返回的推送 token,这里的推送 token 就是小米推送的 regid。 +2019-09-03 15:52:57.725 2984-3173/com.hyphenate.chatuidemo D/ONE SDK: [2019/09/03 15:52:57:725]: [EMPushHelper] onReceiveToken: MIPUSH - Tn0uw0uGRoadNgW6TElcKCGiEwrMCo39nWomRxQU0+K+WlqvFmaHSn45vr9fLG3k + +2019-09-03 15:52:57.725 2984-3173/com.hyphenate.chatuidemo D/ONE SDK: [2019/09/03 15:52:57:725]: [EMPushHelper] Retry upload after 2s if failed. +2019-09-03 15:52:57.725 2984-3173/com.hyphenate.chatuidemo D/ONE SDK: [2019/09/03 15:52:57:725]: [EMPushHelper] Retry upload after 48s if failed. +2019-09-03 15:52:57.725 2984-3173/com.hyphenate.chatuidemo D/ONE SDK: [2019/09/03 15:52:57:725]: [EMPushHelper] Retry upload after 287s if failed. + +//3、去上传推送 token,后面有对应的证书名称。 +2019-09-03 15:52:57.726 2984-3173/com.hyphenate.chatuidemo D/ONE SDK: [2019/09/03 15:52:57:726]: [EMPushHelper] uploadTokenInternal, token=Tn0uw0uGRoadNgW6TElcKCGiEwrMCo39nWomRxQU0+K+WlqvFmaHSn45vr9fLG3k, url=https://a5-v2.easemob.com:443/easemob-demo/chatdemoui/users/omg4, notifier name=2882303761517426801 + +//4、推送 token 上传成功。 +2019-09-03 15:52:58.930 2984-3173/com.hyphenate.chatuidemo D/ONE SDK: [2019/09/03 15:52:58:930]: [EMPushHelper] uploadTokenInternal success. +``` + +上面的是上传推送 token 成功的日志,可以对比你本地 logcat 里的日志,看是否完整。(`需在初始化环信 SDK 的时候设置 EMClient.getInstance().setDebugMode(true) 才会有详细的日志输出`) + +1、如果在这一步看到 MIPUSH 是 false,那就是小米推送没有配置好,比如没有导入小米推送的 jar,清单里的权限和配置没有加上,或者就是没有在初始化之前去设置上小米推送的 Appid 和 App Key。 + +2、如果没有看到小米返回的推送 token 的日志,那应该会有输出 onErrorResponse: 后面会有小米那边返回的错误码,需根据错误码去排查; + +只要保证这两步是正常的,后面上传推送 token 的一般不会有问题,如果发现上传失败的情况,请反馈环信。然后在小米推送后台去使用 regid(regid 在第二步中获取)给设备推送消息,收到之后就可以杀掉进程去测试离线推送了。 + +**如果出现没有收到离线推送,需检查以下两步:** + +1、是否有调用 `EMClient.getInstance().pushManager().disableOfflinePush` 设置离线推送免打扰时间; + +2、如果是群组消息是否有调用 `EMClient.getInstance().pushManager().updatePushServiceForGroup` 屏蔽群组离线推送; + +如果以上两步都有设置,需要提供消息内容、消息时间和接收方 ID 反馈给环信来查。 + +## OPPO 推送 + +集成 OPPO 推送具体文件参考[OPPO推送集成](http://docs-im.easemob.com/im/android/push/thirdpartypush#oppo_推送集成) + +**集成 OPPO 推送时需要注意以下几点:** + +1、在环信开发者后台上传 OPPO 的推送证书时,需要填 OPPO 推送的 App Key 和 MasterSecret 以及程序的包名,MasterSecret 需要到[OPPO 推送平台](https://push.oppo.com/)-配置管理-应用配置 页面查看。 + +2、需要在手机通知管理里打开该应用的允许通知权限 + +3、在初始化环信之前去设置上 OPPO 推送的 App Key 和 AppSecret + +``` +EMPushConfig.Builder builder = new EMPushConfig.Builder(context); +builder.enableOppoPush(appKey,appSecret); +options.setPushConfig(builder.build()); +``` + +4、OPPO 给 8.0 系统之后的手机发推送需要设置通道 ID,环信这边推送给 OPPO 的时候会加上默认的通道 ID:“hyphenate_chatuidemo_notification”,如果需要指定准确的通道 ID 就需要在消息扩展里去设置项目本地使用的channelID + +``` +// 设置推送通道 ID +JSONObject extObject = new JSONObject(); +try { + extObject.put("em_push_channel_id", ”channelID“); +} catch (JSONException e) { + e.printStackTrace(); +} +// 将推送扩展设置到消息中 +message.setAttribute("em_apns_ext", extObject); +``` + +集成完成之后运行 App 去登录,在 logcat 里检索 EMPushHelper 查看日志确定是否集成成功 + +``` +//1、SDK判断当前设备OPPO推送可用 +2019-09-06 14:21:27.532 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:531]: [EMPushHelper] isSupportPush: FCM - false +2019-09-06 14:21:27.556 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:555]: [EMPushHelper] isSupportPush: MIPUSH - false +2019-09-06 14:21:27.575 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:575]: [EMPushHelper] isSupportPush: HMSPUSH - false +2019-09-06 14:21:27.592 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:592]: [EMPushHelper] isSupportPush: MEIZUPUSH - false +2019-09-06 14:21:27.610 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:610]: [EMPushHelper] isSupportPush: OPPOPUSH - true +2019-09-06 14:21:27.610 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:610]: [EMPushHelper] EMPushHelper register, prefer push type: OPPOPUSH + +//2、获取到了 OPPO 返回的推送 token +2019-09-06 14:21:27.805 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:805]: [EMPushHelper] onReceiveToken: OPPOPUSH - CN_724a57d2233d2363fbdeff46af095155 + +2019-09-06 14:21:27.805 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:805]: [EMPushHelper] Retry upload after 1s if failed. +2019-09-06 14:21:27.805 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:805]: [EMPushHelper] Retry upload after 14s if failed. +2019-09-06 14:21:27.806 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:806]: [EMPushHelper] Retry upload after 469s if failed. + +//3、去上传推送 token,后面有对应的证书名称 +2019-09-06 14:21:27.807 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:807]: [EMPushHelper] uploadTokenInternal, token=CN_724a57d2233d2363fbdeff46af095155, url=https://a1.easemob.com:443/easemob-demo/chatdemoui/users/omg4, notifier name=65872dc4c26a446a8f29014f758c8272 + +//4、推送 token 上传成功 +2019-09-06 14:21:27.934 7852-7912/com.hyphenate.chatuidemo.push D/ONE SDK: [2019/09/06 14:21:27:933]: [EMPushHelper] uploadTokenInternal success. +``` + +上面的是上传推送 token 成功的日志,可以对比你本地 logcat 里的日志,看下是否完整。(`需在初始化环信 SDK 的时候设置 EMClient.getInstance().setDebugMode(true) 才会有详细的日志输出`) + +1、如果在这一步看到 OPPOPUSH 是 false,那就是 OPPO 推送没有配置好,比如没有导入 OPPO 推送的 jar,清单里的配置没有加上,或者就是没有在初始化之前去设置上 OPPO 推送的 App Key 和 AppSecret。 + +2、如果没有看到 OPPO 返回的推送 token 的日志,那应该会有输出 onErrorResponse: 后面会有 OPPO 那边返回的错误码,需根据错误码去排查。 + +只要保证这两步是正常的,后面上传推送 token 的一般不会有问题,如果发现上传失败的情况,请反馈环信。然后在 OPPO 后台去使用推送 token (在第二步中获取)给设备推送消息,收到后可以杀掉进程去测试离线推送。 + +**如果出现没有收到离线推送,需检查以下两步:** + +1、是否有调用 `EMClient.getInstance().pushManager().disableOfflinePush` 设置离线推送免打扰时间。 + +2、如果是群组消息是否有调用 `EMClient.getInstance().pushManager().updatePushServiceForGroup` 屏蔽群组离线推送。 + +如果以上两步都有设置,需要提供消息内容、消息时间和接收方 ID 反馈给环信来查。 + +## VIVO 推送 + +集成 VIVO 推送具体文件参考[VIVO推送集成](http://docs-im.easemob.com/im/android/push/thirdpartypush#vivo_推送集成) + +**集成 VIVO 推送时需要注意以下几点:** + +1、测试的 VIVO 机型是否是支持 VIVO 推送的,详情可见[ VIVO 官网文档_支持机型和系统](https://dev.vivo.com.cn/documentCenter/doc/156) + +2、需要在手机通知管理里打开该应用的允许通知权限 + +集成完成之后运行 App 去登录,在 `logcat` 里检索 `EMPushHelper` 查看日志确定下是否集成成功。 + +``` +//1、SDK 判断当前设备 VIVO 推送可用 +2019-10-14 14:57:33.231 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:231]: [EMPushHelper] isSupportPush: FCM - false +2019-10-14 14:57:33.245 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:245]: [EMPushHelper] isSupportPush: MIPUSH - false +2019-10-14 14:57:33.258 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:258]: [EMPushHelper] isSupportPush: HMSPUSH - false +2019-10-14 14:57:33.272 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:272]: [EMPushHelper] isSupportPush: MEIZUPUSH - false +2019-10-14 14:57:33.288 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:288]: [EMPushHelper] isSupportPush: OPPOPUSH - false +2019-10-14 14:57:33.302 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:302]: [EMPushHelper] isSupportPush: VIVOPUSH - true +2019-10-14 14:57:33.303 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:303]: [EMPushHelper] EMPushHelper register, prefer push type: VIVOPUSH + +//2、获取到的 VIVO 返回的推送 token +2019-10-14 14:57:33.623 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:623]: [EMPushHelper] onReceiveToken: VIVOPUSH - 15665456497861102581637 +2019-10-14 14:57:33.623 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:623]: [EMPushHelper] Retry upload after 4s if failed. +2019-10-14 14:57:33.624 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:623]: [EMPushHelper] Retry upload after 9s if failed. +2019-10-14 14:57:33.624 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:624]: [EMPushHelper] Retry upload after 301s if failed. + +//3、去上传推送 token,后面有对应的证书名称 +2019-10-14 14:57:33.624 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:624]: [EMPushHelper] uploadTokenInternal, token=15665456497861102581637, url=https://a4.easemob.com:443/easemob-demo/chatdemoui/users/omg4, notifier name=11025#9b74dbfc-55c4-4441-9d0a-561ff21addc7 + +//4、推送 token 上传成功 +2019-10-14 14:57:33.760 24337-24437/com.hyphenate.chatuidemo D/ONE SDK: [2019/10/14 14:57:33:759]: [EMPushHelper] uploadTokenInternal success. +``` + +上面的是上传推送 token 成功的日志,可以对比你本地 logcat 里的日志,看下是否完整。(`需在初始化环信 SDK 的时候设置 EMClient.getInstance().setDebugMode(true) 才会有详细的日志输出`) + +1、如果在这一步看到 VIVOPUSH 是 false,那就是 VIVO 推送没有配置好,比如没有导入 VIVO 推送的 jar,清单里没有去配置 VIVO 的 Appid 和 App Key; + +2、如果没有看到 VIVO 返回的推送 token 的日志,那应该会有输出 `onErrorResponse`: 后面会有 VIVO 那边返回的错误码,需根据错误码去排查; + +只要保证这两步是正常的,后面上传推送 token 的一般不会有问题,如果发现上传失败的情况,请反馈环信。然后在 OPPO 后台去使用推送 token (在第二步中获取)给设备推送消息,收到后可以杀掉进程去测试离线推送。 + +如果出现没有收到离线推送,需检查以下两步: + +1、是否有调用 `EMClient.getInstance().pushManager().disableOfflinePush` 设置离线推送免打扰时间; + +2、如果是群组消息是否有调用 `EMClient.getInstance().pushManager().updatePushServiceForGroup` 屏蔽群组离线推送。 + +如果以上两步都有设置,需要提供消息内容、消息时间和接收方 ID 反馈给环信技术支持来查。 \ No newline at end of file diff --git a/docs/document/v1/android/user_relationship.md b/docs/document/v1/android/user_relationship.md index 5b72c3e38..875638ad8 100644 --- a/docs/document/v1/android/user_relationship.md +++ b/docs/document/v1/android/user_relationship.md @@ -1,173 +1,112 @@ -# 管理用户关系 +# 好友管理 - -用户登录后,可进行添加联系人、获取好友列表等操作。 +## 获取好友列表 -SDK 提供用户关系管理功能,包括好友列表管理和黑名单管理: +获取好友的 username list,开发者需要根据 username 去自己服务器获取好友的详情。 -- 好友列表管理:查询好友列表、申请添加好友、同意好友申请、拒绝好友申请和删除好友等操作。 -- 黑名单管理:查询黑名单列表、添加用户至黑名单以及将用户移除黑名单等操作。 - -本文介绍如何通过环信即时通讯 IM SDK 管理好友关系。 - -## 技术原理 - -环信即时通讯 IM Android SDK 提供 `EMContactManager` 类实现好友的添加移除,黑名单的添加移除等功能。主要方法如下: - -- `addContact` 申请添加好友。 -- `acceptInvitation` 同意好友申请。 -- `declineInvitation` 拒绝好友申请。 -- `deleteContact` 删除好友。 -- `getAllContactsFromServer` 从服务器获取好友列表。 -- `addUserToBlackList` 添加用户到黑名单。 -- `removeUserFromBlackList` 将用户从黑名单移除。 -- `getBlackListFromServer` 从服务器获取黑名单列表。 - -## 前提条件 - -开始前,请确保满足以下条件: - -- 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 - -## 实现方法 - -本节展示如何在项目中管理好友的添加移除和黑名单的添加移除。 - -### 管理好友列表 +``` +List usernames = EMClient.getInstance().contactManager().getAllContactsFromServer(); +``` -#### 添加好友 +## 查找好友 -添加好友部分主要功能是发送好友请求、接收好友请求、处理好友请求和好友请求处理结果回调等。 +SDK 不提供好友查找的服务,如需要查找好友,需要调用开发者自己服务器的用户查询接口。 -1. 申请指定用户添加好友 +为了保证查找到的好友可以添加,需要将开发者自己服务器的用户数据(用户的环信 ID),通过 SDK 的后台接口导入到环信服务器中。 -示例代码如下: +## 添加好友 -```java -// 添加好友。 -// 同步方法,会阻塞当前线程。异步方法为 asyncAddContact(String, String, EMCallBack)。 +``` +//参数为要添加的好友的username和添加理由 EMClient.getInstance().contactManager().addContact(toAddUsername, reason); ``` -2. 添加监听 +## 删除好友 -请监听与好友请求相关事件的回调,这样当用户收到好友请求,可以调用接受请求的 RESTful API 添加好友。服务器不会重复下发与好友请求相关的事件,建议退出应用时保存相关的请求数据。设置监听示例代码如下: - -```java -EMClient.getInstance().contactManager().setContactListener(new EMContactListener() { - // 对方同意了好友请求。 - @Override - public void onFriendRequestAccepted(String username) { } - - // 对方拒绝了好友请求。 - @Override - public void onFriendRequestDeclined(String username) { } +``` +EMClient.getInstance().contactManager().deleteContact(username); +``` - // 接收到好友请求。 - @Override - public void onContactInvited(String username, String reason) { } +## 同意好友请求 - // 联系人被删除。 - @Override - public void onContactDeleted(String username) { } +默认好友请求是自动同意的,如果要手动同意需要在初始化SDK时调用 `opptions.setAcceptInvitationAlways(false);` 。 - // 联系人已添加。 - @Override - public void onContactAdded(String username) { } -}); ``` - -3. 收到好友请求后,可以选择同意加好友申请或者拒绝加好友申请,示例代码如下: - -```java -// 同意好友申请。 -// 同步方法,会阻塞当前线程。异步方法为 asyncAcceptInvitation(String, EMCallBack)。 EMClient.getInstance().contactManager().acceptInvitation(username); -// 拒绝好友申请。 -// 同步方法,会阻塞当前线程。异步方法为 asyncDeclineInvitation(String, EMCallBack)。 -EMClient.getInstance().contactManager().declineInvitation(username); ``` -当你同意或者拒绝后,对方会通过好友事件回调,收到 `onContactAgreed` 或者 `onContactRefused`。 - -#### 删除好友 - -删除联系人时会同时删除对方联系人列表中的该用户,建议执行双重确认,以免发生误删操作。删除操作不需要对方同意或者拒绝。 - -示例代码如下: +## 拒绝好友请求 -```java -// 同步方法,会阻塞当前线程。 -// 异步方法为 asyncDeleteContact(String, EMCallBack)。 -EMClient.getInstance().contactManager().deleteContact(username); +``` +EMClient.getInstance().contactManager().declineInvitation(username); ``` -调用 `deleteContact` 删除好友后,对方会收到 `onContactDeleted` 回调。 - -#### 获取好友列表 - -你可以从服务器获取好友列表,也可以从本地数据库获取已保存的好友列表。 - -:::notice -需要从服务器获取好友列表之后,才能从本地数据库获取到好友列表。 -::: - -示例代码如下: +## 监听好友状态事件 -```java -// 从服务器获取好友列表。 -// 同步方法,会阻塞当前线程。异步方法为 asyncGetAllContactsFromServer(EMValueCallBack)。 -List usernames = EMClient.getInstance().contactManager().getAllContactsFromServer(); -// 从本地数据库获取好友列表。 -List usernames = EMClient.getInstance().contactManager().getContactsFromLocal(); +``` +EMClient.getInstance().contactManager().setContactListener(new EMContactListener() { + + @Override + public void onContactAgreed(String username) { + //好友请求被同意 + } + + @Override + public void onContactRefused(String username) { + //好友请求被拒绝 + } + + @Override + public void onContactInvited(String username, String reason) { + //收到好友邀请 + } + + @Override + public void onContactDeleted(String username) { + //被删除时回调此方法 + } + + + @Override + public void onContactAdded(String username) { + //增加了联系人时回调此方法 + } +}); ``` -### 管理黑名单 +## 黑名单 -黑名单是与好友无任何关系的独立体系。可以将任何用户加入黑名单,不论该用户与你是否是好友关系。 +### 从服务器获取黑名单列表 -黑名单功能包括加入黑名单,从黑名单移出用户和获取黑名单列表。对于获取黑名单,你可从服务器获取黑名单列表,也可从本地数据库获取已保存的黑名单列表。 +``` +EMClient.getInstance().contactManager().getBlackListFromServer(); +``` -#### 添加用户到黑名单 +### 从本地db获取黑名单列表 -你可以调用 `addUserToBlackList` 添加用户到黑名单。用户被加入黑名单后,无法向你发送消息,也无法发送好友申请。 +``` +EMClient.getInstance().contactManager().getBlackListUsernames(); +``` -用户可以将任何其他用户添加到黑名单列表,无论该用户是否是好友。好友被加入黑名单后仍在好友列表上显示。 +### 把用户加入到黑名单 -```java -// 同步方法,会阻塞当前线程。 -// 异步方法为 asyncAddUserToBlackList(String, boolean, EMCallBack)。 +``` +//true和false的效果一样,都是我能给黑名单的中用户发消息,但是对方发给我时我是收不到的 EMClient.getInstance().contactManager().addUserToBlackList(username,true); ``` -#### 将用户从黑名单移除 - -你可以调用 `removeUserFromBlackList` 将用户从黑名单移除,用户发送消息等行为将恢复。 +### 把用户从黑名单中移除 -```java -// 同步方法,会阻塞当前线程。 -// 异步方法为 asyncRemoveUserFromBlackList(String, EMCallBack)。 +``` EMClient.getInstance().contactManager().removeUserFromBlackList(username); ``` -#### 从服务器获取黑名单列表 +## 获取同一账号在其他端登录的id -你可以调用 `getBlackListFromServer` 从服务端获取黑名单列表。示例代码如下: +获取到该id 后可以用于不同端登录的账号之间互发消息,比如PC端与移动端可以互发消息。 -```java -// 同步方法,会阻塞当前线程。 -// 异步方法为 asyncGetBlackListFromServer(EMValueCallBack)。 -EMClient.getInstance().contactManager().getBlackListFromServer(); +``` +selfIds = EMClient.getInstance().contactManager().getSelfIdsOnOtherPlatform(); ``` -#### 从本地数据库获取黑名单列表 - -从服务器获取黑名单列表之后,才能从本地数据库获取到黑名单列表。 - -示例代码如下: - -```java -EMClient.getInstance().contactManager().getBlackListUsernames(); -``` \ No newline at end of file diff --git a/docs/document/v1/android/user_relationship_v.md b/docs/document/v1/android/user_relationship_v.md new file mode 100644 index 000000000..92b8b5e24 --- /dev/null +++ b/docs/document/v1/android/user_relationship_v.md @@ -0,0 +1,173 @@ +# 管理用户关系 + + + +用户登录后,可进行添加联系人、获取好友列表等操作。 + +SDK 提供用户关系管理功能,包括好友列表管理和黑名单管理: + +- 好友列表管理:查询好友列表、申请添加好友、同意好友申请、拒绝好友申请和删除好友等操作。 +- 黑名单管理:查询黑名单列表、添加用户至黑名单以及将用户移除黑名单等操作。 + +本文介绍如何通过环信即时通讯 IM SDK 管理好友关系。 + +## 技术原理 + +环信即时通讯 IM Android SDK 提供 `EMContactManager` 类实现好友的添加移除,黑名单的添加移除等功能。主要方法如下: + +- `addContact` 申请添加好友。 +- `acceptInvitation` 同意好友申请。 +- `declineInvitation` 拒绝好友申请。 +- `deleteContact` 删除好友。 +- `getAllContactsFromServer` 从服务器获取好友列表。 +- `addUserToBlackList` 添加用户到黑名单。 +- `removeUserFromBlackList` 将用户从黑名单移除。 +- `getBlackListFromServer` 从服务器获取黑名单列表。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 + +## 实现方法 + +本节展示如何在项目中管理好友的添加移除和黑名单的添加移除。 + +### 管理好友列表 + +#### 添加好友 + +添加好友部分主要功能是发送好友请求、接收好友请求、处理好友请求和好友请求处理结果回调等。 + +1. 申请指定用户添加好友 + +示例代码如下: + +```java +// 添加好友。 +// 同步方法,会阻塞当前线程。异步方法为 asyncAddContact(String, String, EMCallBack)。 +EMClient.getInstance().contactManager().addContact(toAddUsername, reason); +``` + +2. 添加监听 + +请监听与好友请求相关事件的回调,这样当用户收到好友请求,可以调用接受请求的 RESTful API 添加好友。服务器不会重复下发与好友请求相关的事件,建议退出应用时保存相关的请求数据。设置监听示例代码如下: + +```java +EMClient.getInstance().contactManager().setContactListener(new EMContactListener() { + // 对方同意了好友请求。 + @Override + public void onFriendRequestAccepted(String username) { } + + // 对方拒绝了好友请求。 + @Override + public void onFriendRequestDeclined(String username) { } + + // 接收到好友请求。 + @Override + public void onContactInvited(String username, String reason) { } + + // 联系人被删除。 + @Override + public void onContactDeleted(String username) { } + + // 联系人已添加。 + @Override + public void onContactAdded(String username) { } +}); +``` + +3. 收到好友请求后,可以选择同意加好友申请或者拒绝加好友申请,示例代码如下: + +```java +// 同意好友申请。 +// 同步方法,会阻塞当前线程。异步方法为 asyncAcceptInvitation(String, EMCallBack)。 +EMClient.getInstance().contactManager().acceptInvitation(username); +// 拒绝好友申请。 +// 同步方法,会阻塞当前线程。异步方法为 asyncDeclineInvitation(String, EMCallBack)。 +EMClient.getInstance().contactManager().declineInvitation(username); +``` + +当你同意或者拒绝后,对方会通过好友事件回调,收到 `onContactAgreed` 或者 `onContactRefused`。 + +#### 删除好友 + +删除联系人时会同时删除对方联系人列表中的该用户,建议执行双重确认,以免发生误删操作。删除操作不需要对方同意或者拒绝。 + +示例代码如下: + +```java +// 同步方法,会阻塞当前线程。 +// 异步方法为 asyncDeleteContact(String, EMCallBack)。 +EMClient.getInstance().contactManager().deleteContact(username); +``` + +调用 `deleteContact` 删除好友后,对方会收到 `onContactDeleted` 回调。 + +#### 获取好友列表 + +你可以从服务器获取好友列表,也可以从本地数据库获取已保存的好友列表。 + +:::notice +需要从服务器获取好友列表之后,才能从本地数据库获取到好友列表。 +::: + +示例代码如下: + +```java +// 从服务器获取好友列表。 +// 同步方法,会阻塞当前线程。异步方法为 asyncGetAllContactsFromServer(EMValueCallBack)。 +List usernames = EMClient.getInstance().contactManager().getAllContactsFromServer(); +// 从本地数据库获取好友列表。 +List usernames = EMClient.getInstance().contactManager().getContactsFromLocal(); +``` + +### 管理黑名单 + +黑名单是与好友无任何关系的独立体系。可以将任何用户加入黑名单,不论该用户与你是否是好友关系。 + +黑名单功能包括加入黑名单,从黑名单移出用户和获取黑名单列表。对于获取黑名单,你可从服务器获取黑名单列表,也可从本地数据库获取已保存的黑名单列表。 + +#### 添加用户到黑名单 + +你可以调用 `addUserToBlackList` 添加用户到黑名单。用户被加入黑名单后,无法向你发送消息,也无法发送好友申请。 + +用户可以将任何其他用户添加到黑名单列表,无论该用户是否是好友。好友被加入黑名单后仍在好友列表上显示。 + +```java +// 同步方法,会阻塞当前线程。 +// 异步方法为 asyncAddUserToBlackList(String, boolean, EMCallBack)。 +EMClient.getInstance().contactManager().addUserToBlackList(username,true); +``` + +#### 将用户从黑名单移除 + +你可以调用 `removeUserFromBlackList` 将用户从黑名单移除,用户发送消息等行为将恢复。 + +```java +// 同步方法,会阻塞当前线程。 +// 异步方法为 asyncRemoveUserFromBlackList(String, EMCallBack)。 +EMClient.getInstance().contactManager().removeUserFromBlackList(username); +``` + +#### 从服务器获取黑名单列表 + +你可以调用 `getBlackListFromServer` 从服务端获取黑名单列表。示例代码如下: + +```java +// 同步方法,会阻塞当前线程。 +// 异步方法为 asyncGetBlackListFromServer(EMValueCallBack)。 +EMClient.getInstance().contactManager().getBlackListFromServer(); +``` + +#### 从本地数据库获取黑名单列表 + +从服务器获取黑名单列表之后,才能从本地数据库获取到黑名单列表。 + +示例代码如下: + +```java +EMClient.getInstance().contactManager().getBlackListUsernames(); +``` \ No newline at end of file diff --git a/docs/document/v1/android/userprofile.md b/docs/document/v1/android/userprofile.md index 902df1dad..c3b164582 100644 --- a/docs/document/v1/android/userprofile.md +++ b/docs/document/v1/android/userprofile.md @@ -7,7 +7,7 @@ 用户属性指实时消息互动用户的信息,如用户昵称、头像、邮箱、电话、性别、签名、生日等。 例如,在招聘场景下,利用用户属性功能可以存储性别、邮箱、用户类型(面试者)、职位类型(web 研发)等。查看用户信息时,可以直接查询服务器存储的用户属性信息。 - + \ No newline at end of file diff --git a/docs/document/v1/applet/alipay.md b/docs/document/v1/applet/alipay.md index f8e2a1e96..3920f563a 100644 --- a/docs/document/v1/applet/alipay.md +++ b/docs/document/v1/applet/alipay.md @@ -4,7 +4,7 @@ ### 注册环信账号 -开发者需要在环信管理后台 [注册并创建应用](/product/enable_and_configure_IM.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 +开发者需要在环信管理后台 [注册并创建应用](/document/v1/privatization/uc_configure.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 ### 搭建支付宝小程序开发环境 @@ -14,8 +14,8 @@ 小程序在发布前,需要配置合法域名。 -登录 [支付宝开放平台](https://open.alipay.com/platform/home.htm), 配置以下服务器域名。 - +登录 [支付宝开放平台](https://open.alipay.com/platform/home.htm), 按私有部署文档中的 **2.2开通防火墙白名单** 配置各服务“地址:端口”。 + ### 说明 支付宝小程序:支付宝小程序在一段时间内只能保留一个 WebSocket 连接,如果当前已存在 WebSocket 连接,那么会自动关闭该连接,并重新创建一个新的 WebSocket 连接。 @@ -41,8 +41,8 @@ wss://im-api-alipay.easemob.com/websocket 可以通过以下两种方式获取 SDK: -- 通过官网[下载 SDK](https://www.easemob.com/download/im) -- 从环信的[github 仓库](https://github.com/easemob/webim-weixin-xcx/tree/master/src/sdk) 中获取 SDK 中的文件 + +- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx) 中获取 SDK 中的文件 #### 引入 SDK diff --git a/docs/document/v1/applet/baidu.md b/docs/document/v1/applet/baidu.md index 6c8c362ea..b03fef2f2 100644 --- a/docs/document/v1/applet/baidu.md +++ b/docs/document/v1/applet/baidu.md @@ -4,7 +4,7 @@ ### 注册环信账号 -开发者需要在环信管理后台 [注册并创建应用](/product/enable_and_configure_IM.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 +开发者需要在环信管理后台 [注册并创建应用](/document/v1/privatization/uc_configure.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 ### 搭建百度小程序开发环境 @@ -14,8 +14,8 @@ 小程序在发布前,需要配置合法域名。 -登录 [百度智能小程序官网](https://smartprogram.baidu.com/),在开发设置页面配置以下服务器域名。 - +登录 [百度智能小程序官网](https://smartprogram.baidu.com/),在开发设置页面配置按私有部署文档中的 **2.2开通防火墙白名单** 配置各服务“地址:端口”。。 + ### 说明 百度小程序注册主体不能为个人,必须为企业、媒体、政府等。 @@ -60,8 +60,8 @@ socket 合法域名: 可以通过以下两种方式获取 SDK: -- 通过官网 [下载 SDK](https://www.easemob.com/download/im) -- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx/tree/master/src/sdk) 中获取 SDK 中的文件 + +- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx) 中获取 SDK 中的文件 #### 引入 SDK diff --git a/docs/document/v1/applet/bytedance.md b/docs/document/v1/applet/bytedance.md index 5f10d4c59..c2cd50c89 100644 --- a/docs/document/v1/applet/bytedance.md +++ b/docs/document/v1/applet/bytedance.md @@ -4,7 +4,7 @@ ### 注册环信账号 -开发者需要在环信管理后台 [注册并创建应用](/product/enable_and_configure_IM.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 +开发者需要在环信管理后台 [注册并创建应用](/document/v1/privatization/uc_configure.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 ### 搭建字节跳动小程序开发环境 @@ -14,8 +14,8 @@ 小程序在发布前,需要配置合法域名。 -登录字节跳动小程序 [开发者平台](https://microapp.bytedance.com/),选择当前小程序(如果没有需要创建一个小程序),进入 “开发管理>开发设置” 页面配置以下服务器地址。 - +登录字节跳动小程序 [开发者平台](https://microapp.bytedance.com/),选择当前小程序(如果没有需要创建一个小程序),进入 “开发管理>开发设置” 页面按私有部署文档中的 **2.2开通防火墙白名单** 配置各服务“地址:端口”。 + ### 集成 SDK #### 下载 SDK 可以通过以下两种方式获取 SDK: -- 通过官网 [下载 SDK](https://www.easemob.com/download/im) -- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx/tree/master/src/sdk) 中获取 SDK 中的文件 + +- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx) 中获取 SDK 中的文件 #### 引入 SDK diff --git a/docs/document/v1/applet/initialization.md b/docs/document/v1/applet/initialization.md index 3934058b8..af1f689c2 100644 --- a/docs/document/v1/applet/initialization.md +++ b/docs/document/v1/applet/initialization.md @@ -6,7 +6,7 @@ ## 前提条件 -开始前,请注册有效的环信即时通讯 IM 开发者账号且获得 App key,见 [环信即时通讯云管理后台](https://console.easemob.com/user/login)。 +开始前,请注册有效的环信即时通讯 IM 开发者账号且获得 App key,见 [环信即时通讯云管理后台](/document/v1/privatization/uc_configure.html)。 ## 引入 SDK @@ -55,15 +55,15 @@ const conn = new EC.connection({ ### 控制台注册 -登录[环信即时通讯云控制台](https://console.easemob.com/user/login),选择**即时通讯** > **运营服务** > **用户管理**,创建 IM 用户。 +登录[环信即时通讯云控制台](/document/v1/privatization/uc_configure.html),选择**运营服务** > **用户管理**,创建 IM 用户。 ### REST API 注册 -请参考 [注册用户](/document/server-side/account_system.html#注册用户)。 +请参考 [注册用户](/document/v1/server-side/account_system.html#注册用户)。 ### SDK 注册 -若支持 SDK 注册,需登录[环信即时通讯云控制台](https://console.easemob.com/user/login),选择 **即时通讯** > **服务概览**,将 **设置**下的 **用户注册模式** 设置为 **开放注册**。 +若支持 SDK 注册,需登录[环信即时通讯云控制台](/document/v1/privatization/uc_configure.html),选择 **应用概览** > **应用详情**,将 **应用设置**下的 **用户注册模式** 设置为 **开放注册**。 ```javascript conn @@ -87,7 +87,7 @@ SDK 不支持自动登录,只支持通过以下方式手动登录: - 用户 ID + 密码 - 用户 ID + token -登录时传入的用户 ID 必须为 String 类型,支持的字符集详见[用户注册的 RESTful 接口](/document/server-side/account_system.html#注册用户)。 +登录时传入的用户 ID 必须为 String 类型,支持的字符集详见[用户注册的 RESTful 接口](/document/v1/server-side/account_system.html#注册用户)。 调用登录接口后,收到 `onConnected` 回调表明 SDK 与环信服务器连接成功。 @@ -109,7 +109,7 @@ conn }); ``` -**用户 ID + token** 是更加安全的登录方式。token 可以通过调用 REST API 获取,详见 [环信用户 token 的获取](/product/easemob_user_token.html)。 +**用户 ID + token** 是更加安全的登录方式。token 可以通过调用 REST API 获取,详见 [环信用户 token 的获取](/document/v1/server-side/easemob_user_token.html)。 :::notice 使用 token 登录时需要处理 token 过期的问题,比如在每次登录时更新 token 等机制。 diff --git a/docs/document/v1/applet/message_send_receive.md b/docs/document/v1/applet/message_send_receive.md index 5760c5aae..17ebc1a7a 100644 --- a/docs/document/v1/applet/message_send_receive.md +++ b/docs/document/v1/applet/message_send_receive.md @@ -38,7 +38,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 @@ -160,7 +160,7 @@ WebIM.conn.addEventHandler("eventName", { ### 撤回消息 -发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在[环信即时通讯云控制台](https://console.easemob.com/user/login)的**功能配置** > **功能配置总览** > **基础功能** 页面设置消息撤回时长,该时长不超过 7 天。 +发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在 环信即时通讯云控制台的**服务管理** > **服务概览** 页面设置消息撤回时长,该时长不超过 7 天。 ```javascript let option = { diff --git a/docs/document/v2/applet/multi_device .md b/docs/document/v1/applet/multi_device.md similarity index 85% rename from docs/document/v2/applet/multi_device .md rename to docs/document/v1/applet/multi_device.md index 54808dcec..e9622cc4d 100644 --- a/docs/document/v2/applet/multi_device .md +++ b/docs/document/v1/applet/multi_device.md @@ -6,13 +6,10 @@ - 在线消息、离线消息以及对应的回执和已读状态; - 好友和群组操作; -- 子区相关操作。 - -环信服务器提供接口查询每个账号已登录设备列表以及[将账号从已登录设备强制下线](account_system.html#强制下线)。 多端登录时,即时通讯 IM 每端默认最多支持 4 个设备同时在线。如需增加支持的设备数量,可以联系环信即时通讯 IM 的商务经理。 -你可以在环信控制台的**功能配置** > **功能配置总览**页面的**基础功能**页签下点击**多端多设备在线**操作栏中的**设置**,在弹出的对话框中设置设置各端设备的数量: +你可以在环信控制台的**服务管理** > **服务概览**页面的下点击**多端多设备在线**操作栏中的**设置**,在弹出的对话框中设置设置各端设备的数量: ![img](@static/images/common/multidevice_device_count.png) @@ -25,7 +22,7 @@ - +
@@ -39,7 +36,7 @@ - +
单端/多端登录
多端登录若一端的登录设备数量达到了上限,最新登录的设备会将该端最早登录的设备踢下线。<br/>即时通讯 IM 仅支持同端互踢,不支持各端之间互踢。若一端的登录设备数量达到了上限,最新登录的设备会将该端最早登录的设备踢下线。
即时通讯 IM 仅支持同端互踢,不支持各端之间互踢。
@@ -57,7 +54,7 @@ 你需要调用 `addEventHandler` 方法注册监听事件,监听其他设备上的操作。服务器同步信息之后,SDK 会回调这些事件,小程序端与其他端均会收到好友和群组相关操作的通知。 对于好友和群组的相关操作来说,多设备事件与单设备事件的名称相同,唯一区别在于事件中的 `from` 字段,即多端多设备事件中该字段的值为当前用户的用户 ID,而单设备事件中,该字段的值为操作方的用户 ID。详见[群组事件](group_manage.html#监听群组事件)和[用户关系事件](user_relationship.html#添加好友)。 - + \ No newline at end of file diff --git a/docs/document/v1/applet/overview.md b/docs/document/v1/applet/overview.md index d30df01c2..e0b97d066 100644 --- a/docs/document/v1/applet/overview.md +++ b/docs/document/v1/applet/overview.md @@ -8,6 +8,7 @@ SDK 目前支持微信、QQ、百度小程序、字节跳动、uni-app 编译的原生 Android 以及 iOS。 ::: + ## 功能说明 环信小程序 Web IM 在微信生态系统进行优化,功能与微信对接更为流畅: diff --git a/docs/document/v1/applet/qq.md b/docs/document/v1/applet/qq.md index be8c7b2d5..625113f42 100644 --- a/docs/document/v1/applet/qq.md +++ b/docs/document/v1/applet/qq.md @@ -6,7 +6,7 @@ ### 注册环信账号 -开发者需要在环信管理后台 [注册并创建应用](/product/enable_and_configure_IM.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 +开发者需要在环信管理后台 [注册并创建应用](/document/v1/privatization/uc_configure.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 ## 实现步骤 @@ -18,8 +18,8 @@ 小程序在发布前,需要配置合法域名。 -登录 QQ 小程序 [开发者平台](https://q.qq.com/),进入 “开发 > 开发设置” 页面配置以下服务器地址。 - +登录 QQ 小程序 [开发者平台](https://q.qq.com/),进入 “开发 > 开发设置” 页面按私有部署文档中的 **2.2开通防火墙白名单** 配置各服务“地址:端口”。 + ### 说明 QQ、微信小程序: 1.7.0 及以上版本,最多可以同时存在 5 个 WebSocket 连接,需开发者控制好连接数量,超出此限制 SDK 将不能连接上服务器。 @@ -64,8 +64,8 @@ QQ、微信小程序: 1.7.0 及以上版本,最多可以同时存在 5 个 W 可以通过以下两种方式获取 SDK: -- 通过官网 [下载 SDK](https://www.easemob.com/download/im) -- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx/tree/master/src/sdk) 中获取 SDK 中的文件 + +- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx) 中获取 SDK 中的文件 #### 引入 SDK diff --git a/docs/document/v1/applet/releasenote.md b/docs/document/v1/applet/releasenote.md index 7927ddbe9..f2aec20b3 100644 --- a/docs/document/v1/applet/releasenote.md +++ b/docs/document/v1/applet/releasenote.md @@ -1,7 +1,7 @@ # 小程序 SDK 更新日志 - + ## 版本:v3.6.3 2021-07-30 - [IM SDK] 增加下载文件验证 secret 功能 diff --git a/docs/document/v1/applet/serverconfig.md b/docs/document/v1/applet/serverconfig.md index c17507370..540535ff5 100644 --- a/docs/document/v1/applet/serverconfig.md +++ b/docs/document/v1/applet/serverconfig.md @@ -25,13 +25,12 @@ ![img](@static/images/applet/config5.png) -7. 登陆环信后台获取 socket 域名,进入即时通讯-服务概览页,即可看到如图的域名展示。 +7. 按私有部署文档中的 **2.2开通防火墙白名单** 配置各服务“地址:端口”。。 :::notice 字节跳动小程序、QQ 小程序、百度小程序、uniapp 全平台等同微信小程序的域名一致,使用微信小程序栏的域名即可。 ::: -![img](@static/images/applet/config6.png) 8. 填写完域名信息之后,点击下面 “保存并提及” 按钮即可设置完成。 diff --git a/docs/document/v1/applet/uniapp.md b/docs/document/v1/applet/uniapp.md index 668e372bf..b757ec9b8 100644 --- a/docs/document/v1/applet/uniapp.md +++ b/docs/document/v1/applet/uniapp.md @@ -17,7 +17,7 @@ SDK 目前支持微信、QQ、百度小程序、字节跳动(请使用低于 1 :::notice - 小程序 Demo 只包含部分 IM 功能,详细参考 **功能说明**。 -- Uni-app Demo Git 源码地址 [https://github.com/easemob/webim-uniapp-demo](https://github.com/easemob/webim-uniapp-demo) +- 下载Uni-app Demo 源码地址 [立即下载](https://downloadsdk.easemob.com/mp/downloads/sdk/private-uniapp-20230918.zip) ::: ## 功能说明 @@ -32,7 +32,7 @@ SDK 目前支持微信、QQ、百度小程序、字节跳动(请使用低于 1 ### 集成前准备 -[注册并创建应用](/product/enable_and_configure_IM.html#创建应用) +[注册并创建应用](/document/v1/privatization/uc_configure.html#创建应用) ### 搭建开发环境 @@ -45,6 +45,7 @@ SDK 目前支持微信、QQ、百度小程序、字节跳动(请使用低于 1 ### 配置服务器域名(以微信为例) + +登录 [微信公众平台](https://mp.weixin.qq.com/),进入 “开发 > 开发设置” 页面,按私有部署文档中的 **2.2开通防火墙白名单** 配置各服务“地址:端口”。 + ### 各端小程序 WebSocket 连接数量 - QQ、微信小程序: `**1.7.0**` 及以上版本,最多可以同时存在 **5** 个 WebSocket 连接 @@ -103,7 +104,7 @@ socket 合法域名: 可以通过以下方式获取 SDK: -- 从环信的 [github 仓库](https://github.com/easemob/webim-uniapp-demo/tree/master/newSDK) 中获取 SDK 中的文件,从 3.3.1 开始支持 uniapp。 +- 从环信的 [Demo包](https://downloadsdk.easemob.com/mp/downloads/sdk/private-uniapp-20230918.zip) 中获取 SDK 中的文件,从 3.3.1 开始支持 uniapp。 #### 引入 SDK diff --git a/docs/document/v1/applet/uniappnativeapp.md b/docs/document/v1/applet/uniappnativeapp.md index a97da9d39..5e1572ba5 100644 --- a/docs/document/v1/applet/uniappnativeapp.md +++ b/docs/document/v1/applet/uniappnativeapp.md @@ -6,14 +6,9 @@ ## 体验 IM 应用 -- 安卓: [https://www.pgyer.com/h4XF](https://www.pgyer.com/h4XF) -- iOS: [https://www.pgyer.com/9ISC](https://www.pgyer.com/9ISC) +- 小程序 Demo 只包含部分 IM 功能,详细参考 **功能说明**。 +- 下载Uni-app Demo 源码地址 [立即下载](https://downloadsdk.easemob.com/mp/downloads/sdk/private-uniapp-20230918.zip) -:::notice - -- Demo 只包含部分 IM 功能,详细参考 **功能说明** -- Uni-app Demo Git 源码地址 [https://github.com/easemob/webim-uniapp-demo](https://github.com/easemob/webim-uniapp-demo) - ::: ## 功能说明 @@ -24,7 +19,7 @@ ## 开发者集成 -[注册并创建应用](/product/enable_and_configure_IM.html#创建应用) +[注册并创建应用](/document/v1/privatization/uc_configure.html#创建应用) ### 搭建 app 开发环境 @@ -82,7 +77,7 @@ WebIM.conn = new WebIM.connection({ }); ``` -IM 基本功能,请参考 [消息管理](/document/web/message_overview.html)。 +IM 基本功能,请参考 [消息管理](/document/v1/web/message_overview.html)。 ## 打包发布 diff --git a/docs/document/v1/applet/wechat.md b/docs/document/v1/applet/wechat.md index 7edbd9b61..c8d8390a5 100644 --- a/docs/document/v1/applet/wechat.md +++ b/docs/document/v1/applet/wechat.md @@ -4,7 +4,7 @@ ### 注册环信账号 -开发者需要在环信管理后台 [注册并创建应用](/product/enable_and_configure_IM.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 +开发者需要在环信管理后台 [注册并创建应用](/document/v1/privatization/uc_configure.html#创建应用),来获取唯一 appKey,SDK 初始化时需要配置 appKey。 ### 搭建微信小程序开发环境 @@ -14,8 +14,8 @@ 小程序在发布前,需要配置合法域名。 -登录[微信公众平台](https://mp.weixin.qq.com/), 在开发设置页面配置以下服务器域名。 - +登录[微信公众平台](https://mp.weixin.qq.com/), 在开发设置页面按私有部署文档中的 **2.2开通防火墙白名单** 配置各服务“地址:端口”。 + ### 集成 SDK #### 下载 SDK 可以通过以下两种方式获取 SDK: -- 通过官网 [下载 SDK](https://www.easemob.com/download/im) -- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx/tree/master/src/sdk) 中获取 SDK 中的文件 + +- 从环信的 [github 仓库](https://github.com/easemob/webim-weixin-xcx) 中获取 SDK 中的文件 #### 引入 SDK diff --git a/docs/document/v1/ios/chatroom.md b/docs/document/v1/ios/chatroom.md new file mode 100644 index 000000000..beb037833 --- /dev/null +++ b/docs/document/v1/ios/chatroom.md @@ -0,0 +1,720 @@ +# 聊天室管理 + +:::notice +客户端SDK不支持创建聊天室,可以调用REST接口来创建 +::: + +聊天室管理主要涉及到的环信SDK头文件如下: + +``` +// 聊天室部分,有聊天室id等属性 +EMChatroom.h + +// 聊天室方法调用部分,比如添加代理,移除代理,获取聊天室等 +IEMChatroomManager.h + +// 聊天室的协议回调方法部分,比如监听有用户加群的回调方法等 +EMChatroomManagerDelegate.h +``` + +环信聊天室模型默认最大成员数为5000,和群组不同,聊天室内成员离线2分钟后,服务器会将此成员踢出聊天室,不会再给此成员发推送,上线后无法自动进入聊天室。聊天室成员数可调整,请联系商务。 + +- 默认支持最大成员数5000,调整请联系商务; +- 环信的聊天室内有所有者,管理员和游客三种身份; +- 支持禁言,黑名单,踢人等操作; +- 不支持客户端邀请; +- 不支持 REST 邀请。 +- 聊天室API通常是同步操作,需要在单独的线程中执行,如需使用异步API,请使用async前缀对应的API + +环信聊天室客户端的主要特性包括: + +- 支持查询所有 APP 聊天室; +- 支持查询聊天室详情; +- 加入聊天室; +- 退出聊天室; + +### 服务器端API + +服务器端聊天室有关的 REST 操作请参考[聊天室管理](/document/v1/server-side/chatroom.html)。 + +### 分页获取聊天室列表 + +``` +/*! + * 从服务器获取指定数目的聊天室 + * + * @param aPageNum 获取第几页 + * @param aPageSize 获取多少条 + * @param aCompletionBlock 完成的回调 + */ + +- (void)getChatroomsFromServerWithPage:(NSInteger)aPageNum + pageSize:(NSInteger)aPageSize + completion:(void (^)(EMPageResult *aResult, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager getChatroomsFromServerWithPage:0 pageSize:50 completion:^(EMPageResult *aResult, EMError *aError) { + if (!aError) { + NSLog(@"从服务器获取指定数目的聊天室成功"); + } else { + NSLog(@"从服务器获取指定数目的聊天室失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 加入聊天室 + +``` +/*! + * 加入聊天室 + * + * @param aChatroomId 聊天室的ID + * @param aCompletionBlock 完成的回调 + */ +- (void)joinChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager joinChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"加入聊天室成功"); + } else { + NSLog(@"加入聊天室失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 离开聊天室 + +``` +/*! + * 退出聊天室 + * + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)leaveChatroom:(NSString *)aChatroomId + completion:(void (^)(EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager leaveChatroom:@"chatroomId" completion:^(EMError *aError) { + if (!aError) { + NSLog(@"退出聊天室成功"); + } else { + NSLog(@"退出聊天室失败的原因 --- %@", aError.errorDescription); + } +}]; +离开聊天室时,SDK默认会删除此聊天室本地所有消息,如果不想删除,可以设置以下属性为NO +/*! + * \~chinese + * 离开聊天室时是否删除所有消息, 默认为YES + * + * \~english + * Whether to delete all the chat room messages when leaving the chat room, default is YES + */ +@property (nonatomic, assign) BOOL isDeleteMessagesWhenExitChatRoom; + +// 调用: +EMOptions *retOpt = [EMOptions optionsWithAppkey:@"appkey"]; +retOpt.isDeleteMessagesWhenExitChatRoom = NO; +``` + +### 获取聊天室详情 + +``` +/*! + * 获取聊天室详情 + * + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + * + */ +- (void)getChatroomSpecificationFromServerWithId:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager getChatroomSpecificationFromServerWithId:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"获取聊天室详情成功"); + } else { + NSLog(@"获取聊天室详情失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 分页获取聊天室成员列表 + +``` +/*! + * 获取聊天室成员列表 + * + * @param aChatroomId 聊天室ID + * @param aCursor 游标 + * @param aPageSize 获取多少条 + * @param aCompletionBlock 完成的回调 + */ +- (void)getChatroomMemberListFromServerWithId:(NSString *)aChatroomId + cursor:(NSString *)aCursor + pageSize:(NSInteger)aPageSize + completion:(void (^)(EMCursorResult *aResult, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager getChatroomMemberListFromServerWithId:@"chatroomId" cursor:@"cursor" pageSize:50 completion:^(EMCursorResult *aResult, EMError *aError) { + if (!aError) { + // EMCursorResult类中有游标属性 + NSLog(@"获取聊天室成员列表成功"); + } else { + NSLog(@"获取聊天室成员列表失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 分页获取聊天室黑名单列表 + +需要Owner或Admin权限 + +``` +/*! + * 获取聊天室黑名单列表, 需要owner/admin权限 + * + * @param aChatroomId 聊天室ID + * @param aPageNum 获取第几页 + * @param aPageSize 获取多少条 + * @param aCompletionBlock 完成的回调 + */ +- (void)getChatroomBlacklistFromServerWithId:(NSString *)aChatroomId + pageNumber:(NSInteger)aPageNum + pageSize:(NSInteger)aPageSize + completion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager getChatroomBlacklistFromServerWithId:@"chatroomId" pageNumber:1 pageSize:50 completion:^(NSArray *aList, EMError *aError) { + if (!aError) { + NSLog(@"获取聊天室黑名单列表成功"); + } else { + NSLog(@"获取聊天室黑名单列表失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 分页获取聊天室禁言列表 + +``` +/*! + * 获取聊天室被禁言列表 + * + * @param aChatroomId 聊天室ID + * @param aPageNum 获取第几页 + * @param aPageSize 获取多少条 + * @param aCompletionBlock 完成的回调 + */ +- (void)getChatroomMuteListFromServerWithId:(NSString *)aChatroomId + pageNumber:(NSInteger)aPageNum + pageSize:(NSInteger)aPageSize + completion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager getChatroomMuteListFromServerWithId:@"chatroomId" pageNumber:1 pageSize:50 completion:^(NSArray *aList, EMError *aError) { + if (!aError) { + NSLog(@"获取聊天室被禁言列表成功"); + } else { + NSLog(@"获取聊天室被禁言列表失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 更新聊天室名称 + +需要Owner权限 + +``` +/*! + * 更改聊天室主题, 需要owner权限 + * + * @param aSubject 新主题 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)updateSubject:(NSString *)aSubject + forChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager updateSubject:@"newSubject" forChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"更改聊天室主题成功"); + } else { + NSLog(@"更改聊天室主题失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 更新聊天室说明 + +需要Owner权限 + +``` +/*! + * 更改聊天室说明信息, 需要owner权限 + * + * @param aDescription 说明信息 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)updateDescription:(NSString *)aDescription + forChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager updateDescription:@"newDescription" forChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"更改聊天室说明信息成功"); + } else { + NSLog(@"更改聊天室说明信息失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 获取聊天室公告 + +``` +/*! + * 获取聊天室公告 + * + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)getChatroomAnnouncementWithId:(NSString *)aChatroomId + completion:(void (^)(NSString *aAnnouncement, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager getChatroomAnnouncementWithId:@"chatroomId" completion:^(NSString *aAnnouncement, EMError *aError) { + if (!aError) { + NSLog(@"获取聊天室公告成功"); + } else { + NSLog(@"获取聊天室公告失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +也可以通过聊天室监听接口来获取聊天室公告的消息推送。见[聊天室相关的回调](http://docs-im.easemob.com/im/ios/basics/chatroom#聊天室相关的回调) + +### 更新聊天室公告 + +``` +/*! + * 修改聊天室公告,需要Owner / Admin权限 + * + * @param aChatroomId 聊天室ID + * @param aAnnouncement 群公告 + * @param aCompletionBlock 完成的回调 + */ +- (void)updateChatroomAnnouncementWithId:(NSString *)aChatroomId + announcement:(NSString *)aAnnouncement + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager updateChatroomAnnouncementWithId:@"chatroomId" announcement:@"newAnnouncement" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"修改聊天室公告成功"); + } else { + NSLog(@"修改聊天室公告失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +聊天室owner/Admin修改聊天室公告时,其它成员会收到聊天室公告有更新的通知 + +``` +/*! + * 聊天室公告有更新 + * + * @param aChatroom 聊天室 + * @param aAnnouncement 公告 + */ +- (void)chatroomAnnouncementDidUpdate:(EMChatroom *)aChatroom + announcement:(NSString *)aAnnouncement; +``` + +### 开启和关闭全员禁言 + +owner和管理员可以开启和关闭全员禁言。 + +``` +/*! + * \~chinese + * 设置全员禁言,需要Owner / Admin权限 + * + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)muteAllMembersFromChatroom:(NSString *)aChatroomId + completion:(void(^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + + +/*! + * \~chinese + * 解除全员禁言,需要Owner / Admin权限 + * + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)unmuteAllMembersFromChatroom:(NSString *)aChatroomId + completion:(void(^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; +``` + +### 白名单管理 + +可以将用户添加到白名单中,用户白名单在管理员开启了全员禁言时生效,可以运行白名单用户发出消息。 另外可以将用户移出白名单,检查自己是否在白名单中以及获取白名单列表。 + +``` +/*! + * \~chinese + * 添加白名单,需要Owner / Admin权限 + * + * @param aMembers 被添加的列表 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)addWhiteListMembers:(NSArray *)aMembers + fromChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +/*! + * \~chinese + * 移除白名单,需要Owner / Admin权限 + * + * @param aMembers 被移除的列表 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)removeWhiteListMembers:(NSArray *)aMembers + fromChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + + +/*! + * \~chinese + * 查看自己是否在聊天室白名单中 + * + * @param aChatroomId 聊天室ID + * @param pError 错误信息 + */ +- (BOOL)isMemberInWhiteListFromServerWithChatroomId:(NSString *)aChatroomId + error:(EMError **)pError; + + +/*! + * \~chinese + * 获取聊天室白名单列表 + * + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)getChatroomWhiteListFromServerWithId:(NSString *)aChatroomId + completion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; +``` + +### 将成员移出聊天室 + +需要Owner或Admin权限 + +``` +/*! + * 将成员移出聊天室, 需要owner/admin权限 + * + * @param aMembers 要移出的用户列表 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)removeMembers:(NSArray *)aMembers + fromChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager removeMembers:@[@"username"] fromChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"将成员移出聊天室成功"); + } else { + NSLog(@"将成员移出聊天室失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 将用户加到聊天室黑名单 + +需要Owner或Admin权限 + +``` +/*! + * 加人到聊天室黑名单 + * + * @param aMembers 要加入黑名单的用户 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)blockMembers:(NSArray *)aMembers + fromChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager blockMembers:@[@"username"] fromChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"加人到聊天室黑名单成功"); + } else { + NSLog(@"加人到聊天室黑名单失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 将用户移出聊天室黑名单 + +需要Owner或Admin权限 + +``` +/*! + * 从聊天室黑名单中减人 + * + * @param aMembers 要从黑名单中移除的用户名列表 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)unblockMembers:(NSArray *)aMembers + fromChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager unblockMembers:@[@"username"] fromChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"从聊天室黑名单中减人成功"); + } else { + NSLog(@"从聊天室黑名单中减人失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 改变聊天室创建者 + +需要Owner权限 + +``` +/*! + * 改变聊天室创建者,需要Owner权限 + * + * @param aChatroomId 聊天室ID + * @param aNewOwner 新Owner + * @param aCompletionBlock 完成的回调 + */ +- (void)updateChatroomOwner:(NSString *)aChatroomId + newOwner:(NSString *)aNewOwner + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager updateChatroomOwner:@"chatroomId" newOwner:@"newOwner" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"改变聊天室创建者成功"); + } else { + NSLog(@"改变聊天室创建者失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 添加聊天室管理员 + +需要Owner权限 + +``` +/*! + * 添加聊天室管理员,需要Owner权限 + * + * @param aAdmin 要添加的群组管理员 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)addAdmin:(NSString *)aAdmin + toChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroomp, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager addAdmin:@"adminId" toChatroom:@"chatroomId" completion:^(EMChatroom *aChatroomp, EMError *aError) { + if (!aError) { + NSLog(@"添加聊天室管理员成功"); + } else { + NSLog(@"添加聊天室管理员失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 移除聊天室管理员 + +需要Owner权限 + +``` +/*! + * 移除聊天室管理员,需要Owner权限 + * + * @param aAdmin 要添加的群组管理员 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)removeAdmin:(NSString *)aAdmin + fromChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager removeAdmin:@"adminId" fromChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"移除聊天室管理员成功"); + } else { + NSLog(@"移除聊天室管理员失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 禁言聊天室成员 + +权限高者可禁言权限低者,反之不允许 + +``` +/*! + * 将一组成员禁言,需要Owner / Admin权限 + * + * @param aMuteMembers 要禁言的成员列表 + * @param aMuteMilliseconds 禁言时长(单位毫秒,如果是“-1”代表永久禁言) + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)muteMembers:(NSArray *)aMuteMembers + muteMilliseconds:(NSInteger)aMuteMilliseconds + fromChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager muteMembers:@[@"userName"] muteMilliseconds:10000 fromChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"将一组成员禁言成功"); + } else { + NSLog(@"将一组成员禁言失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 解除禁言 + +权限高者可禁言权限低者,反之不允许 + +``` +/*! + * 解除禁言,需要Owner / Admin权限 + * + * @param aMuteMembers 被解除的列表 + * @param aChatroomId 聊天室ID + * @param aCompletionBlock 完成的回调 + */ +- (void)unmuteMembers:(NSArray *)aMembers + fromChatroom:(NSString *)aChatroomId + completion:(void (^)(EMChatroom *aChatroom, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].roomManager unmuteMembers:@[@"userName"] fromChatroom:@"chatroomId" completion:^(EMChatroom *aChatroom, EMError *aError) { + if (!aError) { + NSLog(@"解除禁言成功"); + } else { + NSLog(@"解除禁言失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 聊天室相关的回调 + +注册聊天室回调 + +``` +协议:EMChatroomManagerDelegate + +代理: +//注册聊天室回调 +[[EMClient sharedClient].roomManager addDelegate:self delegateQueue:nil]; +//移除聊天室回调 +[[EMClient sharedClient].roomManager removeDelegate:self]; +``` + +回调方法: + +``` +/*! + * 有用户加入聊天室 + * + * @param aChatroom 加入的聊天室 + * @param aUsername 加入者 + */ +- (void)userDidJoinChatroom:(EMChatroom *)aChatroom + user:(NSString *)aUsername; + +/*! + * 有用户离开聊天室 + * + * @param aChatroom 离开的聊天室 + * @param aUsername 离开者 + */ +- (void)userDidLeaveChatroom:(EMChatroom *)aChatroom + user:(NSString *)aUsername; + +/*! + * 被踢出聊天室 + * + * @param aChatroom 被踢出的聊天室 + * @param aReason 被踢出聊天室的原因 + */ +- (void)didDismissFromChatroom:(EMChatroom *)aChatroom + reason:(EMChatroomBeKickedReason)aReason; + +/*! + * 有成员被加入禁言列表 + * + * @param aChatroom 聊天室 + * @param aMutedMembers 被禁言的成员 + * @param aMuteExpire 禁言失效时间,暂时不可用 + */ +- (void)chatroomMuteListDidUpdate:(EMChatroom *)aChatroom + addedMutedMembers:(NSArray *)aMutes + muteExpire:(NSInteger)aMuteExpire; + +/*! + * 有成员被移出禁言列表 + * + * @param aChatroom 聊天室 + * @param aMutedMembers 移出禁言列表的成员 + */ +- (void)chatroomMuteListDidUpdate:(EMChatroom *)aChatroom + removedMutedMembers:(NSArray *)aMutes; + +/*! + * 有成员被加入管理员列表 + * + * @param aChatroom 聊天室 + * @param aAdmin 加入管理员列表的成员 + */ +- (void)chatroomAdminListDidUpdate:(EMChatroom *)aChatroom + addedAdmin:(NSString *)aAdmin; + +/*! + * 有成员被移出管理员列表 + * + * @param aChatroom 聊天室 + * @param aAdmin 移出管理员列表的成员 + */ +- (void)chatroomAdminListDidUpdate:(EMChatroom *)aChatroom + removedAdmin:(NSString *)aAdmin; + +/*! + * 聊天室创建者有更新 + * + * @param aChatroom 聊天室 + * @param aNewOwner 新群主 + * @param aOldOwner 旧群主 + */ +- (void)chatroomOwnerDidUpdate:(EMChatroom *)aChatroom + newOwner:(NSString *)aNewOwner + oldOwner:(NSString *)aOldOwner; +``` \ No newline at end of file diff --git a/docs/document/v1/ios/content.md b/docs/document/v1/ios/content.md new file mode 100644 index 000000000..f2e95b71c --- /dev/null +++ b/docs/document/v1/ios/content.md @@ -0,0 +1,670 @@ +# APNs 内容解析 + +## 单聊 + +### 不显示详情 + +``` +{ + "aps":{ + "alert":{ + "body":"您有一条新消息" + }, + "badge":1, + "sound":"default" + }, + "f":"6001", + "t":"6006", + "m":"373360335316321408" +} +``` + +- alert: 显示信息 +- badge: 角标,表示离线消息数 +- sound: 收到 APNs 时的提示音 +- f: 消息发送方的环信 ID +- t: 消息接收方的环信 ID +- m: 消息 ID + +------ + +### 显示详情 + +``` +{ + "aps":{ + "alert":{ + "body":"ApnsNickName:xxxx" + }, + "badge":1, + "sound":"default" + }, + "f":"6001", + "t":"6006", + "m":"373360335316321408" +} +``` + +- alert: 显示信息 +- ApnsName: 发送方设置的用户名(即环信管理后台中看到的用户昵称) +- xxxx: 消息内容(发送方发的什么,就显示什么) +- badge: 角标,表示离线消息数 +- sound: 收到 APNs 时的提示音 +- f: 消息发送方的环信 ID +- t: 消息接收方的环信 ID +- m: 消息 ID + +------ + +## 群聊 + +### 不显示详情 + +``` +{ + "aps":{ + "alert":{ + "body":"您有一条新消息" + }, + "badge":1, + "sound":"default" + }, + "f":"6001", + "t":"6006", + "g":"1421300621769", + "m":"373360335316321408" +} +``` + +- alert: 显示信息 +- badge: 角标,表示离线消息数 +- sound: 收到 APNs 时的提示音 +- f: 消息发送方的环信 ID +- t: 消息接收方的环信 ID +- g: 群组 ID +- m: 消息 ID + +------ + +### 显示详情 + +``` +{ + "aps":{ + "alert":{ + "body":"ApnsName:xxxx" + }, + "badge":1, + "sound":"default" + }, + "f":"6001", + "t":"6006", + "g":"1421300621769", + "m":"373360335316321408" +} +``` + +- alert: 显示信息 +- ApnsName: 发送方设置的用户名(即环信管理后台中看到的用户昵称) +- xxxx: 消息内容(发送方发的什么,就显示什么) +- badge: 角标,表示离线消息数 +- sound: 收到 APNs 时的提示音 +- f: 消息发送方的环信 ID +- t: 消息接收方的环信 ID +- g: 群组 ID +- m: 消息 ID + +------ + +## 向 APNs 中添加扩展字段 + +APNs 扩展(em_apns_ext):添加后,您收到的 APNs 中将带有您填写的字段,可以帮助您区分 APNs。 + +环信提供以下几种扩展字段: + +| 扩展字段 | 描述 | +| :---------------------- | :----------------------------------- | +| em_push_content | 自定义推送显示 | +| em_push_category | 向 APNs Payload 中添加 category 字段 | +| em_push_sound | 自定义推送提示音 | +| em_push_mutable_content | 开启 APNs 通知扩展 | + +#### 解析内容 + +``` +{ + "apns": { + "alert": { + "body": "hello from rest" + }, + "badge": 1, + "sound": "default" + }, + "e": "自定义推送扩展", + "f": "6001", + "t": "6006", + "m": "373360335316321408" +} +``` + +- e: 您发送的自定义推送扩展 + +#### REST 发送 + +([REST 发消息](https://docs-im.easemob.com/ccim/rest/message#发送消息)) + +``` +{ + "target_type": "users", + "target": [ + "6006" + ], + "msg": { + "type": "txt", + "msg": "hello from rest" + }, + "ext": { + "em_apns_ext": { + "extern": "自定义推送扩展" + } + }, + "from": "6001" +} +``` + +#### iOS 发送 + +([iOS 发消息](message.html#构造扩展消息)) + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"test"]; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6006" from:@"6001" to:@"6006" body:body ext:nil]; +message.ext = @{@"em_apns_ext":@{@"extern":@"自定义推送扩展"}}; // 此处的ext和message初始化时传递的ext效果是一样的,此处单独抽出来的目的是表示的更清晰。 +message.chatType = EMChatTypeChat; // 设置消息类型 +[EMClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +------ + +### 自定义显示 + +设置后,您收到的 APNs 的 alert 信息将是您设置的信息。 + +#### 解析 + +``` +{ + "aps":{ + "alert":{ + "body":"自定义推送显示" + }, + "badge":1, + "sound":"default" + }, + "f":"6001", + "t":"6006", + "m":"373360335316321408" +} +``` + +#### REST 发送 + +([REST 发消息](/document/v1/server-side/message_single.html)) + +``` +{ + "target_type": "users", + "target": [ + "6006" + ], + "msg": { + "type": "txt", + "msg": "hello from rest" + }, + "from": "6001", + "ext": { + "em_apns_ext": { + "em_push_content": "自定义推送显示" + } + } +} +``` + +如果要兼容Android端,需要在消息的扩展中增加以下字段 + +``` +"ext":{ + ... + "em_android_push_ext":{ + //指定自定义渠道 + "em_push_channel_id":"Channel id", + "em_push_sound":"/raw/appsound" + } + } +``` + +#### iOS 发送 + +([iOS 发消息](message.html#构造扩展消息)) + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"test"]; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6006" from:@"6001" to:@"6006" body:body ext:nil]; +message.ext = @{@"em_apns_ext":@{@"em_push_content":@"自定义推送显示"}}; // 此处的ext和message初始化时传递的ext效果是一样的,此处单独抽出来的目的是表示的更清晰。 +message.chatType = EMChatTypeChat; // 设置消息类型 +[EMClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +------ + +### 自定义显示与自定义扩展 + +自定义显示与自定义扩展同时发给对方。 + +#### 解析 + +``` +{ + "aps":{ + "alert":{ + "body":"自定义推送显示" + }, + "badge":1, + "sound":"default" + }, + "f":"6001", + "t":"6006", + "m":"373360335316321408", + "e": "自定义推送扩展", +} +``` + +#### REST 发送 + +([REST 发消息](https://docs-im.easemob.com/im/server/basics/messages#发送扩展消息)) + +``` +{ + "target_type": "users", + "target": [ + "6006" + ], + "msg": { + "type": "txt", + "msg": "hello from rest" + }, + "from": "6001", + "ext": { + "em_apns_ext": { + "em_push_content": "自定义推送显示", + "extern": "自定义推送扩展" + } + } +} +``` + +#### iOS 发送 + +([iOS 发消息](message.html#构造扩展消息)) + +``` +NSString *willSendText = [EaseConvertToCommonEmoticonsHelper convertToCommonEmoticons:text]; +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"test"]; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6006" from:@"6001" to:@"6006" body:body ext:nil]; +message.ext = @{@"em_apns_ext":@{@"extern":@"自定义推送扩展",@"em_push_content":@"自定义推送显示"}}; // 此处的ext和message初始化时传递的ext效果是一样的,此处单独抽出来的目的是表示的更清晰。 +message.chatType = EMChatTypeChat; // 设置消息类型 +[EMClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +------ + +### 添加category字段 + +向 APNs Payload 中添加 category 字段。 + +[苹果描述](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW1) + +#### REST 发送 + +([REST 发消息](https://docs-im.easemob.com/im/server/basics/messages#发送扩展消息)) + +``` +{ + "target_type": "users", + "target": [ + "6006" + ], + "msg": { + "type": "txt", + "msg": "hello from rest" + }, + "from": "6001", + "ext": { + "em_apns_ext": { + "em_push_category" : "NEW_MESSAGE_CATEGORY" + } + } +} +``` + +------ + +### 自定义推送提示音 + +设置后,您收到的 APNs 的提示音将是您设置的提示音。 + +**注:** + +- 如果没有设置该字段,则播放默认提示音;有此字段,如果找到了指定的声音就播放该声音,否则播放默认声音,如果此字段为空字符串,iOS 7 为默认声音,iOS 8 及以上系统为无声音。 + +- 以下示例自定义提示音文件名称为custom.caf。 + +- 集成方式:将自定义提示音的caf格式音频文件导入iOS工程,发送消息按以下示例增加消息扩展,当接收方离线收到APNs离线推送时,即可播放自定义的提示音。 + +支持格式 Linear PCM MA4 (IMA/ADPCM) µLaw aLaw + +存放路径 AppData/Library/Sounds,时长不得超过30秒。 具体信息,可以参考苹果官方文档[Generating a Remote Notification](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification?language=objc) + +#### 解析 + +``` +{ + "aps":{ + "alert":{ + "body":"您有一条新消息" + }, + "badge":1, + "sound":"custom.caf" + }, + "f":"6001", + "t":"6006", + "m":"373360335316321408" +} +``` + +#### REST 发送 + +([REST 发消息](https://docs-im.easemob.com/im/server/basics/messages#发送扩展消息)) + +**注:**“em_push_sound”为设置自定义 APNs 提示音的扩展字段,value 值为音频文件名,字符串类型。 + +``` +{ + "target_type": "users", + "target": [ + "6006" + ], + "msg": { + "type": "txt", + "msg": "hello from rest" + }, + "from": "6001", + "ext": { + "em_apns_ext": { + "em_push_sound": "custom.caf" + } + } +``` + +#### iOS 发送 + +([iOS 发消息](message.html#构造扩展消息)) + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"test"]; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6006" from:@"6001" to:@"6006" body:body ext:nil]; +message.ext = @{@"em_apns_ext":@{@"em_push_sound":@"custom.caf"}}; // 设置自定义APNs提示音的扩展字段,value值为音频文件名,字符串类型 +message.chatType = EMChatTypeChat; // 设置消息类型 +[EMClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +------ + +### 开启 APNs 通知扩展 + +(UNNotificationServiceExtension) + +设置后,该条消息的 APNs 推送将在服务端支持 UNNotificationServiceExtension ,还需要APP在项目中集成 UNNotificationServiceExtension ,才可使用 APNs 通知扩展。iOS 集成方式见 [Apple官方文档](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension?language=objc) + +#### 解析 + +``` +{ + "aps":{ + "alert":{ + "body":"您有一条新消息" + }, + "badge":1, + "sound":"default", + "mutable-content":1 + }, + "f":"6001", + "t":"6006", + "m":"373360335316321408" +} +``` + +#### REST发送 + +([REST 发消息](https://docs-im.easemob.com/im/server/basics/messages#发送扩展消息)) + +**注:**“em_push_mutable_content”的 value 值为 bool 类型,true 为开启;false 或不设置,则是普通的 Remote Notification。 + +``` +{ + "target_type": "users", + "target": [ + "6006" + ], + "msg": { + "type": "txt", + "msg": "hello from rest" + }, + "from": "6001", + "ext": { + "em_apns_ext": { + "em_push_mutable_content": true + } + } +} +``` + +#### iOS发送 + +([iOS 发消息](message.html#构造扩展消息)) + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"test"]; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6006" from:@"6001" to:@"6006" body:body ext:nil]; +message.ext = @{@"em_apns_ext":@{@"em_push_mutable_content":@YES}}; // @YES为开启,@NO或不设置,则是普通的 Remote Notification +message.chatType = EMChatTypeChat; // 设置消息类型 +[EMClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +------ + +## APNs推送国际化配置 + +环信消息的离线推送可支持 APNs 以下几个国际化配置的 key:`title-loc-key`,`title-loc-args`,`loc-key`,`loc-args` + +关于这几个 key 的官方解释: + +- title-loc-key(String):The key for a localized title string. Specify this key instead of the title key to retrieve the title from your app’s Localizable.strings files. The value must contain the name of a key in your strings file. + +- title-loc-args(Array of strings):An array of strings containing replacement values for variables in your title string. Each %@ character in the string specified by the title-loc-key is replaced by a value from this array. The first item in the array replaces the first instance of the %@ character in the string, the second item replaces the second instance, and so on. + +- loc-key(String):The key for a localized message string. Use this key, instead of the body key, to retrieve the message text from your app's Localizable.strings file. The value must contain the name of a key in your strings file. + +- loc-args(Array of strings):An array of strings containing replacement values for variables in your message text. Each %@ character in the string specified by loc-key is replaced by a value from this array. The first item in the array replaces the first instance of the %@ character in the string, the second item replaces the second instance, and so on. + +[苹果官方开发文档](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification) + +**注:** + +- `title-loc-key` 与 `title-loc-args` 组成一对,没有 `title-loc-key` , `title-loc-args` 不生效,如无可变参数,可以只设置 `title-loc-key`; + +- `loc-key` 与 `loc-args` 组成一对,没有 `loc-key` , `loc-args` 不生效,如无可变参数,可以只设置 `loc-key`; + +- 以上两对也可以只设置其中一对。 + +### iOS 客户端配置 + +- 配置国际化文件 `Localizable.strings` ,如 demo 中配置了 `Localizable.strings (Chinese (Simplified))`、`Localizable.strings (English)`; + +- 在 `Localizable.strings` 中配置 `title-loc-key` 和 `loc-key` ,并赋值,需要使用 `title-loc-args` 和 `loc-args` 中的可变参数的字符串,用 `%@` 代替;如下: + +在 `Localizable.strings (Chinese (Simplified))` 中配置: + +``` +"GAME_PLAY_REQUEST_FORMAT" = "%@ 游戏邀请 %@"; +"GAME_PLAY_REQUEST" = "游戏邀请"; +``` + +在 `Localizable.strings (English)` 中配置: + +``` +"GAME_PLAY_REQUEST_FORMAT" = "%@ GAME_PLAY_REQUEST_FORMAT %@"; +"GAME_PLAY_REQUEST" = "GAME_PLAY_REQUEST_CUSTOM"; +``` + +### 发消息时设置消息扩展 + +#### REST 发送 + +``` +{ + "target_type" : "users", + "target" : ["6006"], + "msg" : { + "type" : "txt", + "msg" : "hello from rest" + }, + "ext": { + "em_apns_ext": { + "em_push_content": "自定义推送显示", # 可以同时设置自定义推送显示,没有配置loc-key的app,会显示"自定义推送显示" + "em_push_title_loc_key" : "GAME_PLAY_REQUEST_FORMAT", # 对应title_loc_key + "em_push_title_loc_args" : ["Shelly", "Rick"], # 对应title_loc_args + "em_push_body_loc_key" : "GAME_PLAY_REQUEST_FORMAT", # 对应loc_key + "em_push_body_loc_args" : ["Shelly", "Rick"] # 对应loc_args + } + }, + "from" : "6001" +} +``` + +#### iOS 发送 + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"test"]; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6006" from:@"6001" to:@"6006" body:body ext:nil]; +message.ext = @{@"em_apns_ext":@{@"em_push_title_loc_key":@"GAME_PLAY_REQUEST_FORMAT", @"em_push_title_loc_args":@[@"Shelly", @"Rick"], @"em_push_body_loc_key":@"GAME_PLAY_REQUEST_FORMAT", @"em_push_body_loc_args":@[@"Shelly", @"Rick"]}}; +message.chatType = EMChatTypeChat; // 设置消息类型 +[EMClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +### 解析 + +``` +{ + "aps":{ + "alert":{ + "body":"自定义推送显示", + "title-loc-key":"GAME_PLAY_REQUEST_FORMAT", + "title-loc-args":["Shelly","Rick"], + "loc-key":"GAME_PLAY_REQUEST_FORMAT", + "loc-args":["Shelly","Rick"] + }, + "badge":1, + "sound":"default" + }, + "f":"6001", + "t":"6006", + "m":"373360335316321408" +} +``` + +## 发送静默消息 + +(em_ignore_notification) + +不发APNs。发送时添加后,该消息将不会有 APNs 推送。 + +### REST 发送 + +([REST 发消息](https://docs-im.easemob.com/im/server/basics/messages#发送扩展消息)) + +``` +{ + "target_type":"users", + "target":[ + "6006" + ], + "msg":{ + "type":"txt", + "msg":"hello from rest" + }, + "from":"6001", + "ext":{ + "em_ignore_notification":true + } +} +``` + +------ + +### iOS 发送 + +([iOS 发消息](message.html#构造扩展消息)) + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"test"]; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6006" from:@"6001" to:@"6006" body:body ext:nil]; +message.ext = @{@"em_ignore_notification":@YES}; +message.chatType = EMChatTypeChat; // 设置消息类型 +// 发送消息示例 +[EMClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` + +------ + +## 设置强制推送型 APNs + +(em_force_notification) + +设置后,将强制推送消息,即使客户端设置了免打扰时间,也会得到推送。优先级比 em_ignore_notification 低,即同时设置 em_ignore_notification 后,该属性将失效。 + +### REST 发送 + +([REST 发消息](https://docs-im.easemob.com/im/server/basics/messages#发送扩展消息)) + +``` +{ + "target_type":"users", + "target":[ + "6006" + ], + "msg":{ + "type":"txt", + "msg":"hello from rest" + }, + "from":"6001", + "ext":{ + "em_force_notification":true + } +} +``` + +------ + +### iOS 发送 + +([iOS 发消息](message.html#构造扩展消息)) + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"test"]; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6006" from:@"6001" to:@"6006" body:body ext:nil]; +message.ext = @{@"em_force_notification":@YES}; +message.chatType = EMChatTypeChat; // 设置消息类型 +// 发送消息示例 +[EMClient.sharedClient.chatManager sendMessage:message progress:nil completion:nil]; +``` \ No newline at end of file diff --git a/docs/document/v1/ios/demo.md b/docs/document/v1/ios/demo.md index 7675a32b3..8a483dc0c 100644 --- a/docs/document/v1/ios/demo.md +++ b/docs/document/v1/ios/demo.md @@ -2,7 +2,7 @@ -环信即时通讯 IM iOS 端提供示例应用可供体验。 + ## 代码下载 您可以通过以下两种方式获取到源代码: -- 下载代码压缩包:[IM SDK 及 Demo 下载](https://www.easemob.com/download/im) -- 下载源代码:[github 源码地址](https://github.com/easemob/chat-ios) +- 下载代码压缩包:[IM SDK 及 Demo 下载](https://downloadsdk.easemob.com/downloads/iOS_IM_SDK_V4.1.1.zip) + 欢迎大家提交 PR 改进和修复 EaseIM 和 EaseIMKit 中的问题。 ## 运行 EaseIM 工程 -从 [IM SDK 及 Demo 下载](https://www.easemob.com/download/im) 下载 iOS SDK 压缩包,然后解压。解压后在 `EaseIM` 文件夹下,即为 EaseIM 的工程目录。 +下载 iOS SDK 压缩包,然后解压。解压后在 `EaseIM` 文件夹下,即为 EaseIM 的工程目录。 终端 cd 到 EaseIM 的 `podfile` 目录下,终端执行 `pod install` 命令,等待下载完所有的 pod 依赖库,即可打开 `EaseIM.xcworkspace`,运行 EaseIM demo 进行自定义再次开发。 @@ -67,6 +68,6 @@ Demo 中有几大 UI 功能模块,在集成时将对应的模块添加到工 ## 部分 UI 展示 -![联系人列表](@static/images/android/app-demo-ui-2.jpeg) -![聊天页面](@static/images/android/app-demo-ui-3.jpeg) \ No newline at end of file +   + \ No newline at end of file diff --git a/docs/document/v1/ios/deploy.md b/docs/document/v1/ios/deploy.md new file mode 100644 index 000000000..b94b02d1c --- /dev/null +++ b/docs/document/v1/ios/deploy.md @@ -0,0 +1,331 @@ +# APNs推送 + +## SDK的运行状态 + +- 当 App 在前台可见的时候,SDK 处于前台活跃状态,此时是使用 SDK 长连接接收消息。 + +- 当 App 进入后台,短时间内 SDK 处于后台活跃状态,此时是使用 SDK 长连接接收消息(用户根据需要实现本地通知,否则将不会有本地通知提示弹出)。 + +- 当 App 进入后台被系统挂起,此时 SDK 处于不活跃状态,或者是主动把App进程杀死,此时如果有新消息,是通过苹果的 APNs 服务进行提醒的。当 App 再次启动,SDK 会去服务器拉取不活跃期间的消息。 + +**注意:**`由于本地通知和 APNs 不好区分,调试时建议您将 App 进程杀死,确保所有的提醒都是来自于 APNs 推送。` + +## 消息推送流程 + +### 当SDK处于前台或后台活跃状态时: + +![img](@static/images/privitization/apns_image006.png) + +### 当SDK处于不活跃状态或App进程被杀死时: + +![img](@static/images/privitization/apns_image007.png) + +:::tip +APNs只是起到通知作用,当用户启动App,消息会通过SDK长连接收取到客户端。 +::: + +## 配置推送 + +### 申请远程推送证书 + +1. 首先,登录苹果的[开发者中心](https://developer.apple.com/), 创建App + +
+
+
+ +-------- +2. 为App命名,此处bundle id不能用通配符,否则无法收到推送。 + +
+ +-------- +3. 打开推送功能 + +
+
+ + +-------- +4. 创建推送证书 + +
+ +如果您是测试开发环境,选择Services下的Apple Push Notification service SSL(Sandbox),如果是生产环境,则需要选择Services下的Apple Push Notification service SSL(Sandbox & Production) + +
+ +-------- +5. 选择证书所属的App + +
+ +-------- +6. 上传CSR文件 + +
+ +下面,我们来创建一个CSR文件,首先,选择“钥匙串访问” + +
+ +钥匙串访问 – 证书助理 – 从证书颁发机构请求证书 + +
+ +电子邮件没有要求,符合邮件格式就可以,常用名也没有限制,要注意将“请求是”的参数改为**“存储到磁盘”**, 之后会得到一个CSR文件。 + +
+ +返回到“上传CRS文件”页面,将刚刚生成的CSR文件上传。 + +
+ +点击继续,会得到一个下载页面。 + +
+ +
+ +点击下载,就会下载一个aps_development.cer。(production的是aps.cer) + +
+ +双击下载的cer文件,就会将它添加到“钥匙串访问”中。查看证书,会看到一个以bundle id 证书,这个就是新添加进去的。 + +
+ +:::tip +右键导出,注意右键的时候不要展开,就在证书上点击右键 +::: + +
+ +保存 + +
+ +此处需要记住密码,后面需要用到。 `注意:导出p12证书时,设置证书的密码长度不要超过20个字符,建议使用纯英文或者数字组合,不建议带特殊字符` + +
+ +允许钥匙串访问此项目。 + +
+ +保存,您将得到一个p12后缀的文件。 + +
+ +### 上传推送证书到环信 + +登录环信管理后台,找到要上传证书的Appkey,点击`管理->即时推送->配置证书`下配置证书,选择`添加推送证书`下的苹果选项。 + +
+ +选择`上传证书`按钮 + +
+ + +为证书起名,并记住名称,后续有用。选择上传证书,将上一步中生成的P12文件上传,并设置导出时设置的密码。选择证书类型,此处是【开发环境】(如果之前用的是production,则此处应该选择生产)。填写应用包名,应为**bundle id**,点击上传,完成上传证书操作。 + +:::tip +注意:证书的名称和密码的长度不要超过20个字符,建议使用纯英文或者数字组合,不建议带特殊字符 +::: + +
+ +### 客户端如何申请DeviceToken + +1、 注册远程通知 + +``` +if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) { + //注册推送, 用于iOS8以及iOS8之后的系统 + UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; + [application registerUserNotificationSettings:settings]; +} else { + //注册推送,用于iOS8之前的系统 + UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound; + [application registerForRemoteNotificationTypes:myTypes]; +} + +- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { + [application registerForRemoteNotifications]; +} +``` + +2、 将得到的deviceToken传到SDK + +``` +如果是iOS13及以上的系统,请将SDK更新到v3.6.4或以上版本 +// 将得到的deviceToken传给SDK +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[EMClient sharedClient] bindDeviceToken:deviceToken]; + }); +} +``` + +**注:必须是真机,模拟器不支持APNs。APNs 注册失败,一般是由于使用了通用证书或者是模拟器调试导致,请检查证书并用真机调试。此处是 iOS 系统报的错,如仍不能确定,请从网上查找相关资料。** + +### 客户端如何配置推送证书 + +SDK在初始化的时候,设置要使用的推送证书。 + +``` +// 设置Appkey +EMOptions *options = [EMOptions optionsWithAppkey:@"easemob-demo#chatdemoui"]; +// 设置推送证书名称 +options.apnsCertName = @"apnsTest"; +// 初始化SDK +[[EMClient sharedClient] initializeSDKWithOptions:options]; +``` + +## 使用在线推送通道 + +与APNs离线推送使用苹果厂商推送通道不同,在线推送通道使用环信长连接接收推送,之后以本地通知的形式展示推送消息,可以有效提升推送到达率。 集成在线推送过程如下: + +1. 申请本地通知权限 +2. 启用SDK在线推送 +3. 处理Delegate + +### 申请本地通知权限 + +由于要使用本地通知展示推送消息,你需要在App中需要申请权限,过程如下: + +``` +UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) { + + }]; +``` + +### 启用SDK在线推送 + +在启用APNs在线推送前,你需要完成IM SDK的初始化工作 + +SDK初始化完成后,启用APNs在线推送过程如下: + +``` +[[EMLocalNotificationManager sharedManager] launchWithDelegate:self]; +``` + +### 处理Delegate + +在启用在线通道过程中,SDK会重写 **[UNUserNotificationCenter currentNotificationCenter]** 的delegate,如果要处理其他本地通知,需要实现**EMLocalNotificationDelegate**,过程如下 + +``` +#pragma mark - EMLocalNotificationDelegate +- (void)emuserNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler +{ + // // 这里处理其他本地通知 + completionHandler(UNNotificationPresentationOptionAlert); +} +- (void)emuserNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler +{ + NSDictionary* userInfo = response.notification.request.content.userInfo; + // 这里处理其他本地通知 + completionHandler(); +} +``` + +### 进阶 + +iOS的本地通知管理模块**UNUserNotificationCenter**是单例,一个App 中只能有一个实例,如果在启用SDK在线推送之后,App又重写了 **[UNUserNotificationCenter currentNotificationCenter].delegate**,会把SDK中的delegate覆盖掉,此时需要在App实现的**UNUserNotificationCenterDelegate**中,调用SDK的相关处理,过程如下 + +``` +#pragma mark - UNUserNotificationCenterDelegate + +- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler +{ + // 处理其他通知 + ... + // 调用SDK推送在线通道处理 + [[EMLocalNotificationManager sharedManager] userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler]; +} + +- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler +{ + + // 处理其他通知 + ... + // 调用SDK推送在线通道处理 + [[EMLocalNotificationManager sharedManager] userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; +} +``` + +## 常见问题 + +### 如何实现本地通知 + +本地通知,是在长连接还存在的时候,`通过环信收消息的回调接收到消息`,之后判断当前App的状态,如果是在后台的情况下,就可以`通过代码主动弹出一个通知`,来起到通知用户的作用。具体参考如下: + +``` +- (void)messagesDidReceive:(NSArray *)aMessages { + for (EMMessage *msg in aMessages) { + UIApplicationState state = [[UIApplication sharedApplication] applicationState]; + // App在后台 + if (state == UIApplicationStateBackground) { + //发送本地推送 + if (NSClassFromString(@"UNUserNotificationCenter")) { // ios 10 + // 设置触发时间 + UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.01 repeats:NO]; + UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; + content.sound = [UNNotificationSound defaultSound]; + // 提醒,可以根据需要进行弹出,比如显示消息详情,或者是显示“您有一条新消息” + content.body = @"提醒内容"; + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:msg.messageId content:content trigger:trigger]; + [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil]; + }else { + UILocalNotification *notification = [[UILocalNotification alloc] init]; + notification.fireDate = [NSDate date]; //触发通知的时间 + notification.alertBody = @"提醒内容"; + notification.alertAction = @"Open"; + notification.timeZone = [NSTimeZone defaultTimeZone]; + notification.soundName = UILocalNotificationDefaultSoundName; + [[UIApplication sharedApplication] scheduleLocalNotification:notification]; + } + } + } +} +``` + +### 推送内容解析 + +在环信中,APNs是在长连接不存在的时候,才会产生(即App进程不存在或者被挂起)。此时iOS是不允许直接得到APNs内容的,但是当用户点击推送的提示栏,此时是可以在 +launchOptions中得到APNs的内容。具体解析结构如下: + +``` +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; +``` + + + +``` +{ + "aps":{ + "alert":{ + "body":"您有一条新消息" // 消息内容 + }, + "badge":1, // 角标数 + "sound":"default" // 提示音 + }, + "f":"6001", // 消息发送方 + "t":"6006", // 消息接收方 + "m":"373360335316321408", // 消息id + "g":"1421300621769" // 群组id(如果是单聊则没有该字段) + } +``` + +更多用法,可以参考 ([APNs解析](content)) + +### 证书到期后如何更新 + +证书到期后,要更换新的推送证书,需要在环信管理后台将旧的删除,之后重新上传,`上传时的命名要与旧证书的命名一致`。 + +### 一个Appkey下是否可以传多组推送证书 + +一个appkey下可以传多个证书,这就可以实现夸App聊天,在不同App中初始化sdk的时候,指定不同的推送证书,每个证书对应当前App的bundle id,这样,用户在登录不同的App的时候就会绑定到不同的推送证书,从而实现夸App的聊天和推送。 \ No newline at end of file diff --git a/docs/document/v1/ios/easecallkit.md b/docs/document/v1/ios/easecallkit.md index f106f5d30..4e4f3d1dc 100644 --- a/docs/document/v1/ios/easecallkit.md +++ b/docs/document/v1/ios/easecallkit.md @@ -8,7 +8,7 @@ 使用 `EaseCallKit` 库可以快速实现常用的音视频场景,通过信令的交互确认,保证 **用户多端登录时,收到呼叫同时振铃,一端处理后,其他端自动停止**。 -`EaseCallKit` 库在 Github 上进行了保存,请参见 [EaseCallKit iOS 端使用指南](https://github.com/easemob/easecallkitui-ios)。 +`EaseCallKit` 库在 Github 上进行了保存,请参见 [EaseCallKit iOS 端使用指南](https://github.com/easemob/easecallkitui-ios/tree/4.0.0)。 **`EaseCallKit` 在通话过程中,使用环信 ID 加入频道,方便音视频视图中显示用户名。如果用户不使用 `EaseCallKit` 而直接调用声网 API,也可以直接使用数字 UID 加入频道。** @@ -18,7 +18,7 @@ ## 跑通 Demo -`EaseCallKit` 集成在环信提供的开源 IM Demo 中,你可以通过进入 [环信 IM Demo 下载页面](https://www.easemob.com/download/im),选择 iOS 端 Demo 下载,或直接进入 [Github 开源网站](https://github.com/easemob/chat-ios) 下载。 +EaseCallKit 集成在环信开源 IM Demo 中,你可以直接下载 iOS 端Demo下载 [iOS IM源码](https://downloadsdk.easemob.com/downloads/iOS_IM_SDK_V4.1.1.zip) 。 - 安装 SDK 与 `EaseCallKit` @@ -40,7 +40,7 @@ pod install 在集成该库前,你需要满足以下条件: -- 分别创建 [环信应用](/product/enable_and_configure_IM.html) 及 [声网应用](https://docportal.shengwang.cn/cn/video-legacy/run_demo_video_call_ios?platform=iOS#1-创建声网项目); +- 分别创建 [环信应用](/document/v1/privatization/uc_configure.html) 及 [声网应用](https://docportal.shengwang.cn/cn/video-legacy/run_demo_video_call_ios?platform=iOS#1-创建声网项目); - 已完成环信 IM 的基本功能,包括登录、好友、群组以及会话等的集成; - 上线之前开通声网 token 验证时,用户需要实现自己的 [App Server](https://github.com/easemob/easemob-im-app-server/tree/master/agora-app-server),用于生成 token。利用 App Server 生成 token 的过程参见 [声网 token](https://docportal.shengwang.cn/cn/video-call-4.x/token_server_ios_ng?platform=iOS)。 @@ -163,13 +163,13 @@ config.agoraAppId=@"声网 AppID"; 发起通话后的 UI 界面如下: - + ### 收到邀请 主叫方调用邀请接口后,如果被叫方在线且并未处于通话过程中,将弹出通话页面,被叫用户可选择接听或者拒绝。通话页面如下: - + 被叫振铃的同时,会触发以下回调: diff --git a/docs/document/v1/ios/easeimkit.md b/docs/document/v1/ios/easeimkit.md index b3e5e2317..6f87eb206 100644 --- a/docs/document/v1/ios/easeimkit.md +++ b/docs/document/v1/ios/easeimkit.md @@ -12,11 +12,11 @@ EaseIMKit 是基于环信 IM SDK 的一款 UI 组件库,它提供了一些通 EaseIMKit 源码地址 -- [EaseIMKit 工程](https://github.com/easemob/easeui_ios/tree/EaseIMKit) +- [EaseIMKit 工程](https://github.com/easemob/easeui_ios/tree/EaseIMKit_4.1.0) 使用 EaseIMKit 环信 IM App 地址: -- [环信 IM](https://github.com/easemob/chat-ios) +- [环信 IM](https://downloadsdk.easemob.com/downloads/iOS_IM_SDK_V4.1.1.zip) ## 导入 @@ -43,9 +43,13 @@ EaseIMKit 中包含了拍照,发语音,发图片,发视频,发位置, ### 源码集成 + +[下载IM源码](https://downloadsdk.easemob.com/downloads/iOS_IM_SDK_V4.1.1.zip) + - 创建 `Podfile` 文件并添加 EaseIMKit 源码依赖 @@ -75,7 +79,7 @@ EaseIMKit 中包含了拍照,发语音,发图片,发视频,发位置, 1. 终端 cd 到 Podfile 文件所在目录,执行 pod install 命令在项目中安装 EaseIMKit 本地源码 2. 执行完成后,则在 Xcode 项目目录 Pods/Development Pods/ 可找到 EaseIMKit 源码,如下图所示: - ![img](@static/images/ios/easeimkit3.png) + 3. 可对源码进行符合自己项目目标的自定义修改 @@ -334,19 +338,21 @@ typedef enum { 聊天页背景色,输入区颜色配置示例: -![背景色,输入区颜色](@static/images/ios/easeimkit4.png) + 聊天会话输入区类型参数配置示例: -![全部功能,语音不可用,表情不可用,语音和表情不可用,纯文本](@static/images/ios/easeimkit5.png) + + 输入区扩展功能参数配置示例: -![输入区扩展](@static/images/ios/easeimkit6.jpeg) + 聊天会话群聊消息同左排列,时间线背景色,时间字体颜色配置示例: -![群聊消息同左排列,时间线背景色,时间字体颜色](@static/images/ios/easeimkit7.jpeg) + + ### 会话列表样式配置 @@ -417,7 +423,7 @@ typedef enum { 通讯录添加头部功能区:新的好友,群聊,聊天室示意图: -![头部功能区:新的好友,群聊,聊天室以及联系人列表](@static/images/ios/easeimkit8.png) + ## 自定义功能扩展 @@ -476,7 +482,7 @@ EaseChatViewControllerDelegate 通过自定义 cell 展示单聊音视频通话记录的效果图: -![自定义 cell 展示单聊音视频通话记录](@static/images/ios/easeimkit9.png) + #### 选中消息的回调 diff --git a/docs/document/v1/ios/group.md b/docs/document/v1/ios/group.md new file mode 100644 index 000000000..cf4a9d68c --- /dev/null +++ b/docs/document/v1/ios/group.md @@ -0,0 +1,1369 @@ +# 群组管理 + + +**注意**:`1、群主+管理员 一起一共不超过 100 个,也就是不超过 99 个管理员。2、群组成员最大数(包括群主)取决于所选择的版本,不同版本最大数不同。` + + +群组管理主要涉及到的环信 SDK 头文件如下: + +``` +// 群组部分,有群组id等属性 +EMGroup.h + +// 群组属性选项部分,用于创建群组时的属性设置 +EMGroupOptions.h + +// 群组共享文件部分 +EMGroupSharedFile.h + +// 群组方法调用部分,比如添加代理,移除代理,创建群组,获取群组列表等 +IEMGroupManager.h + +// 群组的协议回调方法部分,比如监听有用户加群的回调方法等 +EMGroupManagerDelegate.h +``` + +注册群组模块回调: + +``` +协议: EMGroupManagerDelegate + +代理: +//注册群组回调 +[[EMClient sharedClient].groupManager addDelegate:self delegateQueue:nil]; + +//移除群组回调 +[[EMClient sharedClient].groupManager removeDelegate:self]; +``` + +------ + +群组分为四种类型。 + +``` +/*! + @enum + @brief 群组类型 + @constant EMGroupStylePrivateOnlyOwnerInvite 私有群组,创建完成后,只允许 Owner 邀请用户加入 + @constant EMGroupStylePrivateMemberCanInvite 私有群组,创建完成后,只允许 Owner 和群成员邀请用户加入 + @constant EMGroupStylePublicJoinNeedApproval 公开群组,创建完成后,只允许 Owner 邀请用户加入; 非群成员用户需发送入群申请,Owner 同意后才能入组 + @constant EMGroupStylePublicOpenJoin 公开群组,创建完成后,允许非群组成员加入,不需要管理员同意 + @discussion + eGroupStyle+Private:私有群组,只允许群组成员邀请人进入 + eGroupStyle+Public: 公有群组,允许非群组成员加入 + */ +typedef NS_ENUM(NSInteger, EMGroupStyle){ + EMGroupStylePrivateOnlyOwnerInvite = 0, + EMGroupStylePrivateMemberCanInvite, + EMGroupStylePublicJoinNeedApproval, + EMGroupStylePublicOpenJoin, +}; +``` + +## 群组操作 + +### 创建群组 + +目前创建群组支持的配置属性有: + +- 群名称 +- 群描述 +- 群人数(默认2000人,支持修改) +- 群类型(即上面提到的四种群组类型) + +异步方法: + +``` +EMGroupOptions *setting = [[EMGroupOptions alloc] init]; // 群组属性选项 + setting.maxUsersCount = 500; // 群组的最大成员数(含群主、管理员,默认是2000,最大8000) + setting.IsInviteNeedConfirm = NO; //邀请群成员时,是否需要发送邀请通知.若NO,被邀请的人自动加入群组 + setting.style = EMGroupStylePublicOpenJoin;// 创建不同类型的群组,这里需要才传入不同的类型 + setting.ext = @"群组扩展信息"; // 扩展信息 + +/*! + * 创建群组 + * + * 异步方法 + * + * @param aSubject 群组名称 + * @param aDescription 群组描述 + * @param aInvitees 群组成员(不包括创建者自己,不能超过100个) + * @param aMessage 邀请消息 + * @param aSetting 群组属性 + * @param pError 出错信息 + * + * @return 创建的群组 + */ +- (void)createGroupWithSubject:(NSString *)aSubject + description:(NSString *)aDescription + invitees:(NSArray *)aInvitees + message:(NSString *)aMessage + setting:(EMGroupOptions *)aSetting + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager createGroupWithSubject:@"群组名称" description:@"群组描述" invitees:@[@"6001",@"6002"] message:@"邀请您加入群组" setting:setting completion:^(EMGroup *aGroup, EMError *aError) { + if(!aError){ + NSLog(@"创建群组成功 -- %@",aGroup); + } else { + NSLog(@"创建群组失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 获取群详情 + +``` +注意:从3.7.4版本开始支持 “是否获取群组成员”参数 +/*! + * 获取群组详情,包含群组ID,群组名称,群组描述,群组基本属性,群组Owner, 群组管理员 + * + * @param aGroupId 群组ID + * @param fetchMembers 是否获取群组成员,默认最多取200人数 + * @param aCompletionBlock 完成的回调 + * + */ +- (void)getGroupSpecificationFromServerWithId:(NSString *)aGroupId + fetchMembers:(BOOL)fetchMembers + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +//调用: +[[EMClient sharedClient].groupManager getGroupSpecificationFromServerWithId:self.group.groupId fetchMembers:YES completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + // EMGroup中包含了很多群组属性,比如群组id,群组成员,是否屏蔽群组消息(isBlocked属性)等,具体到SDK中EMGroup.h头文件查看 + NSLog(@"获取群组详情成功"); + } else { + NSLog(@"获取群组详情失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 加入群组 + +群组分4种类型,目前 SDK 不支持自主选择是否进群。我们将针对每种类型讲解加入群组要进行的操作。 + +- EMGroupStylePrivateOnlyOwnerInvite: 该类型的群组只允许群主(Owner)添加人进群,其他人无法主动加入。 +- EMGroupStylePrivateMemberCanInvite: (推荐使用)该类型的群组允许所有群成员添加人进群,其他人无法主动加入。 +- EMGroupStylePublicJoinNeedApproval: (推荐使用)该类型的群组只允许群主(Owner)添加人进群;其他人想进入群组的话,需要先发送申请,群主同意申请之后才能进群;其他人无法主动加入。 +- EMGroupStylePublicOpenJoin: (不推荐使用)该类型的群组允许任何人主动加入群组。 + +#### 添加人进群 + +被添加的人会收到回调: + +``` +/*! + * SDK自动同意了用户A的加B入群邀请后,用户B接收到该回调,需要设置EMGroupOptions的isAutoAcceptGroupInvitation为YES + * + * @param aGroup 群组实例 + * @param aInviter 邀请者 + * @param aMessage 邀请消息 + */ +- (void)didJoinGroup:(EMGroup *)aGroup + inviter:(NSString *)aInviter + message:(NSString *)aMessage; +``` + +加人接口如下: + +``` +/*! + * 邀请用户加入群组 + * + * @param aUsers 被邀请的用户名列表 + * @param aGroupId 群组ID + * @param aMessage 欢迎信息 + * @param aCompletionBlock 完成的回调 + */ +- (void)addMembers:(NSArray *)aUsers + toGroup:(NSString *)aGroupId + message:(NSString *)aMessage + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager addMembers:@[@"user1"] toGroup:@"groupId" message:@"邀请您加入群组" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"邀请加群成功 --- %@", aGroup); + } else { + NSLog(@"邀请加群失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +#### 发送进群申请 + +``` +/*! + * 申请加入一个需批准的公开群组,群类型应该是EMGroupStylePublicJoinNeedApproval + * + * @param aGroupId 公开群组的ID + * @param aMessage 请求加入的信息 + * @param aCompletionBlock 完成的回调 + */ +- (void)requestToJoinPublicGroup:(NSString *)aGroupId + message:(NSString *)aMessage + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager requestToJoinPublicGroup:@"groupId" message:@"申请加入群组" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"申请加公开群成功 --- %@", aGroup); + } else { + NSLog(@"申请加公开群失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +#### 处理进群申请 + +只有 Owner 有权限处理进群申请。 + +1. 收到进群申请。 + +``` +/*! + * 群组的群主收到用户的入群申请,群的类型是EMGroupStylePublicJoinNeedApproval + * + * @param aGroup 群组实例 + * @param aApplicant 申请者 + * @param aReason 申请者的附属信息 + */ +- (void)joinGroupRequestDidReceive:(EMGroup *)aGroup + user:(NSString *)aUsername + reason:(NSString *)aReason; +``` + +2. 同意进群申请。 + +``` +/*! + * 批准入群申请, 需要Owner权限 + * + * @param aGroupId 所申请的群组ID + * @param aUsername 申请人 + * @param aCompletionBlock 完成的回调 + */ +- (void)approveJoinGroupRequest:(NSString *)aGroupId + sender:(NSString *)aUsername + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +//调用: +[[EMClient sharedClient].groupManager approveJoinGroupRequest:@"groupId" sender:@"userId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"批准入群申请成功 --- %@", aGroup); + } else { + NSLog(@"批准入群申请失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +3. 拒绝加群申请。 + +``` +/*! + * 拒绝入群申请, 需要Owner权限 + * + * @param aGroupId 被拒绝的群组ID + * @param aUsername 申请人 + * @param aReason 拒绝理由 + * @param aCompletionBlock 完成的回调 + */ +- (void)declineJoinGroupRequest:(NSString *)aGroupId + sender:(NSString *)aUsername + reason:(NSString *)aReason + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager declineJoinGroupRequest:@"groupId" sender:@"userId" reason:@"拒绝的原因" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"拒绝入群申请成功 --- %@", aGroup); + } else { + NSLog(@"拒绝入群申请失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +#### 加入 EMGroupStylePublicOpenJoin 类型的群组 + +``` +/*! + * 加入一个公开群组,群类型应该是EMGroupStylePublicOpenJoin + * + * @param aGroupId 公开群组的ID + * @param aCompletionBlock 完成的回调 + */ +- (void)joinPublicGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager joinPublicGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"加入公开群成功 --- %@", aGroup); + } else { + NSLog(@"加入公开群失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 退出群组 + +群主(Owner)不支持退群操作,只能解散群。 + +退出群组分为主动退群和被动退群。被动退群即为被 Owner 踢出群组。 + +#### 主动退群 + +``` +/*! + * 退出群组,owner不能退出群,只能销毁群 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)leaveGroup:(NSString *)aGroupId + completion:(void (^)(EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager leaveGroup:@"groupId" completion:^(EMError *aError) { + if (!aError) { + NSLog(@"退出群组成功"); + } else { + NSLog(@"退出群组失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +#### 被动退群 + +会通过以下回调通知被踢者。 + +``` +/*! + * 离开群组回调 + * + * @param aGroup 群组实例 + * @param aReason 离开原因 + */ +- (void)didLeaveGroup:(EMGroup *)aGroup + reason:(EMGroupLeaveReason)aReason; +``` + +### 解散群组 + +解散群组需要 Owner 权限。 + +``` +/*! + * 解散群组, 需要owner权限 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)destroyGroup:(NSString *)aGroupId + finishCompletion:(void (^)(EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager destroyGroup:@"groupId" finishCompletion:^(EMError *aError) { + if (!aError) { + NSLog(@"解散群组成功"); + } else { + NSLog(@"解散群组失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 修改群主题(名称) + +只有 Owner 有权限修改。 + +``` +/*! + * \~chinese + * 更改群组主题, 需要owner权限 + * + * @param aSubject 新主题 + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + * + * + * \~english + * Change the group subject, owner‘s authority is required + * + * @param aSubject New group‘s subject + * @param aGroupId Group id + * @param aCompletionBlock The callback block of completion + * + */ +- (void)updateGroupSubject:(NSString *)aSubject + forGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager updateGroupSubject:@"更改群组主题" forGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"更改群组主题成功 --- %@", aGroup.subject); + } else { + NSLog(@"更改群组主题失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 修改群描述 + +**不推荐使用** ,只有 Owner 有权限操作。 + +``` +/*! + * 更改群组说明信息, 需要owner权限 + * + * @param aDescription 说明信息 + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)updateDescription:(NSString *)aDescription + forGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager updateDescription:@"更改群组说明信息" forGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"群组说明信息更改成功 --- %@", aGroup.description); + } else { + NSLog(@"群组说明信息更改失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 获取群组成员列表 + +按照群成员进群时间先后排序,后进群排在前面。 + +``` +/*! + * 获取群组成员列表 + * + * @param aGroupId 群组ID + * @param aCursor 游标 + * @param aPageSize 获取多少条 + * @param aCompletionBlock 完成的回调 + */ +- (void)getGroupMemberListFromServerWithId:(NSString *)aGroupId + cursor:(NSString *)aCursor + pageSize:(NSInteger)aPageSize + completion:(void (^)(EMCursorResult *aResult, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager getGroupMemberListFromServerWithId:@"groupId" cursor:@"cursor" pageSize:10 completion:^(EMCursorResult *aResult, EMError *aError) { + if (!aError) { + // aResult.list: 返回的成员列表,内部的值是成员的环信id。 + // aResult.cursor: 返回的cursor,如果要取下一页的列表,需要将这个cursor当参数传入到获取群组成员列表中。 + NSLog(@"获取群组成员列表成功 --- %@", aResult); + } else { + NSLog(@"获取群组成员列表失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 获取群组群主及群组管理员 + +建议先获取到群组详情,然后从返回的aGroup对象中获取群主以及管理员。 + +``` +// 获取群组详情的方法 +[[EMClient sharedClient].groupManager getGroupSpecificationFromServerWithId:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + // 获取群主 + NSString *owner = aGroup.owner; + + // 获取群管理 + NSArray *adminList = aGroup.adminList; + } else { + NSLog(@"获取失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 获取群组黑名单列表 + +需要owner或admin权限 + +``` +/*! + * 获取群组黑名单列表, 需要owner/admin权限 + * + * @param aGroupId 群组ID + * @param aPageNum 获取第几页 + * @param aPageSize 获取多少条 + * @param aCompletionBlock 完成的回调 + */ +- (void)getGroupBlacklistFromServerWithId:(NSString *)aGroupId + pageNumber:(NSInteger)aPageNum + pageSize:(NSInteger)aPageSize + completion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager getGroupBlacklistFromServerWithId:@"groupId" pageNumber:1 pageSize:50 completion:^(NSArray *aList, EMError *aError) { + if (!aError) { + NSLog(@"获取群组黑名单列表成功 --- %@", aList); + } else { + NSLog(@"获取群组黑名单列表失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 白名单管理 + +可以将用户添加到白名单中,用户白名单在管理员开启了全员禁言时生效,可以运行白名单用户发出消息。 另外可以将用户移出白名单,检查自己是否在白名单中以及获取白名单列表。 + +``` +/*! + * \~chinese + * 添加白名单,需要Owner / Admin权限 + * + * @param aMembers 被添加的列表 + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)addWhiteListMembers:(NSArray *)aMembers + fromGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +/*! + * \~chinese + * 移除白名单,需要Owner / Admin权限 + * + * @param aMembers 被移除的列表 + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)removeWhiteListMembers:(NSArray *)aMembers + fromGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + + +/*! + * \~chinese + * 查看自己是否在群组白名单中 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)isMemberInWhiteListFromServerWithGroupId:(NSString *)aGroupId + completion:(void (^)(BOOL inWhiteList, EMError *aError))aCompletionBlock; + + +/*! + * \~chinese + * 获取群组白名单列表 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)getGroupWhiteListFromServerWithId:(NSString *)aGroupId + completion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; +``` + +### 开启和关闭全员禁言 + +owner和管理员可以开启和关闭全员禁言。 + +``` +/*! + * \~chinese + * 设置全员禁言,需要Owner / Admin权限 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)muteAllMembersFromGroup:(NSString *)aGroupId + completion:(void(^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + + +/*! + * \~chinese + * 解除全员禁言,需要Owner / Admin权限 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)unmuteAllMembersFromGroup:(NSString *)aGroupId + completion:(void(^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; +``` + +### 获取被禁言列表 + +需要owner或admin权限 + +``` +/*! + * 获取群组被禁言列表 + * + * @param aGroupId 群组ID + * @param aPageNum 获取第几页 + * @param aPageSize 获取多少条 + * @param aCompletionBlock 完成的回调 + */ +- (void)getGroupMuteListFromServerWithId:(NSString *)aGroupId + pageNumber:(NSInteger)aPageNum + pageSize:(NSInteger)aPageSize + completion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager getGroupMuteListFromServerWithId:@"groupId" pageNumber:1 pageSize:50 completion:^(NSArray *aList, EMError *aError) { + if (!aError) { + NSLog(@"获取群组被禁言列表成功 --- %@", aList); + } else { + NSLog(@"获取群组被禁言列表失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 获取群公告 + +``` +/*! + * 获取群公告 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)getGroupAnnouncementWithId:(NSString *)aGroupId + completion:(void (^)(NSString *aAnnouncement, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager getGroupAnnouncementWithId:@"groupId" completion:^(NSString *aAnnouncement, EMError *aError) { + if(!aError){ + NSLog(@"获取群公告成功 --- %@", aAnnouncement); + } else { + NSLog(@"获取群公告失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 修改群公告 + +``` +/*! + * 修改群公告,需要Owner / Admin权限 + * + * @param aGroupId 群ID + * @param aAnnouncement 群公告 + * @param aCompletionBlock 完成的回调 + */ +- (void)updateGroupAnnouncementWithId:(NSString *)aGroupId + announcement:(NSString *)aAnnouncement + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; +// 调用: +[[EMClient sharedClient].groupManager updateGroupAnnouncementWithId:@"groupId" announcement:@"announcement" completion:^(EMGroup *aGroup, EMError *aError) { + if(!aError){ + NSLog(@"修改群公告成功"); + } else { + NSLog(@"修改群公告失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +当群主或者管理员修改群公告时,其它群成员会收到群公告更新的回调 + +``` +/*! + * 群公告有更新 + * + * @param aGroup 群组 + * @param aAnnouncement 群公告 + */ +- (void)groupAnnouncementDidUpdate:(EMGroup *)aGroup + announcement:(NSString *)aAnnouncement; +``` + +### 获取群共享文件列表 + +``` +/*! + * 获取群共享文件列表 + * + * @param aGroupId 群组ID + * @param aPageNum 获取第几页 + * @param aPageSize 获取多少条 + * @param aCompletionBlock 完成的回调 + */ +- (void)getGroupFileListWithId:(NSString *)aGroupId + pageNumber:(NSInteger)aPageNum + pageSize:(NSInteger)aPageSize + completion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager getGroupFileListWithId:@"groupId" pageNumber:1 pageSize:10 completion:^(NSArray *aList, EMError *aError) { + if(!aError){ + // aList数组里面是 EMGroupSharedFile 对象 + NSLog(@"获取群共享文件列表成功 --- %@", aList); + } else { + NSLog(@"获取群共享文件列表失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 上传下载群共享文件 + +``` +/*! + * 上传群共享文件 + * + * @param aGroupId 群ID + * @param aFilePath 文件路径 + * @param pError 错误信息 + * + * @result 群实例 + */ +- (void)uploadGroupSharedFileWithId:(NSString *)aGroupId + filePath:(NSString*)aFilePath + progress:(void (^)(int progress))aProgressBlock + completion:(void (^)(EMGroupSharedFile *aSharedFile, EMError *aError))aCompletionBlock; + +/*! + * 下载群共享文件 + * + * @param aGroupId 群ID + * @param aFilePath 文件路径 + * @param aSharedFileId 共享文件ID + * @param aProgressBlock 文件下载进度回调block + * @param aCompletionBlock 完成回调block + */ +- (void)downloadGroupSharedFileWithId:(NSString *)aGroupId + filePath:(NSString *)aFilePath + sharedFileId:(NSString *)aSharedFileId + progress:(void (^)(int progress))aProgressBlock + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager uploadGroupSharedFileWithId:@"groupId" filePath:@"filePath" progress:^(int progress) { + NSLog(@"上传文件进度 --- %d", progress); +} completion:^(EMGroupSharedFile *aSharedFile, EMError *aError) { + if(!aError){ + // EMGroupSharedFile中包含文件名称,文件发布者,文件创建时间,文件大小 + NSLog(@"上传群共享文件成功"); + } else { + NSLog(@"上传群共享文件失败的原因 --- %@", aError.errorDescription); + } +}]; + +// 调用: +[[EMClient sharedClient].groupManager downloadGroupSharedFileWithId:@"groupId" filePath:@"filePath" sharedFileId:@"sharedFileId" progress:^(int progress) { + NSLog(@"下载文件进度 --- %d", progress); +} completion:^(EMGroup *aGroup, EMError *aError) { + if(!aError){ + NSLog(@"下载群共享文件成功"); + } else { + NSLog(@"下载群共享文件失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +当群中有人上传群共享文件时,其它群成员会受到新有群文件上传的回调 + +``` +/*! + * 有用户上传群共享文件 + * + * @param aGroup 群组 + * @param aSharedFile 共享文件 + */ +- (void)groupFileListDidUpdate:(EMGroup *)aGroup + addedSharedFile:(EMGroupSharedFile *)aSharedFile; +``` + +### 删除群共享文件 + +``` +/*! + * 删除群共享文件 + * + * @param aGroupId 群ID + * @param aSharedFileId 共享文件ID + * @param aCompletionBlock 完成的回调 + */ +- (void)removeGroupSharedFileWithId:(NSString *)aGroupId + sharedFileId:(NSString *)aSharedFileId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager removeGroupSharedFileWithId:@"groupId" sharedFileId:@"sharedFileId" completion:^(EMGroup *aGroup, EMError *aError) { + if(!aError){ + NSLog(@"删除群共享文件成功"); + } else { + NSLog(@"删除群共享文件失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +当群中有人删除群共享文件时,其它群成员会受到有人删除群文件的回调 + +``` +/*! + * 有用户删除群共享文件 + * + * @param aGroup 群组 + * @param aFileId 共享文件ID + */ +- (void)groupFileListDidUpdate:(EMGroup *)aGroup + removedSharedFile:(NSString *)aFileId; +``` + +### 修改群扩展 + +``` +/*! + * 修改群扩展信息,需要Owner权限 + * + * @param aGroupId 群ID + * @param aExt 扩展信息 + * @param aCompletionBlock 完成的回调 + */ +- (void)updateGroupExtWithId:(NSString *)aGroupId + ext:(NSString *)aExt + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager updateGroupExtWithId:@"groupId" ext:@"ext" completion:^(EMGroup *aGroup, EMError *aError) { + if(!aError){ + NSLog(@"修改群扩展信息成功"); + } else { + NSLog(@"修改群扩展信息失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +## 群成员管理 + +### 改变群主 + +只有 Owner 权限才能调用该接口。 + +***Api:*** + +``` +/*! + * 改变群主,需要Owner权限 + * + * 同步方法,会阻塞当前线程 + * + * @param aGroupId 群ID + * @param aNewOwner 新群主 + * @param pError 错误信息 + * + * @result 返回群组实例 + */ +- (EMGroup *)updateGroupOwner:(NSString *)aGroupId + newOwner:(NSString *)aNewOwner + error:(EMError **)pError; + +/*! + * 改变群主,需要Owner权限 + * + * @param aGroupId 群ID + * @param aNewOwner 新群主 + * @param aCompletionBlock 完成的回调 + */ +- (void)updateGroupOwner:(NSString *)aGroupId + newOwner:(NSString *)aNewOwner + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; +``` + +***Delegate:*** + +``` +/*! + * 群组创建者有更新 + * + * @param aGroup 群组 + * @param aNewOwner 新群主 + * @param aOldOwner 旧群主 + */ +- (void)groupOwnerDidUpdate:(EMGroup *)aGroup + newOwner:(NSString *)aNewOwner + oldOwner:(NSString *)aOldOwner; + +// 调用: +[[EMClient sharedClient].groupManager updateGroupOwner:@"groupId" newOwner:@"newOwner" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"群组创建者更新成功"); + } else { + NSLog(@"群组创建者更新失败的原因 --- %@", aError.errorDescription); + } +}]; + +``` + +### 添加群组管理员 + +只有 Owner 权限才能调用。 + +***Api:*** + +``` +/*! + * 添加群组管理员,需要Owner权限 + * + * 同步方法,会阻塞当前线程 + * + * @param aAdmin 要添加的群组管理员 + * @param aGroupId 群ID + * @param pError 错误信息 + * + * @result 返回群组实例 + */ +- (EMGroup *)addAdmin:(NSString *)aAdmin + toGroup:(NSString *)aGroupId + error:(EMError **)pError; + +/*! + * 添加群组管理员,需要Owner权限 + * + * @param aAdmin 要添加的群组管理员 + * @param aGroupId 群ID + * @param aCompletionBlock 完成的回调 + */ +- (void)addAdmin:(NSString *)aAdmin + toGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用示例: +[[EMClient sharedClient].groupManager addAdmin:@"adminName" toGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"添加群组管理员成功"); + } else { + NSLog(@"添加群组管理员失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +***Delegate:*** + +``` +/*! + * 有成员被加入管理员列表 + * + * @param aGroup 群组 + * @param aAdmin 加入管理员列表的成员 + */ +- (void)groupAdminListDidUpdate:(EMGroup *)aGroup + addedAdmin:(NSString *)aAdmin; +``` + +### 移除群组管理员 + +只有 Owner 权限才能调用。 + +***Api:*** + +``` +/*! + * 移除群组管理员,需要Owner权限 + * + * @param aAdmin 要添加的群组管理员 + * @param aGroupId 群ID + * @param aCompletionBlock 完成的回调 + */ +- (void)removeAdmin:(NSString *)aAdmin + fromGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager removeAdmin:@"adminName" fromGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"移除群组管理员成功"); + } else { + NSLog(@"移除群组管理员失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +***Delegate:*** + +``` +/*! + * 有成员被移出禁言列表 + * + * @param aGroup 群组 + * @param aMutedMembers 移出禁言列表的成员 + */ +- (void)groupMuteListDidUpdate:(EMGroup *)aGroup + removedMutedMembers:(NSArray *)aMutedMembers; +``` + +### 移除群组成员 + +只有 Owner或者Admin 权限才能调用。 + +``` +/*! + * 将群成员移出群组 + * + * @param aUsers 要移出群组的用户列表 + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)removeMembers:(NSArray *)aUsers + fromGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager removeMembers:@[@"user1"] fromGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"将群成员移出群组成功"); + } else { + NSLog(@"将群成员移出群组失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 禁言群成员 + +权限高者可禁言权限低者,反之不允许 + +***Api:*** + +``` +/*! + * 将一组成员禁言,需要Owner / Admin权限 + * + * @param aMuteMembers 要禁言的成员列表 + * @param aMuteMilliseconds 禁言时长(单位毫秒,如果是“-1”代表永久禁言) + * @param aGroupId 群ID + * @param aCompletionBlock 完成的回调 + */ +- (void)muteMembers:(NSArray *)aMuteMembers + muteMilliseconds:(NSInteger)aMuteMilliseconds + fromGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager muteMembers:@[@"user1"] muteMilliseconds:10000 fromGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"将一组成员禁言成功"); + } else { + NSLog(@"将一组成员禁言失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +***Delegate:*** + +``` +/*! + * 有成员被加入禁言列表 + * + * @param aGroup 群组 + * @param aMutedMembers 被禁言的成员 + * @param aMuteExpire 禁言失效时间,当前不可用 + */ +- (void)groupMuteListDidUpdate:(EMGroup *)aGroup + addedMutedMembers:(NSArray *)aMutedMembers + muteExpire:(NSInteger)aMuteExpire; +``` + +### 解除禁言 + +权限高者可禁言权限低者,反之不允许 + +***Api:*** + +``` +/*! + * 解除禁言,需要Owner / Admin权限 + * + * @param aMuteMembers 被解除的列表 + * @param aGroupId 群ID + * @param aCompletionBlock 完成的回调 + */ +- (void)unmuteMembers:(NSArray *)aMembers + fromGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager unmuteMembers:@[@"user1"] fromGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"解除禁言成功"); + } else { + NSLog(@"解除禁言失败的原因 --- %@", aError.errorDescription); + } +}]; + +``` + +***Delegate:*** + +``` +/*! + * 有成员被移出禁言列表 + * + * @param aGroup 群组 + * @param aMutedMembers 移出禁言列表的成员 + */ +- (void)groupMuteListDidUpdate:(EMGroup *)aGroup + removedMutedMembers:(NSArray *)aMutedMembers; +``` + +### 设置全员禁言 + +群主和群组管理员默认不会被禁言 + +***Api:*** + +``` +/*! + * \~chinese + * 设置全员禁言,需要Owner / Admin权限 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + * + * \~english + * mute all members, need Owner / Admin permissions + * + * @param aGroupId Group id + * @param aCompletionBlock The callback block of completion + * + */ +- (void)muteAllMembersFromGroup:(NSString *)aGroupId + completion:(void(^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager muteAllMembersFromGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"全员禁言成功"); + } else { + NSLog(@"全员禁言失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +***Delegate:*** + +``` +/*! +* \~chinese +* 群组全部禁言状态变化 +* +* @param aGroup 群组 +* @param aMuted 是否被全部禁言 +* +* \~english +* Group members are all muted +* +* @param aGroup Group +* @param aMuted All member muted +*/ +- (void)groupAllMemberMuteChanged:(EMGroup *)aGroup + isAllMemberMuted:(BOOL)aMuted; +``` + +### 解除全员禁言 + +***Api:*** + +``` +/*! + * \~chinese + * 解除全员禁言,需要Owner / Admin权限 + * + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + * + * \~english + * unmute all members, need Owner / Admin permissions + * + * @param aGroupId Group id + * @param aCompletionBlock The callback block of completion + * + */ +- (void)unmuteAllMembersFromGroup:(NSString *)aGroupId + completion:(void(^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager unmuteAllMembersFromGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"解除全员禁言成功") + } else { + NSLog(@"解除全员禁言失败的原因 --- %@", aError.errorDescription); + } +}]; + +``` + +***Delegate:*** + +``` +/*! +* \~chinese +* 群组全部禁言状态变化 +* +* @param aGroup 群组 +* @param aMuted 是否被全部禁言 +* +* \~english +* Group members are all muted +* +* @param aGroup Group +* @param aMuted All member muted +*/ +- (void)groupAllMemberMuteChanged:(EMGroup *)aGroup + isAllMemberMuted:(BOOL)aMuted; +``` + +### 加入群黑名单 + +只有 Owner 权限才能调用该接口,并且只有 Owner 权限的才能查看群黑名单。 + +可以将群成员和非群成员的人加入群黑名单。 + +``` +/*! + * 加人到群组黑名单, 需要owner权限 + * + * @param aMembers 要加入黑名单的用户 + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)blockMembers:(NSArray *)aMembers + fromGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager blockMembers:@[@"users1"] fromGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"加人到群组黑名单成功"); + } else { + NSLog(@"加人到群组黑名单失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 移出群黑名单 + +只有 Owner 权限才能调用该接口,并且只有 Owner 权限的才能查看群黑名单。 + +从群黑名单移除出去,该用户已经不在群组里了,需要重新加入群组。 + +``` +/*! + * 从群组黑名单中减人, 需要owner权限 + * + * @param aMembers 要从黑名单中移除的用户名列表 + * @param aGroupId 群组ID + * @param aCompletionBlock 完成的回调 + */ +- (void)unblockMembers:(NSArray *)aMembers + fromGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager unblockMembers:@[@"users1"] fromGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"从群组黑名单中减人成功"); + } else { + NSLog(@"从群组黑名单中减人失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +## 群消息 + +### 屏蔽/取消屏蔽群组消息 + +不允许 Owner 权限的调用。 + +``` +/*! + * 屏蔽群消息,服务器不再发送此群的消息给用户,owner不能屏蔽群消息 + * + * @param aGroupId 要屏蔽的群ID + * @param aCompletionBlock 完成的回调 + */ +- (void)blockGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager blockGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"屏蔽群消息成功"); + } else { + NSLog(@"屏蔽群消息失败的原因 --- %@", aError.errorDescription); + } +}]; + +/*! + * 取消屏蔽群消息 + * + * @param aGroupId 要取消屏蔽的群ID + * @param aCompletionBlock 完成的回调 + */ +- (void)unblockGroup:(NSString *)aGroupId + completion:(void (^)(EMGroup *aGroup, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager unblockGroup:@"groupId" completion:^(EMGroup *aGroup, EMError *aError) { + if (!aError) { + NSLog(@"取消屏蔽群消息成功"); + } else { + NSLog(@"取消屏蔽群消息失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +## 管理群组的 APNS 离线推送 + +见 [APNS离线推送-设置指定群组是否接收APNS](offline#设置群组免打扰)。 + +## 获取与登录者相关的群组 + +查看所有当前登录账号所在群组,包括创建的和加入的群组,提供了2种方法。 + +1.从服务器获取与我相关的群组列表 + +``` +[[EMClient sharedClient].groupManager getJoinedGroupsFromServerWithPage:1 pageSize:50 completion:^(NSArray *aList, EMError *aError) { + if (!aError) { + NSLog(@"获取群组列表成功 --- %@", aList); + } else { + NSLog(@"获取群组列表失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +2. 取内存中的值 + +从服务器获与登录者相关的群组列表之后,才能从本地获取到群组列表 + +``` +// 从内存中获取所有群组,第一次从数据库加载 +NSArray *groupList = [[EMClient sharedClient].groupManager getJoinedGroups]; +``` + +## 获取公开群组 + +获取指定范围内的公开群。 + +``` +/*! + * 从服务器获取指定范围内的公开群 + * + * @param aCursor 获取公开群的cursor,首次调用传空 + * @param aPageSize 期望返回结果的数量, 如果 < 0 则一次返回所有结果 + * @param aCompletionBlock 完成的回调 + */ +- (void)getPublicGroupsFromServerWithCursor:(NSString *)aCursor + pageSize:(NSInteger)aPageSize + completion:(void (^)(EMCursorResult *aResult, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].groupManager getPublicGroupsFromServerWithCursor:nil pageSize:50 completion:^(EMCursorResult *aResult, EMError *aError) { + if (!aError) { + NSLog(@"获取公开群组成功 --- %@", aResult); + } else { + NSLog(@"获取公开群组失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +------ \ No newline at end of file diff --git a/docs/document/v1/ios/group_attributes.md b/docs/document/v1/ios/group_attributes.md index e064d5b71..86c4f47f8 100644 --- a/docs/document/v1/ios/group_attributes.md +++ b/docs/document/v1/ios/group_attributes.md @@ -18,8 +18,8 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -- 了解群组和群成员的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 + ## 实现方法 diff --git a/docs/document/v1/ios/group_manage.md b/docs/document/v1/ios/group_manage.md index 8d5573aba..48d15452c 100644 --- a/docs/document/v1/ios/group_manage.md +++ b/docs/document/v1/ios/group_manage.md @@ -22,8 +22,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -- 了解群组和群成员的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 diff --git a/docs/document/v1/ios/group_members.md b/docs/document/v1/ios/group_members.md index 781231138..dabf4e41e 100644 --- a/docs/document/v1/ios/group_members.md +++ b/docs/document/v1/ios/group_members.md @@ -8,8 +8,8 @@ 环信即时通讯 IM iOS SDK 提供 `IEMGroupManager` 类和 `EMGroup` 类用于群组管理,支持你通过调用 API 在项目中实现如下功能: + - 加入、退出群组 -- 管理群成员的自定义属性 - 管理群主及群管理员 - 管理群组白名单 - 管理群组黑名单 @@ -20,9 +20,9 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 - 了解群成员角色,详见 [群组功能介绍](group_overview.html)。 -- 了解群组和群成员的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 + ## 实现方法 @@ -176,7 +176,7 @@ do { fromGroup:@"groupsID" completion:nil]; ``` - + ### 管理群主和群管理员 #### 变更群主 diff --git a/docs/document/v1/ios/message.md b/docs/document/v1/ios/message.md new file mode 100644 index 000000000..779a14bd8 --- /dev/null +++ b/docs/document/v1/ios/message.md @@ -0,0 +1,1256 @@ +# 消息管理 + + +消息:IM 交互实体,在 SDK 中对应的类型是 **EMChatMessage**。**EMChatMessage** 由 EMMessageBody 组成。 + +消息涉及到的环信SDK头文件如下: + +``` +// 消息构建部分 +EMChatMessage.h +EMMessageBody.h +EMTextMessageBody.h +EMImageMessageBody.h +EMVoiceMessageBody.h +EMVideoMessageBody.h +EMFileMessageBody.h +EMLocationMessageBody.h +EMCmdMessageBody.h + +// 消息方法调用部分,比如添加代理,移除代理,发送消息等,同时也包含会话相关的操作,比如创建或获取会话,获取会话列表等 +IEMChatManager.h + +// 消息的协议回调方法部分,比如监听接收消息的回调方法等 +EMChatManagerDelegate.h +``` + +## 构造消息 + +以下构造消息的示例中,使用到的“初始化消息实例”方法的说明: + +``` +/*! + * 初始化消息实例 + * + * @param aConversationId 会话ID + * @param aFrom 发送方 + * @param aTo 接收方 + * @param aBody 消息体实例 + * @param aExt 扩展信息 + * + * @result 消息实例 + */ +- (id)initWithConversationID:(NSString *)aConversationId + from:(NSString *)aFrom + to:(NSString *)aTo + body:(EMMessageBody *)aBody + ext:(NSDictionary *)aExt; + +``` + +aConversationId: 会话id,比如a给b发送了一条消息,那么SDK会在a这边生成一个会话,会话id就是b,在构建消息时aConversationId与to保持一致。 + +to: 表示接收消息方的环信id。 + +from: 表示当前登录的环信id,一般使用 [EMClient sharedClient].currentUsername; 方法获取。 + +:::notice +如果是给群组或者聊天室发消息,那么aConversationId和to要换成群组id或者聊天室id +::: + +总体来说是当前登录的环信id要给哪个环信id或哪个群组id或哪个聊天室id发消息。 + +### 构造文字消息 + +``` +/*! + * 初始化文本消息体 + * + * @param aText 文本内容 + * + * @result 文本消息体实例 + */ +- (instancetype)initWithText:(NSString *)aText; + +// 调用: +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"]; +// 获取当前登录的环信id +NSString *from = [[EMClient sharedClient] currentUsername]; + +//生成Message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 构造表情消息 + +发表情消息实质上是发文本消息。接收方收到文本消息后,首先查询文本消息是否是表情消息,如果是,则显示该文本消息为对应的表情图片。可以使用[emoji标准](https://unicode.org/emoji/charts/full-emoji-list.html)来做表情图片和对应的文本字符串的映射。也可以自行维护表情图片和文本字符串的映射。 + +``` +/*! + * 初始化表情消息体 + * + * @param aText 表情消息文本串 + * + * @result 表情消息体实例 + */ +- (instancetype)initWithText:(NSString *)aText; + +// 调用: +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的表情消息文本串"]; +// 获取当前登录的环信id +NSString *from = [[EMClient sharedClient] currentUsername]; + +//生成Message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 构造图片消息 + +``` +/*! + * 初始化文件消息体 + * + * @param aData 附件数据 + * @param aDisplayName 附件显示名(不包含路径) + * + * @result 消息体实例 + */ +- (instancetype)initWithData:(NSData *)aData + displayName:(NSString *)aDisplayName; + +// 调用: +EMImageMessageBody *body = [[EMImageMessageBody alloc] initWithData:data displayName:@"image.png"]; +// body.compressionRatio = 1.0f; 1.0表示发送原图不压缩。默认值是0.6,压缩的倍数是0.6倍 +NSString *from = [[EMClient sharedClient] currentUsername]; + +//生成Message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 构造位置消息 + +``` +/*! + * 初始化位置消息体 + * + * @param aLatitude 纬度 + * @param aLongitude 经度 + * @param aAddress 地理位置信息 + * + * @result 位置消息体实例 + */ +- (instancetype)initWithLatitude:(double)aLatitude + longitude:(double)aLongitude + address:(NSString *)aAddress; + +// 调用: +EMLocationMessageBody *body = [[EMLocationMessageBody alloc] initWithLatitude:39 longitude:116 address:@"地址"]; +NSString *from = [[EMClient sharedClient] currentUsername]; + +// 生成message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + + +### 构造语音消息 + +``` +/*! + * 初始化文件消息体 + * + * @param aLocalPath 附件本地路径 + * @param aDisplayName 附件显示名(不包含路径) + * + * @result 消息体实例 + */ +- (instancetype)initWithLocalPath:(NSString *)aLocalPath + displayName:(NSString *)aDisplayName; + +// 调用: +EMVoiceMessageBody *body = [[EMVoiceMessageBody alloc] initWithLocalPath:@"audioPath" displayName:@"audio"]; +body.duration = duration; +NSString *from = [[EMClient sharedClient] currentUsername]; + +// 生成message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 构造视频消息 + +``` +/*! + * 初始化文件消息体 + * + * @param aLocalPath 附件本地路径 + * @param aDisplayName 附件显示名(不包含路径) + * + * @result 消息体实例 + */ +- (instancetype)initWithLocalPath:(NSString *)aLocalPath + displayName:(NSString *)aDisplayName; + +// 调用: +EMVideoMessageBody *body = [[EMVideoMessageBody alloc] initWithLocalPath:@"videoPath" displayName:@"video.mp4"]; +NSString *from = [[EMClient sharedClient] currentUsername]; + +// 生成message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 构造文件消息 + +``` +/*! + * 初始化文件消息体 + * + * @param aLocalPath 附件本地路径 + * @param aDisplayName 附件显示名(不包含路径) + * + * @result 消息体实例 + */ +- (instancetype)initWithLocalPath:(NSString *)aLocalPath + displayName:(NSString *)aDisplayName; + +// 调用: +EMFileMessageBody *body = [[EMFileMessageBody alloc] initWithLocalPath:@"filePath" displayName:@"file"]; +NSString *from = [[EMClient sharedClient] currentUsername]; + +// 生成message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 构造透传消息 + +SDK 提供的一种特殊类型的消息,即 CMD,不会存 db,也不会走 APNS 推送,类似一种指令型的消息。比如您的服务器要通知客户端做某些操作,您可以服务器和客户端提前约定好某个字段,当客户端收到约定好的字段时,执行某种特殊操作。另以“em_”和“easemob::”开头的action为内部保留字段,注意不要使用 + +``` +/*! + * 初始化命令消息体 + * 用户自己定义的字符串,接收到后,解析出自己定义的字符串,就知道某件事情发过来了。 + * ex. 用户要做位置共享,这里的字符串就可以是"loc",解析出"loc"后,就知道这条消息是位置共享的消息了,之后其他信息可以放到.ext属性中去解析。 + * ex. 用户如果需要做“阅后即焚”功能,这里就可以自己写一个字符串,如“Snap”,之后.ext里带上要删除的messageid,接收方收到后,就可以删除对应的message,到达阅后即焚的效果 + * + * @param aAction 命令内容 + * + * @result 命令消息体实例 + */ +- (instancetype)initWithAction:(NSString *)aAction; + +// 调用: +EMCmdMessageBody *body = [[EMCmdMessageBody alloc] initWithAction:action]; +NSString *from = [[EMClient sharedClient] currentUsername]; + +// 生成message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 构造自定义类型消息 + +:::tip +3.6.5及以上版本的SDK支持 +::: + +用户可以在以上几种消息之外,自己定义消息类型,方便用户的业务处理。 自定义消息类型支持用户自己设置一个消息的类型名称,这样用户可以添加多种自定义消息。 自定义消息的内容部分是key,value格式的,用户需要自己添加并解析该内容。 + +``` +// event为需要传递的自定义消息事件,比如礼物消息,可以设置event = @"gift" +// params类型为NSDictionary +EMCustomMessageBody *body = [[EMCustomMessageBody alloc] initWithEvent:event ext: params]; +NSString *from = [[EMClient sharedClient] currentUsername]; + +//生成Message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; // ext:扩展消息部分 +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 构造扩展消息 + +当 SDK 提供的消息类型不满足需求时,开发者可以通过扩展自 SDK 提供的文本、语音、图片、位置等消息类型,从而生成自己需要的消息类型。 + +:::tip +Key值类型必须是NSString, Value值类型必须是NSString或者 NSNumber类型的 BOOL, int, unsigned in, long long, double +::: + +这里是扩展自文本消息,如果这个自定义的消息需要用到语音或者图片等,可以扩展自语音、图片消息,亦或是位置消息。 + +``` +// 以单聊消息举例 +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"]; +NSString *from = [[EMClient sharedClient] currentUsername]; + +//生成Message +NSDictionary *messageExt = @{@"key":@"value"}; +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt]; // ext:扩展消息部分 +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +``` + +### 插入消息 + +#### 方法一 + +直接插入,这样插入会不验证消息所在的EMConversation对象是否存在,直接将消息插入到数据库中 + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要插入的消息"]; +NSString *from = [[EMClient sharedClient] currentUsername]; + +//生成Message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 + +[[EMClient sharedClient].chatManager importMessages:@[message] completion:^(EMError *aError) { + if (!aError) { + NSLog(@"导入一组消息到DB成功"); + } else { + NSLog(@"导入一组消息到DB失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +#### 方法二 + +这种插入方式,会验证所在的EMConversation对象的存在,插入后,会更新EMConversation对象中的属性,比如LatestMessage + +``` +EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要插入的消息"]; +NSString *from = [[EMClient sharedClient] currentUsername]; + +//生成Message +EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:nil]; +message.chatType = EMChatTypeChat;// 设置为单聊消息 +//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息 +//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息 +//message.timestamp = 1509689222137; 消息时间 +EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:message.conversationId type:EMConversationTypeChat createIfNotExist:YES]; + // type: 会话类型 + // EMConversationTypeChat // 单聊 + // EMConversationTypeGroupChat // 群聊 + // EMConversationTypeChatRoom // 聊天室 +[conversation insertMessage:message error:nil]; +``` + +### 更新消息属性 + +``` +/*! + * 更新消息到DB + * + * @param aMessage 消息 + * @param aCompletionBlock 完成的回调 + */ +- (void)updateMessage:(EMMessage *)aMessage + completion:(void (^)(EMMessage *aMessage, EMError *aError))aCompletionBlock; + +//调用: +[[EMClient sharedClient].chatManager updateMessage:nil completion:^(EMMessage *aMessage, EMError *aError) { + if (!aError) { + NSLog(@"更新消息到DB成功"); + } else { + NSLog(@"更新消息到DB失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +## 会话 + +会话涉及到的环信SDK头文件如下: + +``` +// 会话部分,包含会话id,会话类型等 +EMConversation.h + +// 会话方法调用部分,包含创建或获取会话,获取会话列表等 +IEMChatManager.h +``` + +会话:操作聊天消息 **EMMessage** 的容器,在 SDK 中对应的类型是 **EMConversation**。 + +### 新建/获取一个会话 + +根据 conversationId 创建一个 conversation。 + +``` +/*! + * 获取一个会话 + * + * @param aConversationId 会话ID + * @param aType 会话类型 + * @param aIfCreate 如果不存在是否创建 + * + * @result 会话对象 + */ +- (EMConversation *)getConversation:(NSString *)aConversationId + type:(EMConversationType)aType + createIfNotExist:(BOOL)aIfCreate; + +// 调用: + +aConversationId: +单聊会话传接收消息方的环信id +群里会话传向群组内发消息的群组id +聊天室会话传向聊天室内发消息的聊天室id + +aType: +//EMConversationTypeChat 单聊会话 +//EMConversationTypeGroupChat 群聊会话 +//EMConversationTypeChatRoom 聊天室会话 + +[[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES]; +``` + +### 删除会话 + +#### 删除单个会话 + +``` +/*! + * 删除会话 + * + * @param aConversationId 会话ID + * @param aIsDeleteMessages 是否删除会话中的消息 + * @param aCompletionBlock 完成的回调 + */ +- (void)deleteConversation:(NSString *)aConversationId + isDeleteMessages:(BOOL)aIsDeleteMessages + completion:(void (^)(NSString *aConversationId, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].chatManager deleteConversation:@"8001" isDeleteMessages:YES completion:^(NSString *aConversationId, EMError *aError) { + if (!aError) { + NSLog(@"删除会话成功"); + } else { + NSLog(@"删除会话失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +#### 根据 conversationId 批量删除会话 + +``` +/*! + * 删除一组会话 + * + * @param aConversations 会话列表 + * @param aIsDeleteMessages 是否删除会话中的消息 + * @param aCompletionBlock 完成的回调 + */ +- (void)deleteConversations:(NSArray *)aConversations + isDeleteMessages:(BOOL)aIsDeleteMessages + completion:(void (^)(EMError *aError))aCompletionBlock; + + +EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:NO]; +// 调用: +[[EMClient sharedClient].chatManager deleteConversations:@[conversation] isDeleteMessages:YES completion:^(EMError *aError) { + if (!aError) { + NSLog(@"删除一组会话成功"); + } else { + NSLog(@"删除一组会话失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 获取本地会话列表 + +``` +/*! + * 获取所有会话,如果内存中不存在会从DB中加载 + * + * @result 会话列表 + */ +- (NSArray *)getAllConversations; + +// 调用: +NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations]; +``` + +### 从服务器获取会话列表 + + +该功能开通后,用户默认可拉取 7 天内的 10 个会话(每个会话包含最新一条历史消息),如需调整会话数量请联系环信商务经理。 + + +建议此api在首次安装应用时或者本地没有会话的时候调用,其他时候使用本地的会话api即可。默认最多返回100条数据。 +``` +[[EMClient sharedClient].chatManager getConversationsFromServer:^(NSArray *aCoversations, EMError *aError) { + if (!aError && [aCoversations count] > 0) { + //获取到会话列表后进行数据源装配和页面刷新 + } +}]; +``` + +### 获取会话中的所有消息计数 + +``` +// 获取会话中的消息数,以单聊为例,群组、聊天室一样 +EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES]; +[conversation messagesCount]; +``` + +### 获取单个会话未读消息数 + +``` +/*! + * \~chinese + * 获取一个会话 + * + * @param aConversationId 会话ID + * @param aType 会话类型 + * @param aIfCreate 如果不存在是否创建 + * + * @result 会话对象 + */ +- (EMConversation *)getConversation:(NSString *)aConversationId + type:(EMConversationType)aType + createIfNotExist:(BOOL)aIfCreate; + +// 获取单聊会话的未读消息数 +EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES]; +[conversation unreadMessagesCount]; + +// 获取群聊会话的未读消息数 +EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"121828583195137" type:EMConversationTypeGroupChat createIfNotExist:YES]; +[conversation unreadMessagesCount]; +``` + +### 获取所有会话未读消息数 + +SDK目前没提供直接获取全部会话未读消息数的方法,只能先获取会话列表,然后遍历取出每个会话的未读消息数进行累加,计算出所有会话的未读消息数。 + +``` +NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations]; +NSInteger unreadCount = 0; +for (EMConversation *conversation in conversations) { + unreadCount += conversation.unreadMessagesCount; +} +``` + +### 消息检索 + +可以通过关键字、消息类型、开始结束时间检索某个会话中的消息。使用EMConversation会话对象调用。 + +``` +/*! + * 从数据库获取指定数量的消息,取到的消息按时间排序,并且不包含参考的消息,如果参考消息的ID为空,则从最新消息取 + * + * @param aMessageId 参考消息的ID + * @param count 获取的条数 + * @param aDirection 消息搜索方向 + * @param aCompletionBlock 完成的回调 + */ +- (void)loadMessagesStartFromId:(NSString *)aMessageId + count:(int)aCount + searchDirection:(EMMessageSearchDirection)aDirection + completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock; + +// 调用: +EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES]; +[conversation loadMessagesStartFromId:messageId count:10 searchDirection:EMMessageSearchDirectionUp completion:^(NSArray *aMessages, EMError *aError) { + if (!aError) { + // aMessage数组中存的是EMMessage + NSLog(@"从数据库获取消息成功 --- %@", aMessages); + } else { + NSLog(@"删除一组会话失败的原因 --- %@", aError.errorDescription); + } +}]; + +/*! + * 从数据库获取指定类型的消息,取到的消息按时间排序,如果参考的时间戳为负数,则从最新消息取,如果aCount小于等于0当作1处理 + * + * @param aType 消息类型 + * @param aTimestamp 参考时间戳 + * @param aCount 获取的条数 + * @param aUsername 消息发送方,如果为空则忽略 + * @param aDirection 消息搜索方向 + * @param aCompletionBlock 完成的回调 + */ +- (void)loadMessagesWithType:(EMMessageBodyType)aType + timestamp:(long long)aTimestamp + count:(int)aCount + fromUser:(NSString*)aUsername + searchDirection:(EMMessageSearchDirection)aDirection + completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock; + +/*! + * 从数据库获取包含指定内容的消息,取到的消息按时间排序,如果参考的时间戳为负数,则从最新消息向前取,如果aCount小于等于0当作1处理 + * + * @param aKeywords 搜索关键字,如果为空则忽略 + * @param aTimestamp 参考时间戳 + * @param aCount 获取的条数 + * @param aSender 消息发送方,如果为空则忽略 + * @param aDirection 消息搜索方向 + * @param aCompletionBlock 完成的回调 + */ +- (void)loadMessagesWithKeyword:(NSString*)aKeyword + timestamp:(long long)aTimestamp + count:(int)aCount + fromUser:(NSString*)aSender + searchDirection:(EMMessageSearchDirection)aDirection + completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock; + +/*! + * 从数据库获取指定时间段内的消息,取到的消息按时间排序,为了防止占用太多内存,用户应当制定加载消息的最大数 + * + * @param aStartTimestamp 毫秒级开始时间 + * @param aEndTimestamp 结束时间 + * @param aCount 加载消息最大数 + * @param aCompletionBlock 完成的回调 + */ +- (void)loadMessagesFrom:(long long)aStartTimestamp + to:(long long)aEndTimestamp + count:(int)aCount + completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock; +``` + +### 全局消息索引 + +可以通过消息类型、关键字检索所有会话中的消息。使用 [EMClient sharedClient].chatManager 单例调用。 + +``` +/*! + * 从数据库获取指定类型的消息,取到的消息按时间排序,如果参考的时间戳为负数,则从最新消息取,如果aCount小于等于0当作1处理 + * + * @param aType 消息类型 + * @param aTimestamp 参考时间戳 + * @param aCount 获取的条数 + * @param aUsername 消息发送方,如果为空则忽略 + * @param aDirection 消息搜索方向 + * @param aCompletionBlock 完成的回调 + */ +- (void)loadMessagesWithType:(EMMessageBodyType)aType + timestamp:(long long)aTimestamp + count:(int)aCount + fromUser:(NSString*)aUsername + searchDirection:(EMMessageSearchDirection)aDirection + completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock; +// 调用: +[[EMClient sharedClient].chatManager loadMessagesWithKeyword:@"您好" timestamp:1575997248290 count:10 fromUser:nil searchDirection:EMMessageSearchDirectionUp completion:^(NSArray *aMessages, EMError *aError) { + if (!aError) { + // aMessage数组中存的是EMMessage + NSLog(@"从数据库获取指定类型的消息成功 --- %@", aMessages); + } else { + NSLog(@"从数据库获取指定类型的消息失败的原因 --- %@", aError.errorDescription); + } +}]; + +/*! + * 从数据库获取包含指定内容的消息,取到的消息按时间排序,如果参考的时间戳为负数,则从最新消息向前取,如果aCount小于等于0当作1处理 + * + * @param aKeywords 搜索关键字,如果为空则忽略 + * @param aTimestamp 参考时间戳 + * @param aCount 获取的条数 + * @param aSender 消息发送方,如果为空则忽略 + * @param aDirection 消息搜索方向 + * @param aCompletionBlock 完成的回调 + */ +- (void)loadMessagesWithKeyword:(NSString*)aKeywords + timestamp:(long long)aTimestamp + count:(int)aCount + fromUser:(NSString*)aSender + searchDirection:(EMMessageSearchDirection)aDirection + completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock; +// 调用: +[[EMClient sharedClient].chatManager loadMessagesWithType:EMMessageBodyTypeText timestamp:1575997248290 count:10 fromUser:nil searchDirection:EMMessageSearchDirectionUp completion:^(NSArray *aMessages, EMError *aError) { + if (!aError) { + // aMessage数组中存的是EMMessage + NSLog(@"从数据库获取指定内容的消息成功 --- %@", aMessages); + } else { + NSLog(@"从数据库获取指定内容的消息失败的原因 --- %@", aError.errorDescription); + } +}]; + +``` + +## 聊天 + +登录成功之后才能进行聊天操作。发消息时,单聊和群聊调用的是统一接口,区别只是要设置下 message.chatType。 + +### 发送消息 + +``` +/*! + * 发送消息 + * + * @param aMessage 消息 + * @param aProgressBlock 附件上传进度回调block + * @param aCompletionBlock 发送完成回调block + */ +- (void)sendMessage:(EMMessage *)aMessage + progress:(void (^)(int progress))aProgressBlock + completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock; + +//调用示例: +[[EMClient sharedClient].chatManager sendMessage:message progress:^(int progress) { + NSLog(@"附件上传的进度 --- %d", progress); +} completion:^(EMMessage *message, EMError *error) { + if (!error) { + NSLog(@"发送消息成功"); + } else { + NSLog(@"发送消息失败的原因 --- %@", error.errorDescription); + } +}]; +``` + +### 接收消息 + +``` +协议:EMChatManagerDelegate + +代理: +// 注册消息代理 +[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil]; + +// 移除消息代理 +[[EMClient sharedClient].chatManager removeDelegate:self]; +``` + +接收普通消息会走以下回调: + +如果集成时使用的是环信demo中的聊天页面,聊天页面内已经注册了消息代理,监听了接收普通消息的回调方法,无需额外添加。 + +如果集成时是自己写的聊天页面,需要在聊天页面内自己注册消息代理,监听接收普通消息的回调方法。 + +另外建议在自己工程的根控制器中注册消息代理,监听接收普通消息的回调方法,用于不在聊天页面时接收消息的铃声或者本地通知提示等。 + +``` +/*! + @method + @brief 接收到一条及以上非cmd消息 + */ +- (void)messagesDidReceive:(NSArray *)aMessages; +``` + +接收透传(cmd)消息会走以下回调: + +``` +/*! + @method + @brief 接收到一条及以上cmd消息 + */ +- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages; +``` + +### 解析普通消息(含自定义类型消息) + +``` +// 收到消息的回调,带有附件类型的消息可以用 SDK 提供的下载附件方法下载(后面会讲到) +- (void)messagesDidReceive:(NSArray *)aMessages { + for (EMMessage *message in aMessages) { + EMMessageBody *msgBody = message.body; + switch (msgBody.type) { + case EMMessageBodyTypeText: + { + // 收到的文字消息 + EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody; + NSString *txt = textBody.text; + NSLog(@"收到的文字是 txt -- %@",txt); + } + break; + case EMMessageBodyTypeImage: + { + // 得到一个图片消息body + EMImageMessageBody *body = ((EMImageMessageBody *)msgBody); + NSLog(@"大图remote路径 -- %@" ,body.remotePath); + NSLog(@"大图local路径 -- %@" ,body.localPath); // // 需要使用sdk提供的下载方法后才会存在 + NSLog(@"大图的secret -- %@" ,body.secretKey); + NSLog(@"大图的W -- %f ,大图的H -- %f",body.size.width,body.size.height); + NSLog(@"大图的下载状态 -- %lu",body.downloadStatus); + + + // 缩略图sdk会自动下载 + NSLog(@"小图remote路径 -- %@" ,body.thumbnailRemotePath); + NSLog(@"小图local路径 -- %@" ,body.thumbnailLocalPath); + NSLog(@"小图的secret -- %@" ,body.thumbnailSecretKey); + NSLog(@"小图的W -- %f ,大图的H -- %f",body.thumbnailSize.width,body.thumbnailSize.height); + NSLog(@"小图的下载状态 -- %lu",body.thumbnailDownloadStatus); + } + break; + case EMMessageBodyTypeLocation: + { + EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody; + NSLog(@"纬度-- %f",body.latitude); + NSLog(@"经度-- %f",body.longitude); + NSLog(@"地址-- %@",body.address); + } + break; + case EMMessageBodyTypeVoice: + { + // 音频sdk会自动下载 + EMVoiceMessageBody *body = (EMVoiceMessageBody *)msgBody; + NSLog(@"音频remote路径 -- %@" ,body.remotePath); + NSLog(@"音频local路径 -- %@" ,body.localPath); // 需要使用sdk提供的下载方法后才会存在(音频会自动调用) + NSLog(@"音频的secret -- %@" ,body.secretKey); + NSLog(@"音频文件大小 -- %lld" ,body.fileLength); + NSLog(@"音频文件的下载状态 -- %lu" ,body.downloadStatus); + NSLog(@"音频的时间长度 -- %lu" ,body.duration); + } + break; + case EMMessageBodyTypeVideo: + { + EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody; + + NSLog(@"视频remote路径 -- %@" ,body.remotePath); + NSLog(@"视频local路径 -- %@" ,body.localPath); // 需要使用sdk提供的下载方法后才会存在 + NSLog(@"视频的secret -- %@" ,body.secretKey); + NSLog(@"视频文件大小 -- %lld" ,body.fileLength); + NSLog(@"视频文件的下载状态 -- %lu" ,body.downloadStatus); + NSLog(@"视频的时间长度 -- %lu" ,body.duration); + NSLog(@"视频的W -- %f ,视频的H -- %f", body.thumbnailSize.width, body.thumbnailSize.height); + + // 缩略图sdk会自动下载 + NSLog(@"缩略图的remote路径 -- %@" ,body.thumbnailRemotePath); + NSLog(@"缩略图的local路径 -- %@" ,body.thumbnailLocalPath); + NSLog(@"缩略图的secret -- %@" ,body.thumbnailSecretKey); + NSLog(@"缩略图的下载状态 -- %lu" ,body.thumbnailDownloadStatus); + } + break; + case EMMessageBodyTypeFile: + { + EMFileMessageBody *body = (EMFileMessageBody *)msgBody; + NSLog(@"文件remote路径 -- %@" ,body.remotePath); + NSLog(@"文件local路径 -- %@" ,body.localPath); // 需要使用sdk提供的下载方法后才会存在 + NSLog(@"文件的secret -- %@" ,body.secretKey); + NSLog(@"文件文件大小 -- %lld" ,body.fileLength); + NSLog(@"文件文件的下载状态 -- %lu" ,body.downloadStatus); + } + break; + case EMMessageBodyTypeCustom: + { + // 收到的自定义类型消息 + EMCustomMessageBody *body = (EMCustomMessageBody *)msgBody; + NSLog(@"event -- %@", body.event); + NSLog(@"ext -- %@", body.ext); + } + break; + + default: + break; + } + } +} +``` + +### 解析透传消息 + +``` +- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages { + for (EMMessage *message in aCmdMessages) { + EMCmdMessageBody *body = (EMCmdMessageBody *)message.body; + NSLog(@"收到的action是 -- %@",body.action); + } +} +``` + +### 解析消息扩展属性 + +``` +- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages { + for (EMMessage *message in aCmdMessages) { + // cmd消息中的扩展属性 + NSDictionary *ext = message.ext; + NSLog(@"cmd消息中的扩展属性是 -- %@",ext) + } +} +// 收到消息回调 +- (void)messagesDidReceive:(NSArray *)aMessages { + for (EMMessage *message in aMessages) { + // 消息中的扩展属性 + NSDictionary *ext = message.ext; + NSLog(@"消息中的扩展属性是 -- %@",ext); + } +} +``` + +### 自动下载消息中的附件 + +SDK 接收到消息后,会默认下载:图片消息的缩略图,语音消息的语音,视频消息的视频第一帧。 + +**请先判断你要下载附件没有下载成功之后,在调用以下下载方法,否则SDK下载方法会再次从服务器上获取附件。** + +``` +/*! + * 下载缩略图(图片消息的缩略图或视频消息的第一帧图片),SDK会自动下载缩略图,所以除非自动下载失败,用户不需要自己下载缩略图 + * + * @param aMessage 消息 + * @param aProgressBlock 附件下载进度回调block + * @param aCompletionBlock 下载完成回调block + */ +- (void)downloadMessageThumbnail:(EMMessage *)aMessage + progress:(void (^)(int progress))aProgressBlock + completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].chatManager downloadMessageThumbnail:message progress:nil completion:^(EMMessage *message, EMError *error) { + if (!error) { + NSLog(@"下载缩略图成功"); + } else { + NSLog(@"下载缩略图失败的原因 --- %@",error.errorDescription); + } +}]; +``` + +### 下载消息中的原始附件 + +``` +/*! + * 下载消息附件(语音,视频,图片原图,文件),SDK会自动下载语音消息,所以除非自动下载语音失败,用户不需要自动下载语音附件 + * + * 异步方法 + * + * @param aMessage 消息 + * @param aProgressBlock 附件下载进度回调block + * @param aCompletionBlock 下载完成回调block + */ +[[EMClient sharedClient].chatManager downloadMessageAttachment:message progress:nil completion:^(EMMessage *message, EMError *error) { + if (!error) { + NSLog(@"下载消息附件成功"); + } else { + NSLog(@"下载消息附件失败的原因 --- %@",error.errorDescription); + } +}]; +``` + +### 发送会话已读消息 + +- 功能描述:给服务器发送一条“会话已读”消息,表示当前会话的消息已读。 +- 使用场景: + +若当前会话有未读消息,则发送会话“已读”消息给服务器,服务器回调给多设备id或者会话方。 + +- API使用示例: + +``` +if (self.conversation.unreadMessagesCount > 0) { + [[EMClient sharedClient].chatManager ackConversationRead:self.conversation.conversationId completion:nil]; + } + +``` + +### 接收会话已读回调 + +- 功能描述:表示此会话的未读消息在其他登陆的多设备上“已读“,或会话方”已读“接收的未读消息。 +- 使用场景: + +当有我方多设备或会话方“发送会话已读消息”,则会收到会话已读回调,收到会话已读回调后可重新刷新未读数,消息已读相关UI。 + +- API示例: + +``` +- (void)onConversationRead:(NSString *)from to:(NSString *)to; + +``` + +### 消息已送达回执 + +SDK提供了已送达回执,当对方收到您的消息后,您会收到以下回调。 + +``` +/*! + @method + @brief 接收到一条及以上已送达回执 + */ +- (void)messagesDidDeliver:(NSArray *)aMessages; +``` + +### 消息已读回执 + +已读回执需要开发者主动调用的。当用户读取消息后,由开发者主动调用方法。 消息已读回执功能目前仅适用于单聊(ChatType.Chat),推荐使用方案为会话已读回执(conversation ack)+单条消息已读回执(read ack)结合实现,可减少发送read ack消息量。 + + +#### 发送已读回执 + +推荐进入会话首先发送会话已读回执(conversation ack) + +``` +[[EMClient sharedClient].chatManager ackConversationRead:@"会话id" completion:nil]; +``` + +在会话页面,可以在接收到消息时,根据消息类型发送消息已读回执(read ack) + +``` +/*! + * 发送消息已读回执 + * + * 异步方法 + * + * @param aMessage 消息id + * @param aUsername 已读接收方 + * @param aCompletionBlock 完成的回调 + */ +- (void)sendMessageReadAck:(NSString *)aMessageId + toUser:(NSString *)aUsername + completion:(void (^)(EMError *aError))aCompletionBlock; + +// 调用: +// 发送已读回执。在这里写只是为了演示发送,在APP中具体在哪里发送需要开发者自己决定。 +[[EMClient sharedClient].chatManager sendMessageReadAck:@"messageId" toUser:@"username" completion:^(EMError *aError) { + if (!aError) { + NSLog(@"发送已读回执成功"); + } else { + NSLog(@"发送已读回执失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +#### 接收已读回执 + +接收会话已读回执 + +``` +/** + * \~chinese + * 收到会话已读回调 + * + * @param from CHANNEL_ACK 发送方 + * @param to CHANNEL_ACK 接收方 + * + * \~english + * received conversation read ack + * @param from the username who send channel_ack + * @param to the username who receive channel_ack + */ +- (void)onConversationRead:(NSString *)from to:(NSString *)to; +``` + +接收到会话已读回执(channel ack)回调后,SDK会将会话相关消息置为对方已读,在接收到此回调后,需进行页面刷新等操作 + +接收消息已读回执 + +``` +/*! + * 接收到一条及以上已读回执 + * + * @param aMessages 消息列表 + */ +- (void)messagesDidRead:(NSArray *)aMessages; +``` + +### 设置群消息是否需要已读回执 + +当消息为群消息时,消息发送方(目前为管理员和群主)可以设置此消息是否需要已读回执,如需要,则设置EMMessage属性isNeedGroupAck为YES,之后发送。 + +``` +@property (nonatomic) BOOL isNeedGroupAck; +``` + +### 发送群消息已读回执 + +``` +/*! + * \~chinese + * 发送群消息已读回执 + * + * 异步方法 + * + * @param aMessageId 消息id + * @param aGroupId 群id + * @param aContent 附加消息 + * @param aCompletionBlock 完成的回调 + * + * \~english + * Send read acknowledgement for message + * + * @param aMessageId Message id + * @param aGroupId group receiver + * @param aContent Content + * @param aCompletionBlock The callback of completion block + * + */ +- (void)sendGroupMessageReadAck:(NSString *)aMessageId + toGroup:(NSString *)aGroupId + content:(NSString *)aContent + completion:(void (^)(EMError *aError))aCompletionBlock; + + // 调用 + // 发送群消息已读回执。在这里写只是为了演示发送,在APP中具体在哪里发送需要开发者自己决定。 + [[EMClient sharedClient].chatManager sendGroupMessageReadAck:@"messageId" + toGroup:@"GroupId" + content:@"回执内容" + completion:^(EMError *aError) + { + if (!aError) { + NSLog(@"发送已读回执成功"); + } else { + NSLog(@"发送已读回执失败的原因 --- %@", aError.errorDescription); + } + }]; +``` + +当发送群已读回执后,消息发送方对应EMMessage的groupAckCount属性会有相应变化; + +``` +@property (nonatomic, readonly) int groupAckCount; +``` + +### 群消息已读回调 + +``` +/*! + * \~chinese + * 收到群消息已读回执 + * + * @param aMessages 已读消息列表 + * + * \~english + * Invoked when receiving read acknowledgement in message list + * + * @param aMessages Acknowledged message list + */ +- (void)groupMessageDidRead:(EMMessage *)aMessage + groupAcks:(NSArray *)aGroupAcks; +``` + +### 获取群已读详情 + +``` +/** + * \~chinese + * 从服务器获取指定群已读回执 + * + * 异步方法 + * + * @param aMessageId 要获取的消息id + * @param aGroupId 要获取回执对应的群id + * @param aGroupAckId 要回去的群回执id + * @param aPageSize 获取消息条数 + * @param aCompletionBlock 获取消息结束的callback + */ +- (void)asyncFetchGroupMessageAcksFromServer:(NSString *)aMessageId + groupId:(NSString *)aGroupId + startGroupAckId:(NSString *)aGroupAckId + pageSize:(int)aPageSize + completion:(void (^)(EMCursorResult *aResult, EMError *error, int totalCount))aCompletionBlock; +``` + +### 消息漫游 + +SDK提供了从服务器获取历史消息的接口 + +``` +/** + * 从服务器获取指定会话的历史消息 + * + * 异步方法 + * + * @param aConversationId 要获取漫游消息的Conversation id + * @param aConversationType 要获取漫游消息的Conversation type + * @param aStartMessageId 参考起始消息的ID + * @param aPageSize 获取消息条数(一次最多50条) + * @param aCompletionBlock 获取消息结束的callback + */ +- (void)asyncFetchHistoryMessagesFromServer:(NSString *)aConversationId + conversationType:(EMConversationType)aConversationType + startMessageId:(NSString *)aStartMessageId + pageSize:(int)aPageSize + complation:(void (^)(EMCursorResult *aResult, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].chatManager asyncFetchHistoryMessagesFromServer:@"6001" conversationType:EMConversationTypeChat startMessageId:messageId pageSize:10 completion:^(EMCursorResult *aResult, EMError *aError) { + if (!aError) { + NSLog(@"从服务器获取消息成功"); + } else { + NSLog(@"从服务器获取消息失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +### 消息撤回 + +``` +/*! +* 撤回消息 +* +* 异步方法 +* +* @param aMessageId 消息Id +* @param aCompletionBlock 完成的回调 +*/ +- (void)recallMessageWithMessageId:(NSString *)aMessageId + completion:(void (^)(EMError *aError))aCompletionBlock; + +// 调用示例: +[[EMClient sharedClient].chatManager recallMessageWithMessageId:messageId completion:^(EMError *aError) { + if (!aError) { + NSLog(@"撤回消息成功"); + } else { + NSLog(@"撤回消息失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +消息撤回回执 + +``` +/*! + * 收到消息撤回 + * + * @param aMessages 撤回消息列表 + */ +- (void)messagesDidRecall:(NSArray *)aMessages; +``` + + + +### 删除消息 + +SDK提供删除指定时间之前的所有本地消息的接口。调用过程如下 + +``` +/*! + * \~chinese + * 删除某个时间点之前的消息 + * + * 异步方法 + * + * @param aTimestamp 要删除时间点,单位毫秒 + * @param aCompletion 完成回调 + * + * \~english + * Delete messages which before a special timestamp + * + * + * @param aTimestamp The timestamp to delete + * @param aCompletion The callback block of completion + * + */ +- (void)deleteMessagesBefore:(NSUInteger)aTimestamp + completion:(void(^)(EMError*error))aCompletion; +``` + +调用过程如下: + +``` +// 例如删除消息msg之前的所有消息 +[[EMClient sharedClient].chatManager deleteMessagesBefore:msg.timestamp completion:nil]; +``` + diff --git a/docs/document/v1/ios/message_manage.md b/docs/document/v1/ios/message_manage.md index c613b71c2..547f568a6 100644 --- a/docs/document/v1/ios/message_manage.md +++ b/docs/document/v1/ios/message_manage.md @@ -9,8 +9,9 @@ ## 技术原理 环信即时通讯 IM iOS SDK 支持管理用户设备上存储的消息会话数据,其中包含如下主要方法: - + - `EMConversation.loadMessagesStartFromId` 从数据库中读取指定会话的消息; - `EMConversation.unreadMessagesCount` 获取指定会话的未读消息数; - `EMConversation.unreadMessagesCount` 获取所有会话的未读消息数; @@ -23,19 +24,21 @@ - `IEMChatManager.importMessages` 批量导入消息到数据库; - `EMConversation.insertMessage` 插入消息; - `IEMChatManager.updateMessage` 更新消息到本地数据库; + ## 前提条件 开始前,请确保满足以下条件: - 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 - + ### 从数据库中读取指定会话的消息 可以从数据库中读取指定会话的消息: @@ -202,7 +205,7 @@ EMConversation *conversation = [[EMClient sharedClient].chatManager getConversat } }]; ``` - + \ No newline at end of file diff --git a/docs/document/v1/ios/message_modify.md b/docs/document/v1/ios/message_modify.md index b4e2b01c1..7f40a7943 100644 --- a/docs/document/v1/ios/message_modify.md +++ b/docs/document/v1/ios/message_modify.md @@ -9,7 +9,7 @@ 若使用该功能,需将 SDK 升级至 4.1.0 或以上版本。 ::: -你可以调用 `EMChatManager::modifyMessage:body:completion:` 方法修改已经发送成功的消息。一条消息默认最多可修改 10 次,若要提升修改次数,需联系商务。 +你可以调用 `EMChatManager::modifyMessage:body:completion:` 方法修改已经发送成功的消息。一条消息默认最多可修改 10 次。 消息修改后,消息的接收方会收到 `EMChatManagerDelegate#onMessageContentChanged:operatorId:operationTime` 事件,该事件中会携带修改后的消息对象、最新一次修改消息的用户以及消息的最新修改时间。对于群聊会话,除了修改消息的用户,群组内的其他成员均会收到该事件。 diff --git a/docs/document/v1/ios/message_receipt.md b/docs/document/v1/ios/message_receipt.md index a04dea65a..aac4a1ed4 100644 --- a/docs/document/v1/ios/message_receipt.md +++ b/docs/document/v1/ios/message_receipt.md @@ -4,7 +4,7 @@ 单聊会话支持消息送达回执、会话已读回执和消息已读回执,发送方发送消息后可及时了解接收方是否及时收到并阅读了信息,也可以了解整个会话是否已读。 -群聊会话只支持消息已读回执。群主和群管理员在发送消息时,可以设置该消息是否需要已读回执。仅旗舰版及以上版本支持群消息已读回执功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +群聊会话只支持消息已读回执。群主和群管理员在发送消息时,可以设置该消息是否需要已读回执,私有部署即时通讯服务默认支持并开通该功能。 本文介绍如何使用环信即时通讯 IM Android SDK 实现单聊和群聊的消息回执功能。 @@ -40,8 +40,8 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -- 群消息已读回执功能仅在环信 IM 旗舰版及以上版本支持该功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 + ## 实现方法 @@ -189,7 +189,7 @@ EMChatManagerDelegate 对于群聊,群主和群管理员发送消息时,可以设置该消息是否需要已读回执。若需要,每个群成员在阅读消息后,SDK 均会发送已读回执,即阅读该消息的群成员数量即为已读回执的数量。 -仅旗舰版及以上版本支持群消息已读回执功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +私有部署即时通讯服务默认支持并开通群消息已读回执功能。 1. 群主或群管理员设置 `EMChatMessage` 的属性 `isNeedGroupAck` 为 `YES`。 diff --git a/docs/document/v1/ios/message_retrieve.md b/docs/document/v1/ios/message_retrieve.md index 45adf99d3..94dbaefbb 100644 --- a/docs/document/v1/ios/message_retrieve.md +++ b/docs/document/v1/ios/message_retrieve.md @@ -4,30 +4,30 @@ 环信即时通讯 IM 提供消息漫游功能,即将用户的所有会话的历史消息保存在消息服务器,用户在任何一个终端设备上都能获取到历史信息,使用户在多个设备切换使用的情况下也能保持一致的会话场景。本文介绍用户如何获取和删除服务端的会话和消息。 -:::tip -本文介绍的功能均为增值服务,需在[环信即时通讯 IM 管理后台](https://console.easemob.com/user/login)开通。 -::: + ## 技术原理 使用环信即时通讯 IM iOS SDK 可以管理服务端的会话和历史消息。 +- `asyncFetchHistoryMessagesFromServer` 获取服务器保存的指定会话中的消息; + ## 前提条件 开始前,请确保满足以下条件: - 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM API 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 - + + +### 分页获取指定会话的历史消息 + +你可以调用 `asyncFetchHistoryMessagesFromServer` 方法从服务器获取指定会话的消息(消息漫游)。你可以指定消息查询方向,即明确按时间顺序或逆序获取。为确保数据可靠,我们建议你每次最多获取 50 条消息,可多次获取。拉取后,SDK 会自动将消息更新到本地数据库。 + +```objectivec +// 异步方法 + [[EMClient sharedClient].chatManager asyncFetchHistoryMessagesFromServer:conversation.conversationId conversationType:conversation.type startMessageId:self.moreMsgId pageSize:10 completion:^(EMCursorResult *aResult, EMError *aError) { + [self.conversation loadMessagesStartFromId:self.moreMsgId count:10 searchDirection:EMMessageSearchDirectionUp completion:block]; + }]; ``` \ No newline at end of file diff --git a/docs/document/v1/ios/message_send_receive.md b/docs/document/v1/ios/message_send_receive.md index 8485f4305..8143de51d 100644 --- a/docs/document/v1/ios/message_send_receive.md +++ b/docs/document/v1/ios/message_send_receive.md @@ -9,9 +9,9 @@ - 位置消息。 - 透传消息。 - 自定义消息。 -- 合并消息。 + 针对聊天室消息并发量较大的场景,即时通讯服务提供消息分级功能。你可以通过设置消息优先级,将消息划分为高、普通和低三种级别。你可以在创建消息时,将指定消息类型,或指定成员的所有消息设置为高优先级,确保此类消息优先送达。这种方式可以确保在聊天室内消息并发量较大或消息发送频率过高的情况下,服务器首先丢弃低优先级消息,将资源留给高优先级消息,确保重要消息(如打赏、公告等)优先送达,以此提升重要消息的可靠性。请注意,该功能并不保证高优先级消息必达。在聊天室内消息并发量过大的情况下,为保证用户实时互动的流畅性,即使是高优先级消息仍然会被丢弃。 本文介绍如何使用即时通讯 IM SDK 实现发送和接收这些类型的消息。 @@ -38,7 +38,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 @@ -112,7 +112,7 @@ message.priority = EMChatRoomMessagePriorityHigh; ### 撤回消息 -发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在[环信即时通讯云控制台](https://console.easemob.com/user/login)的**功能配置** > **功能配置总览** > **基础功能** 页面设置消息撤回时长,该时长不超过 7 天。 +发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在 环信即时通讯云控制台的**服务管理** > **服务概览** 页面设置消息撤回时长,该时长不超过 7 天。 ```objectivec // 异步方法 @@ -481,6 +481,32 @@ message.chatType = EMChatTypeGroupChat; [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; ``` +### 使用消息的扩展字段 + +当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段来传递自定义的内容,从而生成自己需要的消息类型。 + +当目前消息类型不满足用户需求时,可以在扩展部分保存更多信息,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```objectivec +EMTextMessageBody *textMessageBody = [[EMTextMessageBody alloc] initWithText:content]; +// 增加自定义属性。 +NSDictionary *messageExt = @{@"attribute":@"value"}; +EMChatMessage *message = [[EMChatMessage alloc] initWithConversationID:toChatUsername from:fromChatUsername to:toChatUsername body:textMessageBody ext:messageExt]; +message.chatType = EMChatTypeChat; +// 发送消息。 +[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; + +// 接收消息的时候获取扩展属性。 +- (void)messagesDidReceive:(NSArray *)aMessages + { + // 收到消息,遍历消息列表。 + for (EMChatMessage *message in aMessages) { + // value 为消息扩展里 attribute 字段的值。 + NSString *value = [message.ext objectForKey:@"attribute"]; } + } +``` + + diff --git a/docs/document/v1/ios/multi_device.md b/docs/document/v1/ios/multi_device.md index cc1f13e5b..52fa8c9f8 100644 --- a/docs/document/v1/ios/multi_device.md +++ b/docs/document/v1/ios/multi_device.md @@ -11,7 +11,7 @@ 多端登录时,即时通讯 IM 每端默认最多支持 4 个设备同时在线。如需增加支持的设备数量,可以联系环信即时通讯 IM 的商务经理。 -你可以在环信控制台的**功能配置** > **功能配置总览**页面的**基础功能**页签下点击**多端多设备在线**操作栏中的**设置**,在弹出的对话框中设置设置各端设备的数量: +在环信控制台的**服务管理** > **服务概览**页面,点击**多端多设备在线**对应的**设置**。在弹出的对话框中点击 **新增自定义平台**,在**添加自定义平台**对话框中设置**设备平台**和**设备数量**。 ![img](@static/images/common/multidevice_device_count.png) @@ -24,7 +24,7 @@ - +
@@ -51,11 +51,13 @@ iOS SDK 初始化时会生成登录 ID 用于在多设备登录和消息推送 - 获取当前用户的其他已登录设备的登录 ID 列表; - 获取指定账号的在线登录设备列表; -- 设置登录设备的名称; -- 设置登录设备的平台; - 强制指定账号从单个设备下线; - 强制指定账号从所有设备下线; - 获取其他设备的好友或者群组操作。 + ## 前提条件 @@ -98,7 +100,7 @@ iOS SDK 初始化时会生成登录 ID 用于在多设备登录和消息推送 }]; ``` - + ### 强制指定账号从单个设备下线 你可以调用 `kickDeviceWithUsername` 方法通过传入用户 ID 和登录密码或用户 token 将指定账号从单个登录的设备踢下线。你需要首先调用 `getLoggedInDevicesFromServerWithUsername` 方法获取设备 ID。 diff --git a/docs/document/v1/ios/multidevices.md b/docs/document/v1/ios/multidevices.md new file mode 100644 index 000000000..1599ea907 --- /dev/null +++ b/docs/document/v1/ios/multidevices.md @@ -0,0 +1,138 @@ +# 多设备管理 + + +多设备主要涉及到的环信 SDK 头文件如下: + +``` +// 已登录设备的信息部分,包含设备的UUID,设备名称等 +EMDeviceConfig.h + +// 多设备方法调用部分,比如从服务器获取所有已经登录的设备信息,强制指定的设备退出等 +EMClient.h + +// 多设备的协议回调方法部分,比如监听好友多设备事件,群组多设备事件回调方法等 +EMMultiDevicesDelegate.h +``` + +## 其他端登录的设备ID + +当PC端和手机端登录同一个账号时,在手机端可以通过特定方法获取到PC端的设备ID,该设备ID相当于特殊的好友Username,可以直接使用于聊天,使用方法与好友类似。 + +#### 接口 + +``` +/*! + * 从服务器获取所有已经登录的设备信息 + * + * @param aUsername 用户名 + * @param aPassword 密码 + * @param aCompletionBlock 完成的回调 + * @result aList Information of logged in device + */ +- (void)getLoggedInDevicesFromServerWithUsername:(NSString *)aUsername + password:(NSString *)aPassword + completion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; +``` + +#### 使用示例 + +``` +[[EMClient sharedClient] getLoggedInDevicesFromServerWithUsername:@"username" password:@"password" completion:^(NSArray *aList, EMError *aError) { + if (!aError) { + // 返回的aList数组里面是 EMDeviceConfig 对象,EMDeviceConfig 是已登录设备的信息,具体请到环信SDK EMDeviceConfig.h 头文件中查看介绍 + NSLog(@"从服务器获取所有已经登录的设备信息成功 --- %@", aList); + } else { + NSLog(@"从服务器获取所有已经登录的设备信息失败的原因 --- %@", aError.errorDescription); + } +}]; +``` + +## 多设备事件回调 + +账号A同时在设备A和设备B上登录,账号A在设备A上进行一些操作,设备B上会收到这些操作对应的通知,具体说明如下: + +#### 接口 EMMultiDevicesDelegate + +``` +/*! + * 多设备事件类型 + * 用户UserA,登录2台机子DeviceA1和DeviceA2,另有一个用户UserB + */ +typedef NS_ENUM(NSInteger, EMMultiDevicesEvent) { + EMMultiDevicesEventUnknow = -1, // 默认 + EMMultiDevicesEventContactRemove = 2, // UserB和UserA是好友,UserA在DeviceA1上删除了UserB,DeviceA2会收到该回调 + EMMultiDevicesEventContactAccept = 3, // UserB向UserA发送加好友申请,UserA在DeviceA1上同意了该请求,DeviceA2会收到该回调 + EMMultiDevicesEventContactDecline = 4, // UserB向UserA发送加好友申请,UserA在DeviceA1上拒绝了该请求,DeviceA2会收到该回调 + EMMultiDevicesEventContactBan = 5, // UserA在DeviceA1上将UserB加入黑名单,DeviceA2会收到该回调 + EMMultiDevicesEventContactAllow = 6, // UserA在DeviceA1上将UserB从黑名单中移除,DeviceA2会收到该回调 + + EMMultiDevicesEventGroupCreate = 10, // UserA在DeviceA1上创建了群组Group,DeviceA2会收到该回调 + EMMultiDevicesEventGroupDestroy = 11, // UserA在DeviceA1上销毁了群组Group,DeviceA2会收到该回调 + EMMultiDevicesEventGroupJoin = 12, // UserA在DeviceA1上主动加入了群组Group,DeviceA2会收到该回调 + EMMultiDevicesEventGroupLeave = 13, // UserA在DeviceA1上退出了群组Group,DeviceA2会收到该回调 + EMMultiDevicesEventGroupApply = 14, // UserA在DeviceA1上发送了申请进入Group,DeviceA2会收到该回调 + EMMultiDevicesEventGroupApplyAccept = 15, // UserA收到UserB的入群申请,UserA在DeviceA1上同意了该申请,DeviceA2会收到该回调 + EMMultiDevicesEventGroupApplyDecline = 16, // UserA收到UserB的入群申请,UserA在DeviceA1上拒绝了该申请,DeviceA2会收到该回调 + EMMultiDevicesEventGroupInvite = 17, // UserA在DeviceA1上邀请了某些人进入GroupA,DeviceA2会收到该回调 + EMMultiDevicesEventGroupInviteAccept = 18, //e UserBUserA加入群组,UserA在DeviceA1上同意了UserB的邀请,DeviceA2会收到该回调 + EMMultiDevicesEventGroupInviteDecline = 19, // UserB邀请UserA加入群组,UserA在DeviceA1上拒绝了UserB的邀请,DeviceA2会收到该回调 + EMMultiDevicesEventGroupKick = 20, // UserA在DeviceA1上将某些成员从GroupA中踢出,DeviceA2会收到该回调 + EMMultiDevicesEventGroupBan = 21, // UserA在DeviceA1上将某些成员加入GroupA黑名单,DeviceA2会收到该回调 + EMMultiDevicesEventGroupAllow = 22, // UserA在DeviceA1上将某些成员从GroupA黑名单中移除,DeviceA2会收到该回调 + EMMultiDevicesEventGroupBlock = 23, // UserA在DeviceA1上屏蔽了GroupA的消息,DeviceA2会收到该回调 + EMMultiDevicesEventGroupUnBlock = 24, // UserA在DeviceA1上取消了屏蔽GroupA的消息,DeviceA2会收到该回调 + EMMultiDevicesEventGroupAssignOwner = 25, // UserA在DeviceA1上更新了GroupA的群主,DeviceA2会收到该回调 + EMMultiDevicesEventGroupAddAdmin = 26, // UserA在DeviceA1上添加了GroupA的管理员,DeviceA2会收到该回调 + EMMultiDevicesEventGroupRemoveAdmin = 27, // UserA在DeviceA1上移除了GroupA的管理员,DeviceA2会收到该回调 + EMMultiDevicesEventGroupAddMute = 28, // UserA在DeviceA1上禁言了GroupA的某些成员,DeviceA2会收到该回调 + EMMultiDevicesEventGroupRemoveMute = 29, // UserA在DeviceA1上移除了GroupA的某些禁言成员,DeviceA2会收到该回调 +}; + +/*! + * 好友多设备事件回调 + * + * @param aEvent 多设备事件类型 + * @param aUsername 用户名 + * @param aExt 扩展信息 + */ +- (void)multiDevicesContactEventDidReceive:(EMMultiDevicesEvent)aEvent + username:(NSString *)aUsername + ext:(NSString *)aExt; + +/*! + * 群组多设备事件回调 + * + * @param aEvent 多设备事件类型 + * @param aGroupId 群组ID + * @param aExt 扩展信息, 是被操作对象的数组(NSMutableArray) + */ +- (void)multiDevicesGroupEventDidReceive:(EMMultiDevicesEvent)aEvent + groupId:(NSString *)aGroupId + ext:(id)aExt; +``` + +#### 使用示例 + +``` +//注册监听 +[[EMClient sharedClient] addMultiDevicesDelegate:aDelegate delegateQueue:aQueue]; + +//监听回调 +- (void)multiDevicesContactEventDidReceive:(EMMultiDevicesEvent)aEvent + username:(NSString *)aTarget + ext:(NSString *)aExt +{ + NSString *message = [NSString stringWithFormat:@"%li-%@-%@", (long)aEvent, aTarget, aExt]; + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"alert.multi.contact", @"Contact Multi-devices") message:message delegate:self cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; + [alertView show]; +} + +- (void)multiDevicesGroupEventDidReceive:(EMMultiDevicesEvent)aEvent + groupId:(NSString *)aGroupId + ext:(id)aExt +{ + NSString *message = [NSString stringWithFormat:@"%li-%@-%@", (long)aEvent, aGroupId, aExt]; + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"alert.multi.group", @"Group Multi-devices") message:message delegate:self cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; + [alertView show]; +} +``` \ No newline at end of file diff --git a/docs/document/v1/ios/offline.md b/docs/document/v1/ios/offline.md new file mode 100644 index 000000000..cfc5655f5 --- /dev/null +++ b/docs/document/v1/ios/offline.md @@ -0,0 +1,309 @@ +# APNs 离线推送 + +## 必备条件 + +1. 后台上传了推送证书,具体步骤见[集成 iOS SDK 前的准备工作-制作并上传推送证书](deploy.html#配置推送)。 +2. 代码配置 APNs 使用的推送证书。 + +``` +EMOptions *options = [EMOptions optionsWithAppkey:@"appkey"]; +options.apnsCertName = @"apnsCertName"; +[[EMClient sharedClient] initializeSDKWithOptions:options]; +``` + +3. 代码注册离线推送。 + +``` +UIApplication *application = [UIApplication sharedApplication]; + +//iOS10 注册APNs +if (NSClassFromString(@"UNUserNotificationCenter")) { + [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError *error) { + if (granted) { +#if !TARGET_IPHONE_SIMULATOR + [application registerForRemoteNotifications]; +#endif + } + }]; + return; +} + +if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) +{ + UIUserNotificationType notificationTypes = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert; + UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil]; + [application registerUserNotificationSettings:settings]; +} + +#if !TARGET_IPHONE_SIMULATOR +if ([application respondsToSelector:@selector(registerForRemoteNotifications)]) { + [application registerForRemoteNotifications]; +}else{ + UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeBadge | + UIRemoteNotificationTypeSound | + UIRemoteNotificationTypeAlert; + [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes]; +} +#endif +``` + +您注册了推送功能,iOS 会自动回调以下方法,得到 deviceToken,您需要将 deviceToken 传给 SDK。 + +``` +如果是iOS13及以上的系统,请将SDK更新到v3.6.4及以上版本 +// 将得到的deviceToken传给SDK +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[EMClient sharedClient] bindDeviceToken:deviceToken]; + }); +} + +// 注册deviceToken失败 +- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{ + NSLog(@"error -- %@",error); +} +``` + +**注:必须是真机,模拟器不支持APNs。APNs 注册失败,一般是由于使用了通用证书或者是模拟器调试导致,请检查证书并用真机调试。此处是 iOS 系统报的错,如仍不能确定,请从网上查找相关资料。** + +## 获取 APNs 配置 + +APNs 属性需要从服务器获取端获取。 + +登录成功后调用。 + +``` +/*! + * \~chinese + * 从服务器获取推送属性 + * + * 同步方法,会阻塞当前线程 + * + * @param pError 错误信息 + * + * @result 推送属性 + */ +- (EMPushOptions *)getPushOptionsFromServerWithError:(EMError **)pError; + +/*! + * \~chinese + * 从服务器获取推送属性 + * + * @param aCompletionBlock 完成的回调 + */ +- (void)getPushNotificationOptionsFromServerWithCompletion:(void (^)(EMPushOptions *aOptions, EMError *aError))aCompletionBlock; +``` + +示例代码: + +``` +EMError *err; +EMPushOptions *options = [EMClient.sharedClient.pushManager getPushOptionsFromServerWithError:&err]; +if (err) { + // 获取失败 +}else { + // 获取成功 +} +``` + +## 设置APNs显示名称 + +当您给对方发消息,对方不在线时,推送中显示的发送方将为您设置的昵称; + +登录成功后调用。 + +``` +/*! + * \~chinese + * 设置推送消息显示的昵称 + * + * 同步方法,会阻塞当前线程 + * + * @param aNickname 要设置的昵称 + * + * @result 错误信息 + */ +- (EMError *)updatePushDisplayName:(NSString *)aDisplayName; + +/*! + * \~chinese + * 设置推送的显示名 + * + * @param aDisplayName 推送显示名 + * @param aCompletionBlock 完成的回调 + */ +- (void)updatePushDisplayName:(NSString *)aDisplayName + completion:(void (^)(NSString *aDisplayName, EMError *aError))aCompletionBlock; +``` + +示例代码 + +``` +EMError *err = [EMClient.sharedClient.pushManager updatePushDisplayName:@"推送昵称"]; +if (err) { + // 设置失败 +}else { + // 设置成功 +} +``` + +## 设置 APNs 显示风格 + +当您不在线时,如果有人给您发消息会收到推送,您可以设置显示详情(xxx: 消息内容),或者只显示有新消息(您有一条新消息); + +``` +/*! + * \~chinese + * 推送消息的显示风格 + */ +typedef enum { + EMPushDisplayStyleSimpleBanner = 0, /*! + * 简单显示"您有一条新消息" + */ + + EMPushDisplayStyleMessageSummary, /*! + * 显示消息内容 + */ +} EMPushDisplayStyle; +/*! + * \~chinese + * 设置推送消息显示的样式 + * + * 同步方法,会阻塞当前线程 + * + * @param pushDisplayStyle 要设置的推送样式 + * + * @result 错误信息 + */ +- (EMError *)updatePushDisplayStyle:(EMPushDisplayStyle)pushDisplayStyle; + + +/*! + * \~chinese + * 设置推送的显示名 + * + * @param pushDisplayStyle 推送显示样式 + * @param aCompletionBlock 完成的回调 + */ +- (void)updatePushDisplayStyle:(EMPushDisplayStyle)pushDisplayStyle + completion:(void (^)(EMError *))aCompletionBlock; +``` + +示例代码 + +``` +// 设置为“您有一条新消息” +EMError *err = [EMClient.sharedClient.pushManager updatePushDisplayStyle:EMPushDisplayStyleSimpleBanner]; +if (err) { + // 设置失败 +}else { + // 设置成功 +} +``` + +## 设置免打扰时段 + +当您不想,或者某些时间段不想接收离线推送的时候,您可以设置免打扰时间段,设置后,在您指定的时间段内,环信不会给您发离线推送。 该设置优先级最高,当设置后,群组,单聊的推送在指定时间段内都无法收到。 + +开启离线推送 + +``` +/*! + * \~chinese + * 开启离线推送 + * + * 同步方法,会阻塞当前线程 + * + * @result 错误信息 + * + */ +- (EMError *)enableOfflinePush; +``` + +示例代码 + +``` +EMError *err = [EMClient.sharedClient.pushManager enableOfflinePush]; +if (err) { + // 设置失败 +}else { + // 设置成功 +} +``` + +指定时间不接收离线推送 + +``` +/*! + * \~chinese + * 关闭离线推送 + * + * 同步方法,会阻塞当前线程 + * + * @param aStartHour 开始时间 + * @param aEndHour 结束时间 + * + * @result 错误信息 + */ +- (EMError *)disableOfflinePushStart:(int)aStartHour end:(int)aEndHour; +``` + +示例代码 + +``` +// 如果您想全天不接收推送,start:0, end:24; +// 如果您想早7点到下午5天不接收推送,start:7, end:17; +// 如果您想晚10点到早晨8点不接收推送,start:22, end:8; +EMError *err = [EMClient.sharedClient.pushManager disableOfflinePushStart:0 end:24]; +if (err) { + // 设置失败 +}else { + // 设置成功 +} +``` + +## 设置群组免打扰 + +当您不想收到某个群的离线推送时,您可以设置群组免打扰 + +``` +/*! + * \~chinese + * 设置群组是否接收推送 + * + * 同步方法,会阻塞当前线程 + * + * @param aGroupIds 群组id + * @param disable 是否接收推送 + * + * @result 错误信息 + */ +- (EMError *)updatePushServiceForGroups:(NSArray *)aGroupIds + disablePush:(BOOL)disable; + + +/*! + * \~chinese + * 设置群组是否接收推送 + * + * @param aGroupIds 群组id + * @param disable 是否接收推送 + * @param aCompletionBlock 完成的回调 + */ +- (void)updatePushServiceForGroups:(NSArray *)aGroupIds + disablePush:(BOOL)disable + completion:(void (^)(EMError *))aCompletionBlock; +``` + +示例代码 + +``` +// 不接受群id是82000139的群组推送。 +EMError *err = [EMClient.sharedClient.pushManager updatePushServiceForGroups:@[@"82000139"] disablePush:YES]; +if (err) { + // 设置失败 +}else { + // 设置成功 +} +``` \ No newline at end of file diff --git a/docs/document/v1/ios/overview.md b/docs/document/v1/ios/overview.md index b2e072a95..462fdf711 100644 --- a/docs/document/v1/ios/overview.md +++ b/docs/document/v1/ios/overview.md @@ -1,202 +1,231 @@ -# SDK 集成概述 +# SDK集成概述 - -介绍 iOS 集成相关内容。 +在您阅读此文档时,我们假定您已经具备了基础的 iOS 应用开发经验,并能够理解相关基础概念。 -## 前提条件 +## SDK 同步/异步方法区分 -开始前,请注册有效的环信即时通讯 IM 开发者账号并获得 App key,详见 [环信即时通讯云管理后台](https://console.easemob.com/user/login)。 +SDK 中,大部分接口都提供了同步和异步方法(注:同步方法会阻塞主线程,需要用户自己创建异步线程执行;带有 block 的方法为异步方法。) -## 集成环境 +## 初始化 SDK -详见 [开发环境要求](quickstart.html#前提条件)。 +第 1 步:引入相关头文件 #import 。 -## SDK 初始化 +第 2 步:在工程的 AppDelegate 中的以下方法中,调用 SDK 对应方法。 -初始化是使用 SDK 的必要步骤,需在所有接口方法调用前完成。 - -如果进行多次初始化操作,只有第一次初始化以及相关的参数生效。 - -初始化示例代码: - -```objectivec -// appkey 替换成你在环信即时通讯 IM 管理后台注册应用中的 App Key -EMOptions *options = [EMOptions optionsWithAppkey:@"<#appkey#>"]; -[[EMClient sharedClient] initializeSDKWithOptions:options]; ``` +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + //AppKey:注册的AppKey,详细见下面注释。 + //apnsCertName:推送证书名(不需要加后缀),详细见下面注释。 + EMOptions *options = [EMOptions optionsWithAppkey:@"douser#istore"]; + options.apnsCertName = @"istore_dev"; + [[EMClient sharedClient] initializeSDKWithOptions:options]; -## 注册用户 + return YES; +} -可以使用如下代码创建账号: +// APP进入后台 +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + [[EMClient sharedClient] applicationDidEnterBackground:application]; +} -```objectivec -// 异步方法 -[[EMClient sharedClient] registerWithUsername:@"username" - password:@"your password" - completion:^(NSString *aUsername, EMError *aError) { - }]; +// APP将要从后台返回 +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + [[EMClient sharedClient] applicationWillEnterForeground:application]; +} ``` -:::notice - -- 以上注册模式为在客户端注册,旨在方便测试,并不推荐在正式环境中使用; -- 正式环境应使用服务器端调用 REST API 接口 [注册用户](/document/server-side/account_system.html#注册用户)。 - ::: +调用的 SDK 接口参数解释如下: -## 用户登录 +- AppKey: 区别 APP 的标识,参考[开发者注册及管理后台](/document/v1/privatization/uc_configure.html#创建应用)。 +- apnsCertName: iOS 中推送证书名称,参考[制作与上传推送证书](quickstart)。 -目前登录服务器支持手动和自动登录。手动登录有两种方式: +环信为 IM 部分提供了 APNS 推送功能,如果您要使用,请跳转到[APNS离线推送](offline)。 -- 用户 ID + 密码 -- 用户 ID + token +## 注册 -### 手动登录 +注册模式分两种,开放注册和授权注册。 -登录时传入的用户 ID 必须为 String 类型,支持的字符集详见[用户注册的 RESTful 接口](/document/server-side/account_system.html#注册用户)。 +建议使用异步注册方法,防止网络不好的情况下,出现卡UI主线程的情况出现。 -手动登录后,收到 `connectionStateDidChange` 回调表明 SDK 与环信服务器连接成功。 +- 只有开放注册时,才可以客户端注册。开放注册是为了测试使用,正式环境中不推荐使用该方式注册环信账号。 +- 授权注册的流程应该是您服务器通过环信提供的 REST API 注册,之后保存到您的服务器或返回给客户端。 -**用户 ID + 密码** 是传统的登录方式。用户名和密码均由你的终端用户自行决定,密码需要符合密码规则要求。 +``` +[[EMClient sharedClient] registerWithUsername:@"8001" password:@"111111" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"注册成功"); + } else { + NSLog(@"注册失败的原因---%@", aError.errorDescription); + } +}]; +``` -```objectivec -// 异步方法 -[[EMClient sharedClient] loginWithUsername:@"username" - password:@"your password" - completion:^(NSString *aUsername, EMError *aError) { +## 登录 -}]; +登录:调用 SDK 的登录接口进行的操作。 +建议使用异步登录方法,防止网络不好的情况下,出现卡UI主线程的情况出现。 +``` +[[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"登录成功"); + } else { + NSLog(@"登录失败的原因---%@", aError.errorDescription); + } +}]; ``` -**用户 ID + token** 是更加安全的登录方式。token 可以通过调用 REST API 获取,详见 [环信用户 token 的获取](/document/server-side/easemob_user_token.html)。 +## 使用token登录 -:::notice -使用 token 登录时需要处理 token 过期的问题,比如每次登录时更新 token 等机制。 -::: +SDK也支持使用token登录,比如在app的服务器获取token,然后交给应用使用token登录。 -```objectivec -// 异步方法 -[EMClient.sharedClient loginWithUsername:@"username" token:@"token" completion:^(NSString * _Nonnull aUsername, EMError * _Nullable aError) { +**`请注意: 使用token 登录时需要处理token过期的问题,比如在每次登录时更新token 等机制。`** +``` +[[EMClient sharedClient] loginWithUsername:@"8001" token:@"111111" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"登录成功"); + } else { + NSLog(@"登录失败的原因---%@", aError.errorDescription); + } }]; ``` -登录重试机制如下: +## 自动登录 -- 登录时,若服务器返回明确的失败原因,例如,token 不正确,SDK 不会重试登录。 -- 若登录因超时失败,SDK 会重试登录。 +自动登录:sdk在初始化的时候会根据options中的isAutoLogin来决定是否执行自动登录,如果为YES,则sdk会直接登录上次登录且未做退出操作的账号,如果值为NO,则为未登录任何账号的状态。 -### 自动登录 +``` +注意:3.6.5版本之后,isAutoLogin默认为YES,SDK会自动登录 +3.6.5之前的版本,isAutoLogin默认为NO,SDK是不会自动登录的,如果要使用自动登录需要按照下面的方式主动设置。 +[[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + // 设置自动登录 + [[EMClient sharedClient].options setIsAutoLogin:YES]; + NSLog(@"登录成功-----"); + } else { + NSLog(@"登录失败----%@", aError.errorDescription); + } +}]; +``` -在初始化的时候,可以设置是否自动登录。如果设置为自动登录,则登录成功之后,后续启动初始化的时候会自动登录。 +当出现以下几种情况时,建议调用 SDK 的登出操作。 -自动登录完成后,触发 `EMClientDelegate` 中的以下回调: +- 用户的账号从服务器端删除 -```objectivec -- (void)autoLoginDidCompleteWithError:(EMError * _Nullable)aError -{ -} +``` +/*! + * 当前登录账号已经被从服务器端删除时会收到该回调 + */ +- (void)userAccountDidRemoveFromServer; ``` -自动登录时,SDK 尝试连接服务器失败后,延时随机一段时间后自动重连。 +- 用户的账号被禁用(被封禁用户自动登录的时候触发) -## 退出登录 +``` +/*! + * 服务被禁用 + */ +- (void)userDidForbidByServer; +``` -```objectivec -// 异步方法 -[EMClient.sharedClient logout:YES completion:^(EMError * _Nullable aError) { +- 用户的账号从服务器端被强制下线 +- 用户在别的设备上登录,把当前设备上登录的用户踢出 +- 用户在别的设备上更改了密码 -}]; +``` +/*! + * 当前登录账号被强制退出时会收到该回调,有以下原因: + * 1.密码被修改; + * 2.登录设备数过多; + * 3.服务被封禁; + * 4.被强制下线; + */ +- (void)userAccountDidForcedToLogout:(EMError *)aError; ``` -## 连接状态相关 - -你可以通过注册连接监听 `EMClientDelegate` 确认连接状态。 +SDK 中,如果发生自动登录,会有以下回调: -```objectivec -- viewDidLoad -{ - ... - // 注册连接状态监听,在 SDK 初始化之后调用。 - [EMClient.sharedClient addDelegate:self delegateQueue:nil]; - ... -} +``` +/*! + * 自动登录返回结果 + * + * @param error 错误信息 + */ +- (void)autoLoginDidCompleteWithError:(EMError *)error + +//添加回调监听代理: [[EMClient sharedClient] addDelegate:self delegateQueue:nil]; +``` -// 连接状态变更时触发该回调 -- (void)connectionStateDidChange:(EMConnectionState)aConnectionState -{ - if(aConnectionState == EMConnectionConnected) { - // 连接成功 - }else { - // 断开连接 - } -} +## 重连 -// token 已过期,使用 agoraToken 登录可能触发 -- (void)tokenDidExpire:(EMErrorCode)aErrorCode -{ -} +当掉线时,iOS SDK 会自动重连,只需要监听重连相关的回调,无需进行任何操作。 -// token 已过期,使用 agoraToken 登录可能触发 -- (void)tokenWillExpire:(EMErrorCode)aErrorCode -{ -} +``` +/*! + * SDK连接服务器的状态变化时会接收到该回调 + * + * 有以下几种情况,会引起该方法的调用: + * 1. 登录成功后,手机无法上网时,会调用该回调 + * 2. 登录成功后,网络状态变化时,会调用该回调 + * + * @param aConnectionState 当前状态 + */ +- (void)connectionStateDidChange:(EMConnectionState)aConnectionState; ``` -### 断网自动重连 - -如果由于网络信号弱、切换网络等原因引起的连接中断,SDK 会自动尝试重连。重连成功或者失败会触发回调 `- (void)connectionStateDidChange:(EMConnectionState)aConnectionState`。 - -### 被动退出登录 +## 退出登录 -你可以通过监听 `EMClientDelegate` 中的以下回调,调用 `EMClient#logout:completion:` 退出登录并返回登录界面。 +退出登录分两种类型:主动退出登录和被动退出登录。 -```objectivec -// 当前登录账号在其它设备登录时会触发回调 -- (void)userAccountDidLoginFromOtherDevice -{ -} +建议使用异步退出登录方法,防止网络不好的情况下,出现卡UI主线程的情况出现。 -// 当前登录账号被强制退出时会收到该回调,如密码被修改、登录设备过多、服务被封禁、被强制下线等原因 -- (void)userAccountDidForcedToLogout:(EMError *_Nullable)aError -{ -} +- 主动退出登录:调用 SDK 的退出接口; +- 被动退出登录:1. 正在登录的账号在另一台设备上登录;2. 正在登录的账号被从服务器端删除。 -// 当前登录账号已被从服务器端删除时会收到该回调 -- (void)userAccountDidRemoveFromServer -{ -} +logout:YES:是否解除 device token 的绑定,在被动退出时 SDK 内部处理,需要调用退出方法。 -// 当前用户账号被禁用时会收到该回调 -- (void)userDidForbidByServer -{ -} +``` +[[EMClient sharedClient] logout:YES completion:^(EMError *aError) { + if (!aError) { + NSLog(@"退出登录成功"); + } else { + NSLog(@"退出登录失败的原因---%@", aError.errorDescription); + } +}]; ``` -## 输出信息到日志文件 +## 被动退出登录 -SDK 默认的日志输出级别为 `DEBUG`,开发阶段如果希望在环信即时通讯云管理后台上输出 SDK 日志,可在 SDK 初始化时开启以下开关: +使用回调方法监听被动退出登录。 -```objectivec -EMOptions* option = [EMOptions optionsWithAppkey:@"<#appkey#>"]; -// 日志输出到环信即时通讯管理后台 -option.enableConsoleLog = YES; -// 调整日志输出级别,默认为 `Debug` -option.logLevel = EMLogLevelDebug; -[EMClient.sharedClient initializeSDKWithOptions:option]; +``` +/*! + * 当前登录账号在其它设备登录时会接收到该回调 + */ +- (void)userAccountDidLoginFromOtherDevice; + +/*! + * 当前登录账号已经被从服务器端删除时会收到该回调 + */ +- (void)userAccountDidRemoveFromServer; ``` -### 获取本地日志 +## 输出信息到日志文件 -SDK 会写入日志文件到本地。日志文件路径如下:沙箱 Library/Application Support/HyphenateSDK/easemobLog/easemob.log。 +用户可以在App中将需要的信息输出到SDK日志文件中,该接口从SDK 3.8.1开始支持,需要在完成SDK初始化之后调用。调用方法如下 -以真机为例,获取本地日志过程如下: +``` +[[EMClient sharedClient] log:@"这里完成初始化"]; +``` -- 打开 Xcode,连接设备,选择 **Xcode** > **Window** > **Devices and Simulators**。 -- 进入 **Devices** 选项卡,在左侧选择目标设备,例如 Easemob IM,点击设置图标,然后选择 **Download Container**。 +## 用户被封禁后的提示 -![img](@static/images/ios/overview_fetchlogfile.png) +在[IM管理后台](/document/v1/privatization/uc_configure.html#用户管理)可以对用户进行管理,例如可以在后台封禁用户。 用户被封禁后会提示SDK登录会返回 SERVER_SERVING_DISABLED(305), 可以根据用户这个返回值来进行相应的提示或者处理。 -日志文件 `easemob.log` 文件在下载包的 AppData/Library/Application Support/HyphenateSDK/easemobLog 目录下。 +需要注意的是app整个被禁用时也会返回上述错误码,由于app一般不会被禁用,所以可以用来提示用户被封禁。 \ No newline at end of file diff --git a/docs/document/v1/ios/overview_v.md b/docs/document/v1/ios/overview_v.md new file mode 100644 index 000000000..7c120acf3 --- /dev/null +++ b/docs/document/v1/ios/overview_v.md @@ -0,0 +1,202 @@ +# SDK 集成概述 + + + +介绍 iOS 集成相关内容。 + +## 前提条件 + +开始前,请注册有效的环信即时通讯 IM 开发者账号并获得 App key,详见 [环信即时通讯云管理后台](/document/v1/privatization/uc_configure.html)。 + +## 集成环境 + +详见 [开发环境要求](quickstart.html#前提条件)。 + +## SDK 初始化 + +初始化是使用 SDK 的必要步骤,需在所有接口方法调用前完成。 + +如果进行多次初始化操作,只有第一次初始化以及相关的参数生效。 + +初始化示例代码: + +```objectivec +// appkey 替换成你在环信即时通讯 IM 管理后台注册应用中的 App Key +EMOptions *options = [EMOptions optionsWithAppkey:@"<#appkey#>"]; +[[EMClient sharedClient] initializeSDKWithOptions:options]; +``` + +## 注册用户 + +可以使用如下代码创建账号: + +```objectivec +// 异步方法 +[[EMClient sharedClient] registerWithUsername:@"username" + password:@"your password" + completion:^(NSString *aUsername, EMError *aError) { + }]; +``` + +:::notice + +- 以上注册模式为在客户端注册,旨在方便测试,并不推荐在正式环境中使用; +- 正式环境应使用服务器端调用 REST API 接口 [注册用户](/document/v1/server-side/account_system.html#注册用户)。 + ::: + +## 用户登录 + +目前登录服务器支持手动和自动登录。手动登录有两种方式: + +- 用户 ID + 密码 +- 用户 ID + token + +### 手动登录 + +登录时传入的用户 ID 必须为 String 类型,支持的字符集详见[用户注册的 RESTful 接口](/document/v1/server-side/account_system.html#注册用户)。 + +手动登录后,收到 `connectionStateDidChange` 回调表明 SDK 与环信服务器连接成功。 + +**用户 ID + 密码** 是传统的登录方式。用户名和密码均由你的终端用户自行决定,密码需要符合密码规则要求。 + +```objectivec +// 异步方法 +[[EMClient sharedClient] loginWithUsername:@"username" + password:@"your password" + completion:^(NSString *aUsername, EMError *aError) { + +}]; + + +``` + +**用户 ID + token** 是更加安全的登录方式。token 可以通过调用 REST API 获取,详见 [环信用户 token 的获取](/document/v1/server-side/easemob_user_token.html)。 + +:::notice +使用 token 登录时需要处理 token 过期的问题,比如每次登录时更新 token 等机制。 +::: + +```objectivec +// 异步方法 +[EMClient.sharedClient loginWithUsername:@"username" token:@"token" completion:^(NSString * _Nonnull aUsername, EMError * _Nullable aError) { + +}]; +``` + +登录重试机制如下: + +- 登录时,若服务器返回明确的失败原因,例如,token 不正确,SDK 不会重试登录。 +- 若登录因超时失败,SDK 会重试登录。 + +### 自动登录 + +在初始化的时候,可以设置是否自动登录。如果设置为自动登录,则登录成功之后,后续启动初始化的时候会自动登录。 + +自动登录完成后,触发 `EMClientDelegate` 中的以下回调: + +```objectivec +- (void)autoLoginDidCompleteWithError:(EMError * _Nullable)aError +{ +} +``` + +自动登录时,SDK 尝试连接服务器失败后,延时随机一段时间后自动重连。 + +## 退出登录 + +```objectivec +// 异步方法 +[EMClient.sharedClient logout:YES completion:^(EMError * _Nullable aError) { + +}]; +``` + +## 连接状态相关 + +你可以通过注册连接监听 `EMClientDelegate` 确认连接状态。 + +```objectivec +- viewDidLoad +{ + ... + // 注册连接状态监听,在 SDK 初始化之后调用。 + [EMClient.sharedClient addDelegate:self delegateQueue:nil]; + ... +} + +// 连接状态变更时触发该回调 +- (void)connectionStateDidChange:(EMConnectionState)aConnectionState +{ + if(aConnectionState == EMConnectionConnected) { + // 连接成功 + }else { + // 断开连接 + } +} + +// token 已过期,使用 agoraToken 登录可能触发 +- (void)tokenDidExpire:(EMErrorCode)aErrorCode +{ +} + +// token 已过期,使用 agoraToken 登录可能触发 +- (void)tokenWillExpire:(EMErrorCode)aErrorCode +{ +} +``` + +### 断网自动重连 + +如果由于网络信号弱、切换网络等原因引起的连接中断,SDK 会自动尝试重连。重连成功或者失败会触发回调 `- (void)connectionStateDidChange:(EMConnectionState)aConnectionState`。 + +### 被动退出登录 + +你可以通过监听 `EMClientDelegate` 中的以下回调,调用 `EMClient#logout:completion:` 退出登录并返回登录界面。 + +```objectivec +// 当前登录账号在其它设备登录时会触发回调 +- (void)userAccountDidLoginFromOtherDevice +{ +} + +// 当前登录账号被强制退出时会收到该回调,如密码被修改、登录设备过多、服务被封禁、被强制下线等原因 +- (void)userAccountDidForcedToLogout:(EMError *_Nullable)aError +{ +} + +// 当前登录账号已被从服务器端删除时会收到该回调 +- (void)userAccountDidRemoveFromServer +{ +} + +// 当前用户账号被禁用时会收到该回调 +- (void)userDidForbidByServer +{ +} +``` + +## 输出信息到日志文件 + +SDK 默认的日志输出级别为 `DEBUG`,开发阶段如果希望在环信即时通讯云管理后台上输出 SDK 日志,可在 SDK 初始化时开启以下开关: + +```objectivec +EMOptions* option = [EMOptions optionsWithAppkey:@"<#appkey#>"]; +// 日志输出到环信即时通讯管理后台 +option.enableConsoleLog = YES; +// 调整日志输出级别,默认为 `Debug` +option.logLevel = EMLogLevelDebug; +[EMClient.sharedClient initializeSDKWithOptions:option]; +``` + +### 获取本地日志 + +SDK 会写入日志文件到本地。日志文件路径如下:
沙箱 Library/Application Support/HyphenateSDK/easemobLog/easemob.log。 + +以真机为例,获取本地日志过程如下: + +- 打开 Xcode,连接设备,选择 **Xcode** > **Window** > **Devices and Simulators**。 +- 进入 **Devices** 选项卡,在左侧选择目标设备,例如 Easemob IM,点击设置图标,然后选择 **Download Container**。 + +![img](@static/images/ios/overview_fetchlogfile.png) + +日志文件 `easemob.log` 文件在下载包的 AppData/Library/Application Support/HyphenateSDK/easemobLog 目录下。 diff --git a/docs/document/v1/ios/presence.md b/docs/document/v1/ios/presence.md index d552061ae..d351a6618 100644 --- a/docs/document/v1/ios/presence.md +++ b/docs/document/v1/ios/presence.md @@ -35,8 +35,8 @@ 使用在线状态功能前,请确保满足以下条件: 1. 完成 `3.9.1 或以上版本` SDK 初始化,详见 [快速开始](quickstart.html)。 -2. 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -3. 已联系商务开通在线状态订阅功能。 +2. 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +3. 私有部署已开通在线状态订阅功能。 ## 实现方法 diff --git a/docs/document/v1/ios/push.md b/docs/document/v1/ios/push.md index 06d09e556..8bfacdd52 100644 --- a/docs/document/v1/ios/push.md +++ b/docs/document/v1/ios/push.md @@ -184,7 +184,7 @@ DeviceToken 注册后,iOS 系统会通过以下方式将 DeviceToken 回调给 - 设置推送通知,包含设置推送通知方式和免打扰模式。 - 配置推送翻译和推送模板。 -其中,设置推送通知方式、免打扰模式和推送模板为推送的高级功能,使用前需要在[环信即时通讯云控制后台](https://console.easemob.com/user/login)上开通。 +其中,设置推送通知方式、免打扰模式和推送模板为推送的高级功能,使用前需要在环信即时通讯云控制后台上开通。 ![image](@static/images/ios/push/push_ios_27_enable_push.png) @@ -449,7 +449,7 @@ NSArray *conversations = @[conversation1,conversation2]; #### 4.3 设置推送翻译 -如果用户启用 [自动翻译](message_translation.html) 功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 +如果用户启用 自动翻译 功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 推送通知与翻译功能协同工作。作为接收方,你可以设置你在离线时希望接收的推送通知的首选语言。如果翻译消息的语言符合你的设置,则翻译消息显示在推送通知中;否则,将显示原始消息。 diff --git a/docs/document/v1/ios/quickstart.md b/docs/document/v1/ios/quickstart.md index 0964ab6e9..0e2fdf749 100644 --- a/docs/document/v1/ios/quickstart.md +++ b/docs/document/v1/ios/quickstart.md @@ -1,131 +1,408 @@ -# 环信即时通讯 IM iOS 快速开始 +# iOS SDK 快速集成 - +在您阅读此文档时,我们假定您已经具备了基础的 iOS 应用开发经验,并能够理解相关基础概念,最新版本的 SDK 只支持 **iOS 10** 及以上 iOS 系统版本。 -本文介绍如何快速集成环信即时通讯 IM iOS SDK 实现单聊。 -## 实现原理 +`特殊提示:如果使用的是 xcode11 打包,那么需要先将环信 SDK 内的模拟器框架去掉,否则会报 “IPA processing failed” 的错误。` (如何剔除 SDK 内的模拟器框架,见 iOS SDK 快速集成中的'集成动态库上传 AppStore') -下图展示在客户端发送和接收一对一文本消息的工作流程。 -![img](@static/images/android/sendandreceivemsg.png) +## DEMO 体验 -## 前提条件 +[EaseIM 源码地址](https://download-sdk.oss-cn-beijing.aliyuncs.com/downloads/iOS_IM_SDK_V3.7.4.7.zip) -- Xcode (推荐最新版本)。 -- 安装 iOS 10.0 或更高版本的 iOS 模拟器或 Apple 设备。 -- CocoaPods [1.10.1 或更高版本](https://cocoapods.org/)。 -- 有效的环信即时通讯 IM 开发者账号和 App Key,见 [环信即时通讯云管理后台](https://console.easemob.com/user/login)。 -- 如果你的网络环境部署了防火墙,请联系环信技术支持设置白名单。 -## 1. 准备开发环境 -### 创建 Xcode 项目 +## 注册并创建应用 -参考以下步骤在 Xcode 中创建一个 iOS 平台下的 Single View App,项目设置如下: +注册环信开发者账号并创建后台应用 -- **Product Name** 设为 `HyphenateChatQuickstart`。 -- **Organization Identifier** 设为 `hyphenatechat`。 -- **User Interface** 选择 **Storyboard**。 -- **Language** 选择 **Objective-C**。 +详细操作步骤见[开发者注册及管理后台](/document/v1/privatization/uc_configure.html#创建应用)。 -## 2. 集成 SDK +Appkey:一个 APP 的唯一标识 -SDK 支持 **CocoaPods 导入**和**手动导入**两种方式。 +IM 用户:一个 Appkey 下的唯一标识用户,用来登录环信服务器进行收发消息的用户。 可以在创建好的应用内注册两个 IM 用户(也可以称为环信 ID),例如: 账号:user1,密码:123 ; 账号:user2,密码:123,用来通过 SDK 登录环信服务器,收发消息测试。 -### 方法一:使用 CocoaPods 集成 SDK。 +在环信 Console 后台,点击创建好的应用 → IM 用户 → [创建 IM 用户](/document/v1/privatization/uc_configure.html#用户管理),建议创建两个 IM 用户,用于后面集成 SDK 之后聊天使用。例如登录 user1 ,在初始化聊天页面时传入 user2 ,user1 给 user2 发消息测试。 -1. 在 **Terminal** 里进入项目根目录,并运行 `pod init` 命令。项目文件夹下会生成一个 **Podfile** 文本文件。 -2. 打开 **Podfile** 文件,修改文件为如下内容: -```pod -# platform :ios, '10.0' +![img](@static/images/privitization/deploy_user_manage.png) - target 'EMChatQuickstart' do - pod 'HyphenateChat' - end + + + +## iOS SDK 介绍 + +环信 SDK 为用户开发 IM 相关的应用提供的一套完善的开发框架。包括以下几个部分: + +![img](@static/images/privitization/image006.png) + +- SDK_Core: 为核心的消息同步协议实现,完成与服务器之间的信息交换。 + +- SDK: 是基于核心协议实现的完整的 IM 功能,实现了不同类型消息的收发、会话管理、群组、好友、聊天室等功能。 + +- UI:[见集成 UI](#集成-ui) + +用户可以基于我们提供的 Demo 实现自己的应用,也可以基于 SDK 开发自己应用。 + +SDK 采用模块化设计,每一模块的功能相对独立和完善,用户可以根据自己的需求选择使用下面的模块: + +![img](@static/images/privitization/image005.png) + +- EMClient: 是 SDK 的入口,主要完成登录、退出、连接管理等功能。也是获取其他模块的入口。 + +- EMChatManager: 管理消息的收发,完成会话管理等功能。 + +- EMContactManager: 负责好友的添加删除,黑名单的管理。 + +- EMGroupManager: 负责群组的管理,创建、删除群组,管理群组成员等功能。 + +- EMChatroomManager: 负责聊天室的管理。 + + + +## 集成 SDK + +环信 SDK 支持 **pod 方式导入**,**手动导入**两种方式任选其一即可,下面分别介绍两种导入方式。 + +:::notice +从 3.6.0 版本开始,SDK 只支持 iOS 9.0 及以上版本。 +::: + +### Pod 导入 SDK + +推荐使用 `Cocoapods` 集成环信 SDK。 Cocoapods 提供了一个简单的依赖管理系统,避免手动导入产生的错误(首先需要确认已经安装了 Cocoapods,如果没有安装过 Cocoapods,参考安装使用指南:https://www.cnblogs.com/wangluochong/p/5567082.html)。 + +``` +sudo gem install cocoapods +pod setup +``` + +在 `Xcode` 项目的根目录下,新建一个空文件,命名为 `Podfile`,向此文件添加以下行: + +``` +pod 'HyphenateChat' +``` + +在 `Podfile` 目录下,执行以下指令: + +``` +pod install --repo-update ``` -3. 运行 `pod update` 命令更新本地库版本。 -4. 运行 `pod install` 命令安装 HyphenateChat SDK。成功安装后,**Terminal** 中会显示 `Pod installation complete!`,此时项目文件夹下会生成一个 **workspace** 文件。 +执行完 pod install,打开工程目录,找到 .xcworkspace 文件运行即可。 + +------ + +### 手动导入 SDK + +[下载环信demo](https://download-sdk.oss-cn-beijing.aliyuncs.com/downloads/iOS_IM_SDK_V3.7.4.7.zip) + +- HyphenateChat 开发使用 SDK + +开发者最开始集成,如果选择手动导入文件集成的方式,只需要向工程中添 `HyphenateChat` 就可以,下面会介绍具体的集成方式。 + +demo 中的 SDK 文件夹为 Hyphenate SDK,将 SDK 文件夹拖入到工程中,并勾选截图中标注的三项。 + +![img](@static/images/privitization/choice.png) + +#### 设置工程属性 + +Xcode 中,向 General → Embedded Binaries 中添加依赖库。 + +**注意要将 'Do Not Embed' 改成 'Embed & Sign'** + +![img](@static/images/privitization/prepare1.png) + + + +### Demo 目录介绍 + +目录 EaseIM —>Class 中的 Demo 目录介绍 + + +![img](@static/images/privitization/prepare2.png) + + +- Account:主要是 demo 的注册,登录 + +- AppDelegate:主要是 demo 中初始化环信 SDK,注册推送等 + +- Communicate:demo 的语音视频通话功能页面(包含 1v1 实时通话以及多人实时通话的功能) + +- Chat:demo 的聊天功能页面 + +- Contact:demo 的好友功能页面 + +- Conversation:demo 的会话列表功能页面 + +- EaseIMHelper:demo 的单例类,主要是全局监听接收消息,好友,群组,聊天室等相关事件的回调,从而进行对应的处理 + +- Group:demo 的群组功能页面 + +- Helper:demo 的功能性文件,全局通用的配置 + +- Home:demo 的根控制器页面 + +- Notification:demo 的好友,群组相关请求通知的页面 + +- Settings:demo 的功能设置页面 + + + +## 集成 UI + +环信的 UI 模块在 demo 中的该路径下 EaseIM—Class + +demo 中有几大 UI 功能模块,在集成时将对应的模块添加到工程中即可。 + +- Helper——自定义库和页面,第三方库,全局通用模块 + +- Chat——聊天模块 + +- Conversation——会话列表模块 + +- Communicate——实时音视频模块(包含 1v1 实时通话以及多人实时通话的功能) + +- Contact——好友列表模块 + +- Group——群组模块 + +- Chatroom——聊天室模块 + +在集成时,必须要先向自己的工程中导入 `Helper` 模块,然后在根据自己的需求导入其他模块。 + +环信的 UI 模块依赖于以下三方库: + +- Masonry + +- MJRefresh + +- MBProgressHUD -国内开发者如果遇到网络问题导致 pod 命令无法执行,可使用国内镜像源,例如 [Gitee 镜像源](https://gitee.com/mirrors/CocoaPods-Specs) 或 [TUNA 镜像源](https://mirrors.tuna.tsinghua.edu.cn/help/CocoaPods/)。 +- SDWebImage -### 方法二:手动导入 SDK v3.8.9.1 及以上版本 +- FLAnimatedImage -1. 下载最新版的 [HyphenateChat iOS SDK](https://downloadsdk.easemob.com/downloads/iOS_IM_SDK_V3.8.9.1.zip) 并解压。 -2. 复制 SDK 包中的 `HyphenateChat.framework` 至项目路径下。 -3. 打开 Xcode,进入 **TARGETS > Project Name > General > Frameworks, Libraries, and Embedded Content**菜单。 -4. 点击 **+ > Add Other… > Add Files** 添加对应动态库,并确保添加的动态库 **Embed** 属性设置为 **Embed & Sign**。 +保证这些三方库在自己的工程中存在。 -添加完成后,项目会自动链接所需系统库。 +**注意**:三方推荐使用 pod 方式导入,手动导入需要修改 `info.plist` 重复等报错。 -## 3.初始化 SDK -在工程的 AppDelegate 中的以下方法中,调用 SDK 对应方法。 -```objectivec -(BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions +## 增加隐私权限 + +在工程`info.plist`文件中增加隐私权限 + +用于 Chat 聊天模块中发送图片,语音,视频,位置消息使用,如您的工程中已经添加过请忽略: + +- Privacy - Photo Library Usage Description 需要访问您的相册 + +- Privacy - Microphone Usage Description 需要访问您的麦克风 + +- Privacy - Camera Usage Description 需要访问您的摄像机 + +- Privacy - Location Always Usage Description 需要您的同意,才能始终访问位置 + + + +## 添加 SDK 以及 UI 头文件 + +建议在 `PCH` 文件中引入 SDK 以及 UI 的头文件。如果工程中没有 `pch` 文件,需要新建一个,并在 `Build Settings` 中设置 `Prefix Header` 为该 pch 文件,例如:`iOS/PrefixHeader.pch`。 + +在 pch 文件文件中添加如下代码: + +``` +#ifdef __OBJC__ +#import +// UI 头文件 +#import "EMHeaders.h" +#endif +``` + +如果自己工程中的 pch 文件还引入了其他的头文件,那么所有的头文件都需要放到。 + +``` +#ifdef __OBJC__ + +// 存放 pch 文件中所有的头文件 + +#endif 的内部 +``` + + +## 初始化及登录 + +初始化 SDK 以及登录环信服务器 + +### 初始化 SDK + +在工程的 `AppDelegate` 中的以下方法中,调用 SDK 对应方法。 + +``` +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // appkey 替换成你在环信即时通讯 IM 管理后台注册应用中的 App Key - EMOptions *options = [EMOptions optionsWithAppkey:@"<#appkey#>"]; - // apnsCertName是证书名称,可以先传 nil,等后期配置 APNs 推送时在传入证书名称 + // Appkey 替换成自己在环信管理后台注册应用中的 Appkey +EMOptions *options = [EMOptions optionsWithAppkey:@"appkey"]; +// apnsCertName是证书名称,可以先传nil,等后期配置apns推送时在传入证书名称 options.apnsCertName = nil; [[EMClient sharedClient] initializeSDKWithOptions:options]; return YES; } ``` -## 4.初始化聊天页面 +### 登录环信服务器 + +建议使用异步登录方法,防止网络不好的情况下,出现卡 UI 主线程的情况出现。 + +``` +// 传入在应用(appkey)下注册的IM用户user1,密码123,用于登录环信服务器 + +[[EMClient sharedClient] loginWithUsername:@"user1" password:@"123" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"登录成功"); + } else { + NSLog(@"登录失败的原因---%@", aError.errorDescription); + } +}]; +``` + +- 如果在集成调试阶段,可以在初始化环信 SDK 完成之后,就调用登录方法。 + +- 如果项目上线,建议开发者在登录自己服务器成功之后,再调用环信 SDK 登录方法使用用户绑定的环信 ID 登录环信服务器(开发者给自己用户在自己服务器创建账号的同时,调用环信的 REST 接口在给用户授权注册一个环信 ID,一起返回给 App 端,App 端拿到用户的账号密码以及环信 ID 密码分别登录自己的服务器以及环信服务器)。 + -向工程中导入 Chat 文件。 +## 初始化聊天页面 -```objectivec -// ConversationId 接收消息方的环信ID:@"user2" +向工程中导入 `Chat` 文件 + +``` +// ConversationId 接收消息方的环信 ID:@"user2" // type 聊天类型:EMConversationTypeChat 单聊类型 // createIfNotExist 如果会话不存在是否创建会话:YES - EMChatViewController *chatViewController = [[EMChatViewController alloc] initWithConversationId:@"user2" conversationType:EMConversationTypeChat]; - [self.navigationController pushViewController:chatViewController animated:YES]; +EMChatViewController *chatController = [[EMChatViewController alloc] initWithConversationId:@"user2" conversationType:EMConversationTypeChat createIfNotExist:YES]; + +[self.navigationController pushViewController:chatController animated:YES]; ``` -有导航的话,可以用 push 方式跳转到聊天页面发消息测试,也就是用登录的 user1 给 user2 发消息,没有导航的话,可以用 present 方式跳转到聊天页面。 +有导航的话,可以用 `push` 方式跳转到聊天页面发消息测试,也就是用登录的 user1 给 user2 发消息,没有导航的话,可以用 `present` 方式跳转到聊天页面。 + + +## 集成实时音视频通话 -## 5.创建账号 +向工程中导入 `Communicate` 文件 -设置用户名和密码创建账号。 +在初始化 SDK 完成之后,在初始化SDK所在的类引入头文件: -```objectivec -// 异步方法 -[[EMClient sharedClient] registerWithUsername:@"username" - password:@"your password" - completion:^(NSString *aUsername, EMError *aError) { - }]; +``` +#import "SingleCallController.h" // 1v1 实时通话功能的头文件 +#import "ConferenceController.h" // 多人实时通话功能的头文件 + 添加: +[SingleCallController sharedManager]; // 初始化 1v1 实时通话功能的单例 +[ConferenceController sharedManager]; // 初始化多人实时通话功能的单例 ``` -## 6. 登录账号 +在聊天页面中下方,点击视频通话图标按钮即可使用。 -利用创建的用户名和密码登录环信 IM。 -```objectivec -[[EMClient sharedClient] loginWithUsername:@"username" - password:@"your password" - completion:^(NSString *aUsername, EMError *aError) { -}]; +## 集成其他模块 + +集成这些模块,涉及到一些回调方法的监听与页面的跳转,需要在初始化环信 SDK 之后,添加 [EMDemoHelper shareHelper]; + +### 会话列表 + +向工程中导入 `Conversation` 文件 + +头文件:`#import “EMConversationsViewController.h”` + +初始化页面跳转(导航跳转示例): + +``` +EMConversationsViewController *conversationVC = [[EMConversationsViewController alloc] init]; +[self.navigationController pushViewController:conversationVC animated:YES]; +``` + +### 好友列表 + +向工程中导入 `Contact` 文件 + +头文件:`#import “EMContactsViewController.h”` + +初始化页面跳转(导航跳转示例): + ``` +EMContactsViewController *contactVC= [[EMContactsViewController alloc] init]; +[self.navigationController pushViewController:contactVC animated:YES]; +``` + +### 群组 + +向工程中导入 `Group` 文件 + +头文件:`#import “EMGroupsViewController.h”` + +初始化页面跳转(导航跳转示例): -## 7.发送消息 +``` +EMGroupsViewController *groupVC= [[EMContactsViewController alloc] init]; +[self.navigationController pushViewController:groupVC animated:YES]; +``` + +### 聊天室 + +向工程中导入 `Chatroom` 文件 + +头文件:`#import “EMChatroomsViewController.h”` + +初始化页面跳转(导航跳转示例): + +``` +EMChatroomsViewController *chatRoomVC= [[EMChatroomsViewController alloc] init]; +[self.navigationController pushViewController:chatRoomVC animated:YES]; +``` + +------ + +## 集成动态库上传 AppStore + +从 3.7.4 版本 SDK 开始支持 bitcode 打包,并且不再支持 armv7,i386 指令集,打包时需去除 armv7 指令。 +Xcode11 需在 Build Settings - Valid Architectures 设置项去除 armv7 指令; +Xcode12 需在 Build Settings - Excluded Architectures 设置项添加 armv7 指令,若是 iOS11 以上无需此操作; + +由于 iOS 编译的特殊性,为了方便开发者使用,我们将 `x86_64`,`arm64` 两个平台都合并到了一起,所以使用动态库上传 AppStore 时需要将 `x86_64` 平台删除后,才能正常提交审核。 + +首先将 SDK 进行备份。因为剔除过 SDK 的项目只能真机运行,要想继续模拟器运行,要换回未剔除的 SDK。 + +然后进入到 Launchpad 中,找到其他—打开终端,然后 cd 到 SDK 的所在目录。 +简单的方式就是找到项目中的环信 SDK,然后终端先输入 cd,然后按空格键,将环信 SDK 拖拽到终端内,会自动生成SDK的路径,然后环信 SDK 名称 .framework 删除掉,不要 cd 到环信 SDK,只 cd 到 SDK 所在的目录下即可。 +示例: +比如环信 SDK 的路径是 +/Users/easemob-dn0164/Desktop/iOS_IM_SDK_V3.6.0/HyphenateFullSDK/Hyphenate.framework +那么只需要 cd 到 +/Users/easemob-dn0164/Desktop/iOS_IM_SDK_V3.6.0/HyphenateFullSDK/ +就可以了。 + +后续在 SDK 当前路径下执行以下命令删除 x86_64 平台 +实时音视频版本`Hyphenate.framework` + +``` +【首先进入Hyphenate.framework所在目录】 +// 移除支持 x86_64 的二进制文件 +lipo Hyphenate.framework/Hyphenate -remove x86_64 -output Hyphenate +//替换framwork内部二进制文件 +mv Hyphenate Hyphenate.framework/Hyphenate +//查看剥离后的二进制文件支持的CPU架构,如果显示 arm64,就完成剥离,可上传AppStore +lipo -info Hyphenate.framework/Hyphenate +``` -利用创建的用户名和密码登录环信 IM,向对端用户发送消息。在下面示例中,向 user 2 发送文本消息。 +不包含实时音视频版本 `HyphenateLite.framework` -```objectivec -// 创建消息 -EMTextMessageBody* textBody = [[EMTextMessageBody alloc] initWithText:@"hello"]; -EMChatMessage *message = [[EMChatMessage alloc] initWithConversationID:@"user2" - from:@"user1" - to:@"user2" - body:textBody - ext:@{}]; -// 发送消息 -[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMChatMessage *message, EMError *error) {}]; ``` +【首先进入HyphenateLite.framework所在目录】 +// 移除支持 x86_64 的二进制文件 +lipo HyphenateLite.framework/HyphenateLite -remove x86_64 -output HyphenateLite +//替换 framwork 内部二进制文件[记得备份] +mv HyphenateLite HyphenateLite.framework/HyphenateLite +//查看剥离后的二进制文件支持的CPU架构,如果显示 arm64,就完成剥离,可上传 AppStore +lipo -info HyphenateLite.framework/HyphenateLite +``` \ No newline at end of file diff --git a/docs/document/v1/ios/quickstart_v.md b/docs/document/v1/ios/quickstart_v.md new file mode 100644 index 000000000..c861150a9 --- /dev/null +++ b/docs/document/v1/ios/quickstart_v.md @@ -0,0 +1,131 @@ +# 环信即时通讯 IM iOS 快速开始 + + + +本文介绍如何快速集成环信即时通讯 IM iOS SDK 实现单聊。 + +## 实现原理 + +下图展示在客户端发送和接收一对一文本消息的工作流程。 + +![img](@static/images/android/sendandreceivemsg.png) + +## 前提条件 + +- Xcode (推荐最新版本)。 +- 安装 iOS 10.0 或更高版本的 iOS 模拟器或 Apple 设备。 +- CocoaPods [1.10.1 或更高版本](https://cocoapods.org/)。 +- 有效的环信即时通讯 IM 开发者账号和 App Key,见 [环信即时通讯云管理后台](/document/v1/privatization/uc_configure.html)。 +- 如果你的网络环境部署了防火墙,请联系环信技术支持设置白名单。 + +## 1. 准备开发环境 + +### 创建 Xcode 项目 + +参考以下步骤在 Xcode 中创建一个 iOS 平台下的 Single View App,项目设置如下: + +- **Product Name** 设为 `HyphenateChatQuickstart`。 +- **Organization Identifier** 设为 `hyphenatechat`。 +- **User Interface** 选择 **Storyboard**。 +- **Language** 选择 **Objective-C**。 + +## 2. 集成 SDK + +SDK 支持 **CocoaPods 导入**和**手动导入**两种方式。 + +### 方法一:使用 CocoaPods 集成 SDK。 + +1. 在 **Terminal** 里进入项目根目录,并运行 `pod init` 命令。项目文件夹下会生成一个 **Podfile** 文本文件。 +2. 打开 **Podfile** 文件,修改文件为如下内容: + +```pod +# platform :ios, '10.0' + + target 'EMChatQuickstart' do + pod 'HyphenateChat' + end +``` + +3. 运行 `pod update` 命令更新本地库版本。 +4. 运行 `pod install` 命令安装 HyphenateChat SDK。成功安装后,**Terminal** 中会显示 `Pod installation complete!`,此时项目文件夹下会生成一个 **workspace** 文件。 + +国内开发者如果遇到网络问题导致 pod 命令无法执行,可使用国内镜像源,例如 [Gitee 镜像源](https://gitee.com/mirrors/CocoaPods-Specs) 或 [TUNA 镜像源](https://mirrors.tuna.tsinghua.edu.cn/help/CocoaPods/)。 + +### 方法二:手动导入 SDK v3.8.9.1 及以上版本 + +1. 下载最新版的 [HyphenateChat iOS SDK](https://downloadsdk.easemob.com/downloads/iOS_IM_SDK_V3.8.9.1.zip) 并解压。 +2. 复制 SDK 包中的 `HyphenateChat.framework` 至项目路径下。 +3. 打开 Xcode,进入 **TARGETS > Project Name > General > Frameworks, Libraries, and Embedded Content**菜单。 +4. 点击 **+ > Add Other… > Add Files** 添加对应动态库,并确保添加的动态库 **Embed** 属性设置为 **Embed & Sign**。 + +添加完成后,项目会自动链接所需系统库。 + +## 3.初始化 SDK + +在工程的 AppDelegate 中的以下方法中,调用 SDK 对应方法。 + +```objectivec +(BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions +{ + // appkey 替换成你在环信即时通讯 IM 管理后台注册应用中的 App Key + EMOptions *options = [EMOptions optionsWithAppkey:@"<#appkey#>"]; + // apnsCertName是证书名称,可以先传 nil,等后期配置 APNs 推送时在传入证书名称 + options.apnsCertName = nil; + [[EMClient sharedClient] initializeSDKWithOptions:options]; + return YES; +} +``` + +## 4.初始化聊天页面 + +向工程中导入 Chat 文件。 + +```objectivec +// ConversationId 接收消息方的环信ID:@"user2" +// type 聊天类型:EMConversationTypeChat 单聊类型 +// createIfNotExist 如果会话不存在是否创建会话:YES + EMChatViewController *chatViewController = [[EMChatViewController alloc] initWithConversationId:@"user2" conversationType:EMConversationTypeChat]; + [self.navigationController pushViewController:chatViewController animated:YES]; +``` + +有导航的话,可以用 push 方式跳转到聊天页面发消息测试,也就是用登录的 user1 给 user2 发消息,没有导航的话,可以用 present 方式跳转到聊天页面。 + +## 5.创建账号 + +设置用户名和密码创建账号。 + +```objectivec +// 异步方法 +[[EMClient sharedClient] registerWithUsername:@"username" + password:@"your password" + completion:^(NSString *aUsername, EMError *aError) { + }]; +``` + +## 6. 登录账号 + +利用创建的用户名和密码登录环信 IM。 + +```objectivec +[[EMClient sharedClient] loginWithUsername:@"username" + password:@"your password" + completion:^(NSString *aUsername, EMError *aError) { + +}]; +``` + +## 7.发送消息 + +利用创建的用户名和密码登录环信 IM,向对端用户发送消息。在下面示例中,向 user 2 发送文本消息。 + +```objectivec +// 创建消息 +EMTextMessageBody* textBody = [[EMTextMessageBody alloc] initWithText:@"hello"]; +EMChatMessage *message = [[EMChatMessage alloc] initWithConversationID:@"user2" + from:@"user1" + to:@"user2" + body:textBody + ext:@{}]; +// 发送消息 +[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMChatMessage *message, EMError *error) {}]; +``` diff --git a/docs/document/v1/ios/reaction.md b/docs/document/v1/ios/reaction.md index 9004c5168..064abee75 100644 --- a/docs/document/v1/ios/reaction.md +++ b/docs/document/v1/ios/reaction.md @@ -6,7 +6,6 @@ :::notice 1. 目前 Reaction 仅适用于单聊和群组。聊天室暂不支持 Reaction 功能。 -2. 私有化版本不支持 Reaction 功能。 ::: ## 技术原理 @@ -30,8 +29,8 @@ Reaction 场景示例如下: 开始前,请确保满足以下条件: 1. 完成 `HyphenateChat 3.9.2.1 或以上版本` SDK 初始化,详见 [快速开始](quickstart.html)。 -2. 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -3. 已联系商务开通 Reaction 功能。 +2. 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +3. 私有部署已开通 Reaction 功能。 ## 实现方法 diff --git a/docs/document/v1/ios/releasenote.md b/docs/document/v1/ios/releasenote.md index e6f624172..764663295 100644 --- a/docs/document/v1/ios/releasenote.md +++ b/docs/document/v1/ios/releasenote.md @@ -1,7 +1,7 @@ # iOS IM SDK 更新日志 - + ## 版本 V3.7.4 2021-02-04 SDK: @@ -917,7 +915,7 @@ IM_DEMO 修改: 新功能: -- 实现不同模式的实时语音会议功能 [多人音视频会议](https://docs-im.easemob.com/im/ios/basics/multiuserconference) +- 实现不同模式的实时语音会议功能 [多人音视频会议](/private/media/conference_ios.html) - 添加动态更换对方实时视频显示页面的功能[IEMConferenceManager updateConference:streamId:remoteVideoView:completion:] ## 版本 V3.3.9 2018-02-11 diff --git a/docs/document/v1/ios/room_attributes.md b/docs/document/v1/ios/room_attributes.md index ac023fd45..f97aee547 100644 --- a/docs/document/v1/ios/room_attributes.md +++ b/docs/document/v1/ios/room_attributes.md @@ -2,7 +2,7 @@ -聊天室是支持多人沟通的即时通讯系统。聊天室属性可分为聊天室名称、描述和公告等基本属性和自定义属性(key-value)。若聊天室基本属性不满足业务要求,用户可增加自定义属性并同步给所有成员。利用自定义属性可以存储直播聊天室的类型、狼人杀等游戏中的角色信息和游戏状态以及实现语聊房的麦位管理和同步等。聊天室自定义属性以键值对(key-value)形式存储,属性信息变更会实时同步给聊天室成员。 +聊天室是支持多人沟通的即时通讯系统。聊天室属性可分为聊天室名称、描述和公告等基本属性。 本文介绍如何管理聊天室属性信息。 @@ -11,17 +11,17 @@ 环信即时通讯 IM SDK 提供 `IEMChatRoomManager` 类、`EMChatRoomManagerDelegate` 类和 `EMChatroom` 类用于聊天室属性管理,支持你通过调用 API 在项目中实现如下功能: - 获取和更新聊天室基本属性; -- 获取聊天室自定义属性; + ## 前提条件 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的 [使用限制](/product/limitation.html)。 -- 了解聊天室的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 + ## 实现方法 @@ -79,7 +79,7 @@ EMError *error = nil; // 异步方法 [[EMClient sharedClient].roomManager updateDescription:textString forChatroom:self.chatroom.chatroomId completion:nil]; ``` - + ### 监听聊天室事件 详见 [监听聊天室事件](room_manage.html#监听聊天室事件)。 diff --git a/docs/document/v1/ios/room_manage.md b/docs/document/v1/ios/room_manage.md index ed6ea659e..52473bbb2 100644 --- a/docs/document/v1/ios/room_manage.md +++ b/docs/document/v1/ios/room_manage.md @@ -25,9 +25,8 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的 [使用限制](/product/limitation.html)。 -- 了解环信即时通讯 IM 不同版本的聊天室相关数量限制,详见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im)。 -- 只有超级管理员才有创建聊天室的权限,因此你还需要确保已调用 RESTful API 添加了超级管理员,详见 [添加聊天室超级管理员](/document/server-side/chatroom.html#添加超级管理员)。 +- 了解环信即时通讯 IM 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 只有超级管理员才有创建聊天室的权限,因此你还需要确保已调用 RESTful API 添加了超级管理员,详见 [添加聊天室超级管理员](/document/v1/server-side/chatroom.html#添加超级管理员)。 - 聊天室创建者和管理员的数量之和不能超过 100 ,即管理员最多可添加 99 个。 ## 实现方法 @@ -36,9 +35,9 @@ ### 创建聊天室 -仅 [超级管理员](/document/server-side/chatroom.html#管理超级管理员) 可以调用 `createChatroomWithSubject` 方法创建聊天室,并设置聊天室的名称、描述、最大成员数等信息。成功创建聊天室后,该超级管理员为该聊天室的所有者。 +仅 [超级管理员](/document/v1/server-side/chatroom.html#管理超级管理员) 可以调用 `createChatroomWithSubject` 方法创建聊天室,并设置聊天室的名称、描述、最大成员数等信息。成功创建聊天室后,该超级管理员为该聊天室的所有者。 -你也可以直接调用 REST API [从服务端创建聊天室](/document/server-side/chatroom.html#创建聊天室)。 +你也可以直接调用 REST API [从服务端创建聊天室](/document/v1/server-side/chatroom.html#创建聊天室)。 示例代码如下: diff --git a/docs/document/v1/ios/room_members.md b/docs/document/v1/ios/room_members.md index 9c0c73bb9..019aa42c0 100644 --- a/docs/document/v1/ios/room_members.md +++ b/docs/document/v1/ios/room_members.md @@ -21,8 +21,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的 [使用限制](/product/limitation.html)。 -- 了解环信即时通讯 IM 聊天室相关限制,详见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 diff --git a/docs/document/v1/ios/thread.md b/docs/document/v1/ios/thread.md index 594924d5e..4af20ad26 100644 --- a/docs/document/v1/ios/thread.md +++ b/docs/document/v1/ios/thread.md @@ -4,9 +4,6 @@ 子区是群组成员的子集,是支持多人沟通的即时通讯系统,本文介绍如何使用环信即时通讯 IM iOS SDK 在实时互动 app 中创建和管理子区,并实现子区相关功能。 -:::notice -私有化版本不支持子区功能。 -::: ## 技术原理 @@ -26,9 +23,8 @@ 开始前,请确保满足以下条件: - 完成 3.9.3 或以上版本 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -- 了解子区和子区成员数量限制,详见 [使用限制](/product/limitation.html)。 -- 联系商务开通子区功能。 +- 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 私有部署已开通子区功能。 ## 实现方法 diff --git a/docs/document/v1/ios/thread_message.md b/docs/document/v1/ios/thread_message.md index e09af9b6a..e7cbdffaa 100644 --- a/docs/document/v1/ios/thread_message.md +++ b/docs/document/v1/ios/thread_message.md @@ -30,9 +30,8 @@ 开始前,请确保满足以下条件: - 完成 3.9.3 以上版本 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -- 了解子区和子区成员数量限制,详见 [使用限制](/product/limitation.html)。 -- 联系商务开通子区功能。 +- 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 私有部署已开通子区功能。 ## 实现方法 diff --git a/docs/document/v1/ios/user_relationship.md b/docs/document/v1/ios/user_relationship.md index 6410b097c..e75687788 100644 --- a/docs/document/v1/ios/user_relationship.md +++ b/docs/document/v1/ios/user_relationship.md @@ -1,226 +1,271 @@ -# 管理用户关系 +# 好友管理 - -用户登录后,可进行添加联系人、获取好友列表等操作。 -本文介绍如何通过环信即时通讯 IM SDK 管理好友关系,包括添加、同意、拒绝、删除、查询好友,以及管理黑名单,包括添加、移出、查询黑名单。 -SDK 提供用户关系管理功能,包括好友列表管理和黑名单管理: +注:环信不是好友也可以聊天,不推荐使用环信的好友机制。如果你有自己的服务器或好友关系,请自己维护好友关系。 -- 好友列表管理:查询好友列表、申请添加好友、同意好友申请、拒绝好友申请和删除好友等操作。 -- 黑名单管理:查询黑名单列表、将添加用户至黑名单以及从黑名单中移出用户等操作。 +好友管理涉及到的环信SDK头文件如下: -## 技术原理 - -环信即时通讯 IM iOS SDK 可以实现好友的添加移除,黑名单的添加移除等功能,主要调用方法如下: - -- `addContact` 申请添加好友。 -- `deleteContact` 删除好友。 -- `getContactsFromServerWithCompletion` 从服务器获取好友列表。 -- `addUserToBlackList` 添加黑名单。 -- `removeUserFromBlackList` 删除黑名单。 -- `getBlackListFromServerWithCompletion` 从服务器获取黑名单列表。 +``` +// 好友方法调用部分,比如添加代理,移除代理,添加,删除好友等 +IEMContactManager.h -## 前提条件 +// 好友的协议回调方法部分,比如监听接收好友请求的回调方法等 +EMContactManagerDelegate.h +``` -开始前,请确保满足以下条件: +## 获取好友列表 -- 完成 SDK 初始化并连接到服务器,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html); -- 调用好友请求相关方法之前先导入头文件 `IEMContactManager.h`; -- 调用监听接收好友请求等回调方法 API 之前导入头文件:`EMContactManagerDelegate.h`。 +获取好友列表,环信提供了两种方法。 -## 实现方法 +### 从服务器获取所有的好友 -本节展示如何在项目中管理好友的添加移除和黑名单的添加移除。 +``` +[[EMClient sharedClient].contactManager getContactsFromServerWithCompletion:^(NSArray *aList, EMError *aError) { + if (!aError) { + NSLog(@"获取所有好友成功 -- %@",aList); + } else { + NSLog(@"获取所有好友失败的原因 --- %@", aError.errorDescription); + } +}]; +``` -### 管理好友列表 +#### 从数据库获取所有的好友 -#### 添加好友 +``` +// 从服务器获取所有好友之后,才能从本地获取到好友 +NSArray *userlist = [[EMClient sharedClient].contactManager getContacts]; +``` -添加好友部分主要功能是发送好友请求、接收好友请求、处理好友请求和好友请求处理结果回调等。 +## 好友申请 -1. 申请指定用户添加好友 +### 发送加好友申请 -示例代码如下: +环信 iOS SDK 提供了添加好友的方法。 -```objectivec -// 异步方法 -[[EMClient sharedClient].contactManager addContact:@"aUsername" message:@"Message" completion:^(NSString *aUsername, EMError *aError) { -if (!aError) { - NSLog(@"添加好友成功 %@",aUsername); -} else { - NSLog(@"添加好友失败的原因 %@", aError.errorDescription); -} +``` +/*! + * 添加好友 + * + * @param aUsername 要添加的用户 + * @param aMessage 邀请信息 + * @param aCompletionBlock 完成的回调 + */ +- (void)addContact:(NSString *)aUsername + message:(NSString *)aMessage + completion:(void (^)(NSString *aUsername, EMError *aError))aCompletionBlock; + +// 调用 +[[EMClient sharedClient].contactManager addContact:@"6001" message:@"我想添加您为好友" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"添加好友成功 -- %@",aUsername); + } else { + NSLog(@"添加好友失败的原因 --- %@", aError.errorDescription); + } }]; ``` -2. 监听与好友请求相关的回调 +### 监听加好友请求 -请监听好友请求相关事件的回调,这样当用户收到好友请求,可以调用接受请求的 RESTful API 添加好友。服务器不会重复下发与好友请求相关的事件,建议退出应用时保存相关的请求数据。 +当您收到好友请求,如果您没有处理,请自己保存数据,新协议下不会每次都发送。 -设置好友监听示例代码如下: +``` +协议:EMContactManagerDelegate -```objectivec -// 注册好友回调。 +代理: +//注册好友回调 [[EMClient sharedClient].contactManager addDelegate:self delegateQueue:nil]; -// 移除好友回调。 +//移除好友回调 [[EMClient sharedClient].contactManager removeDelegate:self]; - -// 好友申请已收到。 -- (void)friendRequestDidReceiveFromUser:(NSString *)aUsername - message:(NSString *)aMessage - { } ``` -收到好友请求后,可以选择同意加好友申请或者拒绝加好友申请,示例代码如下: - -```objectivec -// 同意好友申请。 -// 异步方法 -[[EMClient sharedClient].contactManager approveFriendRequestFromUser:@"aUsername" completion:^(NSString *aUsername, EMError *aError) { -if (!aError) { - NSLog(@"同意加好友申请成功"); -} else { - NSLog(@"同意加好友申请失败的原因 --- %@", aError.errorDescription); -} -}]; +监听回调 -// 拒绝好友申请。 -// 异步方法 -[[EMClient sharedClient].contactManager declineFriendRequestFromUser:@"aUsername" completion:^(NSString *aUsername, EMError *aError) { -if (!aError) { - NSLog(@"拒绝加好友申请成功"); -} else { - NSLog(@"拒绝加好友申请失败的原因 %@", aError.errorDescription); -} -}]; ``` - -当你同意或者拒绝后,对方会通过好友事件回调,收到 `friendRequestDidApprove` 或者 `friendRequestDidDecline`。 - -示例代码如下: - -```objectivec -// 对方同意了好友申请。 -- (void)friendRequestDidApproveByUser:(NSString *)aUsername - { } - -// 对方拒绝了好友申请。 -- (void)friendRequestDidDeclineByUser:(NSString *)aUsername - { } +/*! + * 用户A发送加用户B为好友的申请,用户B会收到这个回调 + * + * @param aUsername 用户名 + * @param aMessage 附属信息 + */ +- (void)friendRequestDidReceiveFromUser:(NSString *)aUsername + message:(NSString *)aMessage; ``` -#### 删除好友 +### 同意加好友申请 -删除联系人时会同时删除对方联系人列表中的该用户,建议执行双重确认,以免发生误删操作。删除操作不需要对方同意或者拒绝。 - -示例代码如下: - -```objectivec -// 删除好友。 -// 异步方法 -[[EMClient sharedClient].contactManager deleteContact:@"aUsername" isDeleteConversation:aIsDeleteConversation completion:^(NSString *aUsername, EMError *aError) { -if (!aError) { - NSLog(@"删除好友成功"); -} else { - NSLog(@"删除好友失败的原因 %@", aError.errorDescription); -} +``` +/*! + * 同意加好友的申请 + * + * @param aUsername 申请者 + * @param aCompletionBlock 完成的回调 + */ +- (void)approveFriendRequestFromUser:(NSString *)aUsername + completion:(void (^)(NSString *aUsername, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].contactManager approveFriendRequestFromUser:@"6001" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"同意加好友申请成功"); + } else { + NSLog(@"同意加好友申请失败的原因 --- %@", aError.errorDescription); + } }]; ``` -调用 `deleteContact` 删除好友后,用户 A,B 都会收到 `onContactDeleted` 回调,示例代码如下: +### 拒绝加好友申请 -```objectivec -// 好友已被删除。 -- (void)friendshipDidRemoveByUser:(NSString *)aUsername - { } +``` +/*! + * 拒绝加好友的申请 + * + * @param aUsername 申请者 + * @param aCompletionBlock 完成的回调 + */ +- (void)declineFriendRequestFromUser:(NSString *)aUsername + completion:(void (^)(NSString *aUsername, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].contactManager declineFriendRequestFromUser:@"6001" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"拒绝加好友申请成功"); + } else { + NSLog(@"拒绝加好友申请失败的原因 --- %@", aError.errorDescription); + } +}]; ``` -#### 获取好友列表 +### 好友申请处理结果回调 -你可以从服务器获取好友列表,也可以从本地数据库获取已保存的好友列表。 +监听回调 -:::notice -需要从服务器获取好友列表之后,才能从本地数据库获取到好友列表。 -::: +``` +/*! + @method + @brief 用户A发送加用户B为好友的申请,用户B同意后,用户A会收到这个回调 + */ +- (void)friendRequestDidApproveByUser:(NSString *)aUsername; + +/*! + @method + @brief 用户A发送加用户B为好友的申请,用户B拒绝后,用户A会收到这个回调 + */ +- (void)friendRequestDidDeclineByUser:(NSString *)aUsername; +``` -示例代码如下: +## 删除好友 -```objectivec -// 从服务器获取好友列表。 -// 异步方法 -[[EMClient sharedClient].contactManager getContactsFromServerWithCompletion:^(NSArray *aList, EMError *aError) { +``` +/*! + * 删除好友 + * + * @param aUsername 要删除的好友 + * @param aIsDeleteConversation 是否删除会话 + * @param aCompletionBlock 完成的回调 + */ +- (void)deleteContact:(NSString *)aUsername + isDeleteConversation:(BOOL)aIsDeleteConversation + completion:(void (^)(NSString *aUsername, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].contactManager deleteContact:@"6001" isDeleteConversation:YES completion:^(NSString *aUsername, EMError *aError) { if (!aError) { - NSLog(@"获取所有好友成功 %@",aList); + NSLog(@"删除好友成功"); } else { - NSLog(@"获取所有好友失败的原因 %@", aError.errorDescription); + NSLog(@"删除好友失败的原因 --- %@", aError.errorDescription); } -}]; -// 从本地数据库获取好友列表。 -NSArray *userlist = [[EMClient sharedClient].contactManager getContacts]; +}]; ``` -### 管理黑名单 +### 删除好友回调 -黑名单是与好友无任何关系的独立体系。可以将任何用户加入黑名单,不论该用户与你是否是好友关系。 +监听回调 -黑名单功能包括加入黑名单,从黑名单移出用户和获取黑名单列表。对于获取黑名单,你可从服务器获取黑名单列表,也可从本地数据库获取已保存的黑名单列表。 +``` +/*! + @method + @brief 用户B删除与用户A的好友关系后,用户A,B会收到这个回调 +*/ +- (void)friendshipDidRemoveByUser:(NSString *)aUsername; +``` -#### 查看当前用户黑名单列表 +## 黑名单 -1. 通过服务器获取黑名单列表 +### 获取好友黑名单 -从服务器获取黑名单列表之后,才能从本地数据库获取到黑名单列表。 +环信的黑名单体系是独立的,与好友无任何关系。也就是说,您可以将任何人加入黑名单,不论他是否与您是好友关系。同时,如果您将好友加入黑名单,则他仍然是您的好友,只不过同时也在黑名单中。 -```objectivec -// 从服务器获取黑名单列表。 -// 异步方法 +查询黑名单列表,环信提供了两种方法。 + +#### 异步方法 + +``` +/*! + * 从服务器获取黑名单列表 + * + * @param aCompletionBlock 完成的回调 + */ +- (void)getBlackListFromServerWithCompletion:(void (^)(NSArray *aList, EMError *aError))aCompletionBlock; + +// 调用: [[EMClient sharedClient].contactManager getBlackListFromServerWithCompletion:^(NSArray *aList, EMError *aError) { if (!aError) { - NSLog(@"获取黑名单列表成功 %@",aList); + NSLog(@"获取黑名单列表成功 -- %@",aList); } else { - NSLog(@"获取黑名单列表失败的原因 %@", aError.errorDescription); + NSLog(@"获取黑名单列表失败的原因 --- %@", aError.errorDescription); } }]; ``` -2. 从本地数据库获取黑名单列表 +#### 从数据库获取黑名单列表 -```objectivec -// 同步方法 +``` +// 从服务器获取黑名单列表之后,才能从本地获取到黑名单列表 NSArray *blockList = [[EMClient sharedClient].contactManager getBlackList]; ``` -#### 将用户加入黑名单 - -你可以调用 `addUserToBlackList` 将指定用户加入黑名单。用户被加入黑名单后将无法向你发送消息,也无法发送好友申请。 - -用户可以将任何其他聊天用户添加到他们的黑名单列表中,无论该用户是否是好友。好友被加入黑名单后仍在好友列表上显示。 - -示例代码如下: +### 加入黑名单 -```objectivec -// 异步方法 -[[EMClient sharedClient].contactManager addUserToBlackList:@"aUsername" completion:^(NSString *aUsername, EMError *aError) { +``` +/*! + * 将用户加入黑名单 + * + * @param aUsername 要加入黑名单的用户 + * @param aCompletionBlock 完成的回调 + */ +- (void)addUserToBlackList:(NSString *)aUsername + completion:(void (^)(NSString *aUsername, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].contactManager addUserToBlackList:@"6001" completion:^(NSString *aUsername, EMError *aError) { if (!aError) { NSLog(@"将用户加入黑名单成功"); } else { - NSLog(@"将用户加入黑名单失败的原因 %@", aError.errorDescription); + NSLog(@"将用户加入黑名单失败的原因 --- %@", aError.errorDescription); } }]; ``` -#### 将用户移出黑名单 +### 移出黑名单 -你可以调用 `removeUserFromBlackList` 将用户从黑名单移除,用户发送消息等行为将恢复。 +接口调用 -```objectivec -// 异步方法 -[[EMClient sharedClient].contactManager removeUserFromBlackList:@"aUsername" completion:^(NSString *aUsername, EMError *aError) { +``` +/*! + * 将用户移出黑名单 + * + * @param aUsername 要移出黑命单的用户 + * @param aCompletionBlock 完成的回调 + */ +- (void)removeUserFromBlackList:(NSString *)aUsername + completion:(void (^)(NSString *aUsername, EMError *aError))aCompletionBlock; + +// 调用: +[[EMClient sharedClient].contactManager removeUserFromBlackList:@"6001" completion:^(NSString *aUsername, EMError *aError) { if (!aError) { NSLog(@"将用户移出黑名单成功"); } else { - NSLog(@"将用户移出黑名单失败的原因 %@", aError.errorDescription); + NSLog(@"将用户移出黑名单失败的原因 --- %@", aError.errorDescription); } -}]; +}]; ``` \ No newline at end of file diff --git a/docs/document/v1/ios/user_relationship_v.md b/docs/document/v1/ios/user_relationship_v.md new file mode 100644 index 000000000..35117c483 --- /dev/null +++ b/docs/document/v1/ios/user_relationship_v.md @@ -0,0 +1,226 @@ +# 管理用户关系 + + + +用户登录后,可进行添加联系人、获取好友列表等操作。 +本文介绍如何通过环信即时通讯 IM SDK 管理好友关系,包括添加、同意、拒绝、删除、查询好友,以及管理黑名单,包括添加、移出、查询黑名单。 +SDK 提供用户关系管理功能,包括好友列表管理和黑名单管理: + +- 好友列表管理:查询好友列表、申请添加好友、同意好友申请、拒绝好友申请和删除好友等操作。 +- 黑名单管理:查询黑名单列表、将添加用户至黑名单以及从黑名单中移出用户等操作。 + +## 技术原理 + +环信即时通讯 IM iOS SDK 可以实现好友的添加移除,黑名单的添加移除等功能,主要调用方法如下: + +- `addContact` 申请添加好友。 +- `deleteContact` 删除好友。 +- `getContactsFromServerWithCompletion` 从服务器获取好友列表。 +- `addUserToBlackList` 添加黑名单。 +- `removeUserFromBlackList` 删除黑名单。 +- `getBlackListFromServerWithCompletion` 从服务器获取黑名单列表。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化并连接到服务器,详见 [快速开始](quickstart.html); +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html); +- 调用好友请求相关方法之前先导入头文件 `IEMContactManager.h`; +- 调用监听接收好友请求等回调方法 API 之前导入头文件:`EMContactManagerDelegate.h`。 + +## 实现方法 + +本节展示如何在项目中管理好友的添加移除和黑名单的添加移除。 + +### 管理好友列表 + +#### 添加好友 + +添加好友部分主要功能是发送好友请求、接收好友请求、处理好友请求和好友请求处理结果回调等。 + +1. 申请指定用户添加好友 + +示例代码如下: + +```objectivec +// 异步方法 +[[EMClient sharedClient].contactManager addContact:@"aUsername" message:@"Message" completion:^(NSString *aUsername, EMError *aError) { +if (!aError) { + NSLog(@"添加好友成功 %@",aUsername); +} else { + NSLog(@"添加好友失败的原因 %@", aError.errorDescription); +} +}]; +``` + +2. 监听与好友请求相关的回调 + +请监听好友请求相关事件的回调,这样当用户收到好友请求,可以调用接受请求的 RESTful API 添加好友。服务器不会重复下发与好友请求相关的事件,建议退出应用时保存相关的请求数据。 + +设置好友监听示例代码如下: + +```objectivec +// 注册好友回调。 +[[EMClient sharedClient].contactManager addDelegate:self delegateQueue:nil]; +// 移除好友回调。 +[[EMClient sharedClient].contactManager removeDelegate:self]; + +// 好友申请已收到。 +- (void)friendRequestDidReceiveFromUser:(NSString *)aUsername + message:(NSString *)aMessage + { } +``` + +收到好友请求后,可以选择同意加好友申请或者拒绝加好友申请,示例代码如下: + +```objectivec +// 同意好友申请。 +// 异步方法 +[[EMClient sharedClient].contactManager approveFriendRequestFromUser:@"aUsername" completion:^(NSString *aUsername, EMError *aError) { +if (!aError) { + NSLog(@"同意加好友申请成功"); +} else { + NSLog(@"同意加好友申请失败的原因 --- %@", aError.errorDescription); +} +}]; + +// 拒绝好友申请。 +// 异步方法 +[[EMClient sharedClient].contactManager declineFriendRequestFromUser:@"aUsername" completion:^(NSString *aUsername, EMError *aError) { +if (!aError) { + NSLog(@"拒绝加好友申请成功"); +} else { + NSLog(@"拒绝加好友申请失败的原因 %@", aError.errorDescription); +} +}]; +``` + +当你同意或者拒绝后,对方会通过好友事件回调,收到 `friendRequestDidApprove` 或者 `friendRequestDidDecline`。 + +示例代码如下: + +```objectivec +// 对方同意了好友申请。 +- (void)friendRequestDidApproveByUser:(NSString *)aUsername + { } + +// 对方拒绝了好友申请。 +- (void)friendRequestDidDeclineByUser:(NSString *)aUsername + { } +``` + +#### 删除好友 + +删除联系人时会同时删除对方联系人列表中的该用户,建议执行双重确认,以免发生误删操作。删除操作不需要对方同意或者拒绝。 + +示例代码如下: + +```objectivec +// 删除好友。 +// 异步方法 +[[EMClient sharedClient].contactManager deleteContact:@"aUsername" isDeleteConversation:aIsDeleteConversation completion:^(NSString *aUsername, EMError *aError) { +if (!aError) { + NSLog(@"删除好友成功"); +} else { + NSLog(@"删除好友失败的原因 %@", aError.errorDescription); +} +}]; +``` + +调用 `deleteContact` 删除好友后,用户 A,B 都会收到 `onContactDeleted` 回调,示例代码如下: + +```objectivec +// 好友已被删除。 +- (void)friendshipDidRemoveByUser:(NSString *)aUsername + { } +``` + +#### 获取好友列表 + +你可以从服务器获取好友列表,也可以从本地数据库获取已保存的好友列表。 + +:::notice +需要从服务器获取好友列表之后,才能从本地数据库获取到好友列表。 +::: + +示例代码如下: + +```objectivec +// 从服务器获取好友列表。 +// 异步方法 +[[EMClient sharedClient].contactManager getContactsFromServerWithCompletion:^(NSArray *aList, EMError *aError) { + if (!aError) { + NSLog(@"获取所有好友成功 %@",aList); + } else { + NSLog(@"获取所有好友失败的原因 %@", aError.errorDescription); + } +}]; +// 从本地数据库获取好友列表。 +NSArray *userlist = [[EMClient sharedClient].contactManager getContacts]; +``` + +### 管理黑名单 + +黑名单是与好友无任何关系的独立体系。可以将任何用户加入黑名单,不论该用户与你是否是好友关系。 + +黑名单功能包括加入黑名单,从黑名单移出用户和获取黑名单列表。对于获取黑名单,你可从服务器获取黑名单列表,也可从本地数据库获取已保存的黑名单列表。 + +#### 查看当前用户黑名单列表 + +1. 通过服务器获取黑名单列表 + +从服务器获取黑名单列表之后,才能从本地数据库获取到黑名单列表。 + +```objectivec +// 从服务器获取黑名单列表。 +// 异步方法 +[[EMClient sharedClient].contactManager getBlackListFromServerWithCompletion:^(NSArray *aList, EMError *aError) { + if (!aError) { + NSLog(@"获取黑名单列表成功 %@",aList); + } else { + NSLog(@"获取黑名单列表失败的原因 %@", aError.errorDescription); + } +}]; +``` + +2. 从本地数据库获取黑名单列表 + +```objectivec +// 同步方法 +NSArray *blockList = [[EMClient sharedClient].contactManager getBlackList]; +``` + +#### 将用户加入黑名单 + +你可以调用 `addUserToBlackList` 将指定用户加入黑名单。用户被加入黑名单后将无法向你发送消息,也无法发送好友申请。 + +用户可以将任何其他聊天用户添加到他们的黑名单列表中,无论该用户是否是好友。好友被加入黑名单后仍在好友列表上显示。 + +示例代码如下: + +```objectivec +// 异步方法 +[[EMClient sharedClient].contactManager addUserToBlackList:@"aUsername" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"将用户加入黑名单成功"); + } else { + NSLog(@"将用户加入黑名单失败的原因 %@", aError.errorDescription); + } +}]; +``` + +#### 将用户移出黑名单 + +你可以调用 `removeUserFromBlackList` 将用户从黑名单移除,用户发送消息等行为将恢复。 + +```objectivec +// 异步方法 +[[EMClient sharedClient].contactManager removeUserFromBlackList:@"aUsername" completion:^(NSString *aUsername, EMError *aError) { + if (!aError) { + NSLog(@"将用户移出黑名单成功"); + } else { + NSLog(@"将用户移出黑名单失败的原因 %@", aError.errorDescription); + } +}]; +``` \ No newline at end of file diff --git a/docs/document/v1/ios/userprofile.md b/docs/document/v1/ios/userprofile.md index c28363ace..06c277674 100644 --- a/docs/document/v1/ios/userprofile.md +++ b/docs/document/v1/ios/userprofile.md @@ -9,7 +9,7 @@ 例如,在招聘场景下,利用用户属性功能可以存储性别、邮箱、用户类型(面试者)、职位类型(web 研发)等。查看用户信息时,可以直接查询服务器存储的用户属性信息。 本文介绍如何通过管理用户属性设置、更新、存储并获取实时消息用户的相关信息。 - + \ No newline at end of file diff --git a/docs/document/v1/linux/overview.md b/docs/document/v1/linux/overview.md new file mode 100644 index 000000000..9a3a5aad4 --- /dev/null +++ b/docs/document/v1/linux/overview.md @@ -0,0 +1,109 @@ +# Linux SDK 集成说明 + + +Linux SDK 是为在 Linux 及其他嵌入式设备中集成 IM 功能提供的 SDK。用户可以用 SDK 实现 IM 功能。目前支持文本消息、图片、语音、位置等消息以及透传消息,还可以实现好友管理、群组管理等功能。 + +目前已经支持 ARM 平台及 MIPS 平台。 + +## 集成准备 + +获取环信 IM Linux SDK,SDK中包含如下文件: + +- release +- doc +- demo + +release 目录中包含SDK的库文件和头文件,libeasemob.a 是 SDK 静态库文件,include 目录包含 sdk 的头文件,doc 目录包含对 sdk 的详细说明,demo 包含使用 SDK 的 demo 程序。 + +## 集成示例 + +### 获取 EMClient + +EMClient 是 IM 服务的入口,可以直接调用 EMClient 的接口,也可以通过 EMClient 获得相应 EMContactManager、EMChatManager 等进行相应的操作。 + +``` +#include "emclient.h" + ... + using namespace easemob; + + easemob::EMChatConfigsPtr configPtr = easemob::EMChatConfigsPtr(new easemob::EMChatConfigs(resourcePath, workPath, "easemob-demo#chatdemoui")); + chatClient = easemob::EMClient::create(configPtr); +``` + +### 注册及登录 + +调用 chatclient 的 createAccount(), login() 接口可以实现注册、登录功能。 + +注册的示例: + +``` +easemob::EMErrorPtr result = chatClient->createAccount("zhangsan", "passw0rd"); +if(result->mErrorCode == EMError::NO_ERROR) { + cout << "Sing up successfully." << endl; +} else { + cout << result->mDescription << endl; +} +``` + +登录的示例 : + +``` +easemob::EMErrorPtr result = chatClient->login("zhangsan", "passw0rd"); +if(result->mErrorCode == EMError::NO_ERROR) { + cout << "Login successfully" << endl; +} else { + cout << result->mDescription << endl; +} +``` + +**注意:** createAccount(), login() 是需要与后台服务器通讯的操作,可能需要一定时间,如果程序想同时显示 UI 的话,需要放在单独线程中处理。 + +### 添加好友 + +管理好友的操作需要通过 EMChatManager 进行。 + +``` +chatClient->getContactManager().inviteContact("contact01", "hi, contact01"); +``` + +添加好友需要等待对方的确认,也可以由程序设置成自动接受好友邀请。 + +### 与好友聊天 + +接收消息需要实现 EMChatManagerListener 的 onReceiveMessage() 方法并且注册该listener。 + +``` +class Chat : public easemob::EMChatManagerListener { + void onReceiveMessage(const easemob::EMMessageList &messages); +} + +chatClient->getChatManager().addListener(this); +``` + +发送消息需要创建 EMMessage 实例,目前支持文本、图片、音频文件等消息类型。 + +``` +EMTextMessageBody* body = new EMTextMessageBody("How are you, du"); + easemob::EMMessagePtr msg = EMMessage::createSendMessage(loginUser, to, body); + + easemob::EMCallbackPtr callback(new easemob::EMCallback(mHandle, + [=]()->bool{ + window_->AddOutput("Msg send success"); + return true; + }, + [=](const easemob::EMErrorPtr error)->bool{ + window_->AddOutput( "Send message failed: " + error->mDescription); + return true; + })); + + msg->setCallback(callback); + chatClient->getChatManager().sendMessage(msg); +``` + +请注意 callback 的定义,为了能够获知 callback 的拥有者是否仍然存在,需要在您的类中定义`EMCallbackObserverHandle`。 + +``` +easemob::EMCallbackObserverHandle mHandle; +``` + +具体接口说明及使用可以参考 SDK 中的文档和 demo 程序。 \ No newline at end of file diff --git a/docs/document/v1/linux/releasenote.md b/docs/document/v1/linux/releasenote.md new file mode 100644 index 000000000..63e4247f4 --- /dev/null +++ b/docs/document/v1/linux/releasenote.md @@ -0,0 +1,6 @@ +# Linux SDK 更新日志 + +## 版本:V3.1.0 2016-03-24 + +1. 全新的通信协议:全新的基于消息同步的私有协议,在不稳定网络环境下更稳定更省流量,确保消息投递的可靠、顺序以及实时性,并具有更高的安全性。同时提供了更好的扩展性,将支持更多的对接和设备同步场景。 +2. 全新的 SDK:全面重构,将核心通信模块做了更好的封装;简化了接口,结构更清晰,集成更容易;提升了登录速度和弱网络环境下的可靠性。 \ No newline at end of file diff --git a/docs/document/v1/linux/techspec.md b/docs/document/v1/linux/techspec.md new file mode 100644 index 000000000..2230c31f7 --- /dev/null +++ b/docs/document/v1/linux/techspec.md @@ -0,0 +1,7 @@ +# 技术参数 + + +- 开发语言:C++11 +- 编译器:GCC 4.8.4 +- 已适配系统:Ubuntu 14.04、树莓派 +- 第三方库:libpthread、libsqlite3、libcurl、libssl、libz \ No newline at end of file diff --git a/docs/document/v1/privatization/easemob_app_token.md b/docs/document/v1/privatization/easemob_app_token.md new file mode 100644 index 000000000..07180658e --- /dev/null +++ b/docs/document/v1/privatization/easemob_app_token.md @@ -0,0 +1,81 @@ +# 使用环信 App Token 鉴权 + + + +环信提供的 REST API 需要 app token (管理员权限 token) 才能使用,即发送 HTTP 请求时需要携带 app token。本文介绍如何获取 app token。 + + +## 获取管理员权限 Token + +获取 token 时,服务器会返回 token 有效期,即响应中的 `expires_in` 字段的值。由于网络延迟等原因,系统不保证 token 在此值表示的有效期内绝对有效。如果发现 token 使用异常,如返回 HTTP 状态码 401,请重新获取新的 token。 + +:::notice +请不要频繁向服务器发送获取 token 的请求,同一账号发送此请求超过一定频率会被服务器封禁。 +::: + +### HTTP 请求 + +```http +POST https://{host}/{org_name}/{app_name}/token +``` + +#### 路径参数 + +| 参数 | 类型 | 是否必需 | 描述 | +| :--------- | :----- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | + +#### 请求 header + +| 参数 | 类型 | 是否必需 | 描述 | +| :------------- | :----- | :------- | :---------------------------------- | +| `Content-Type` | String | 是 | 内容类型。请填 `application/json`。 | +| `Accept` | String | 是 | 内容类型。请填 `application/json`。 | + +#### 请求 body + +| 参数 | 类型 | 是否必需 | 描述 | +| :-------------- | :----- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `grant_type` | String | 是 | 授权方式。该参数设置为固定字符串 `client_credentials`,即客户端凭证模式。 | +| `client_id` | String | 是 | App 的 `client_id`,用于生成 app token 调用 REST API。详见环信即时通讯控制台的 `应用概览->应用详情`页面下的`应用信息-Client ID`。 | +| `client_secret` | String | 是 | App 的 `client_secret`,用于生成 app token 调用 REST API。详见环信即时通讯控制台的 `应用概览->应用详情`页面下的`应用信息-ClientSecret`。 | +| `ttl` | Long | 否 | token 有效期,单位为秒。
- 若传入该参数,token 有效期以传入的值为准。
- 若不传该参数,以 详见环信即时通讯控制台的`用户认证`页面的 token 有效期的设置为准。
- 若设置为 `0`,则 token 永久有效。 | + +### HTTP 响应 + +#### 响应 body + +如果返回的 HTTP 状态码为 `200`,表示成功返回 token。响应 body 包含如下字段: + +| 参数 | 类型 | 描述 | +| :------------- | :----- | :--------------------------------------------------- | +| `access_token` | String | 有效的 Token 字符串。 | +| `expires_in` | Long | Token 有效时间,单位为秒,在有效期内不需要重复获取。 | +| `application` | String | 当前 App 的 UUID 值。 | + +如果返回的 HTTP 状态码非 `200`,表示请求失败。你可以参考 [响应状态码](/document/v1/server-side/error.html) 了解可能的原因。 + +### 示例 + +#### 请求示例 + +```shell +curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{ + "grant_type": "client_credentials", + "client_id": "YXA6i-Ak8Ol4Eei2l11ZjV-EAg", + "client_secret": "YXA6VunqiNxoB7IwXHInk1cGiXOOJfc", + "ttl": "1024000" + }' 'http://a1.easemob.com/easemob-demo/testapp/token' +``` + +#### 响应示例 + +```json +{ + "access_token": "YWMte3bGuOukEeiTkNP4grL7iwAAAAAAAAAAAAAAAAAAAAGL4CTw6XgR6LaXXVmNX4QCAgMAAAFnKdc-ZgBPGgBFTrLhhyK8woMEI005emtrLJFJV6aoxsZSioSIZkr5kw", + "expires_in": 1024000, + "application": "8be024f0-e978-11e8-b697-5d598d5f8402" +} +``` diff --git a/docs/document/v1/privatization/easemob_user_token.md b/docs/document/v1/privatization/easemob_user_token.md new file mode 100644 index 000000000..55335ed34 --- /dev/null +++ b/docs/document/v1/privatization/easemob_user_token.md @@ -0,0 +1,219 @@ +# 使用环信 User Token 鉴权 + + + +客户端 SDK 不提供获取 token 的 API。如果你的用户在客户端使用环信 token 登录和鉴权,你需要在应用服务器(App Server)集成环信服务端获取 token 的 API,实现获取 Token 的业务逻辑。 + +环信服务端支持以下三种方式获取用户 token: + +- 通过“用户 ID”和“密码”获取:用户注册后,使用 “用户 ID” 和 “密码” 登录。登录成功后,你的 App Server 会为客户端提供一个用户 token。 + +- 通过“用户 ID”获取:用户在客户端上登录时,你的应用服务器会下发用户 token,SDK 使用用户 ID 和用户 token 进行登录。开发者可通过 RESTful API 在你的应用服务器上对用户 token 进行管理,设置有效期,并确定当用户不存在时是否自动创建用户。 + +- 基于 `AppKey、AppSecret` 和 `userId`(即注册用户时传入的 `username`)生成动态 Token。 + +## 前提条件 + +要调用环信即时通讯 RESTful API,请确保满足以下要求: + +- 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](uc_configure.html)。 +- 已从服务端获取 app token,详见 [App Token 鉴权](easemob_app_token.html)。 + +## 认证方式 + +环信即时通讯 RESTful API 要求 Bearer HTTP 认证。每次发送 HTTP 请求时,都必须在请求头部填入如下 `Authorization` 字段: + +Authorization:`Bearer YourAppToken` + +为提高项目的安全性,环信使用 token(动态密钥)对即将登录即时通讯系统的用户进行鉴权。即时通讯 RESTful API 推荐使用 app token 的鉴权方式,详见 [使用 App Token 鉴权](easemob_app_token.html)。 + +## 通过用户 ID 和密码获取用户 token + +### HTTP 请求 + +```http +POST https://{host}/{org_name}/{app_name}/token +``` + +#### 路径参数 + +| 参数 | 类型 | 是否必需 | 描述 | +| :------------- | :----- | :------- | :--------------------- | +| `host`| String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。| + +#### 请求 header + +| 参数 | 类型 | 是否必需 | 描述 | +| :------------- | :----- | :------- | :---------------------- | +| `Content-Type` | String | 是 | 内容类型。请填 `application/json`。 | +| `Accept` | String | 是 | 内容类型。请填 `application/json`。 | + +#### 请求 body + +| 参数 | 类型 | 是否必需 | 描述 | +| :----------- | :----- | :------- | :------------------- | +| `grant_type` | String | 是 | 授权方式。
- 若值为 `password`,通过用户 ID 和密码获取 token,需设置 `username` 和 `password` 参数。在该请求中,该参数需设置为 `password`。
- 若值为 `inherit`,通过用户 ID 获取 token,只需设置 `username` 参数。 | +| `username` | String | 是 | 用户 ID。 | +| `password` | String | 是 | 用户的登录密码。 | +| `ttl` | Long | 否 | token 有效期,单位为秒。
- 若传入该参数,token 有效期以传入的值为准。
- 若不传该参数,以 详见环信即时通讯控制台的`用户认证`页面的 token 有效期的设置为准。
- 若设置为 `0`,则 token 永久有效。 | + +### HTTP 响应 + +#### 响应 body + +如果返回的 HTTP 状态码为 200,表示成功获取 token,响应包体中包含以下字段: + +| 字段 | 类型 | 描述 | +| :-------------- | :----- | :---------------- | +| `access_token` | String | 有效的用户 token。 | +| `expires_in` | Long | token 有效期,单位为秒。在有效期内无需重复获取。 | +| `user` | JSON | 用户相关信息。 | +| `user.uuid` | String | 用户的 UUID。即时通讯服务为该请求中的 app 或用户生成的唯一内部标识,用于生成用户 token。 | +| `user.type` | String | 对象类型,无需关注。 | +| `user.created` | Long | 注册用户的 Unix 时间戳,单位为毫秒。 | +| `user.modified` | Long | 最近一次修改用户信息的 Unix 时间戳,单位为毫秒。 | +| `user.username` | String | 用户 ID。 | +| `user.activated` | Bool | 用户是否为活跃状态:
- `true`:用户为活跃状态。
- `false`:用户为封禁状态。如要使用已被封禁的用户账户,你需要调用[解禁用户的 API](/document/v1/server-side/account_system.html#账号解禁)对账号解除封禁。 | + +如果返回的 HTTP 状态码非 200,表示请求失败。你可以参考[响应状态码](/document/v1/server-side/error.html)了解可能的原因。 + +### 示例 + +#### 请求示例 + +```shell +curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{ + "grant_type": "password", + "username": "C", + "password": "1", + "ttl": "1024000" + }' 'http://XXXX/XXXX/XXXX/token' +``` + +#### 响应示例 + +```json +{ + "access_token": "YWMtrR6ECkz8Eeyx6Y9j1eX9kbsMrFep3U6BvVj7KSnNonWqRx7gTPwR7Kzl-Q_xISNOAwMAAAF9UPZqbQAPoAAtYK9fWgaTNyuWoB3-6nGf_TXBx3Nt3XRZST-elU0x2A", + "expires_in": 1024000, + "user": { + "uuid": "aa471ee0-XXXX-XXXX-ace5-f90ff121234e", + "type": "user", + "created": 1637740861395, + "modified": 1637740861395, + "username": "c", + "activated": true + } +} +``` + +## 通过用户 ID 获取用户 token + +你通过用户 ID 获取用户 token。若用户 ID 不存在,你可以确定是否自动创建用户。 + +### HTTP 请求 + +```http +POST https://{host}/{org_name}/{app_name}/token +``` + +#### 路径参数 + +| 参数 | 类型 | 是否必需 | 描述 | +| :------------- | :----- | :------- | :---------------------------------- | +| `host`| String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。| + +#### 请求 header + +| 参数 | 类型 | 是否必需 | 描述 | +| :------------- | :----- | :------- | :---------------------------------- | +| `Content-Type` | String | 是 | 内容类型。请填 `application/json`。 | +| `Accept` | String | 是 | 内容类型。请填 `application/json`。 | +| `Authorization`| String | 是 | App 管理员的鉴权 token,格式为 `Bearer YourAppToken`,其中 `Bearer` 为固定字符,后面为英文空格和获取到的 app token。 | + +#### 请求 body + +| 参数 | 类型 | 是否必需 | 描述 | +| :----------- | :----- | :------- | :------------------- | +| `grant_type` | String | 是 | 授权方式。
- 若值为 `password`,通过用户 ID 和密码获取 token,需设置 `username` 和 `password` 参数。
- 若值为 `inherit`,通过用户 ID 获取 token,只需设置 `username` 参数。在该请求中,该参数需设置为 `inherit`。 | +| `username` | String | 是 | 用户 ID。 | +| `autoCreateUser` | Boolean | 是 | 当用户不存在时,是否自动创建用户。**自动创建用户时,需保证授权方式(`grant_type`)必须为 `inherit`,API 请求 header 中使用 App token 进行鉴权**。 | +| `ttl` | Long | 否 | token 有效期,单位为秒。
- 若传入该参数,token 有效期以传入的值为准。
- 若不传该参数,有效期默认为 60 天。此外,也可通过 环信即时通讯控制台的`用户认证`页面的 token 有效期的设置为准。
- 若设置为 `0`,则 token 永久有效。 | + +### HTTP 响应 + +#### 响应 body + +如果返回的 HTTP 状态码为 `200`,表示成功获取 token。如果返回的 HTTP 状态码非 200,表示请求失败。你可以参考[响应状态码](/document/v1/server-side/error.html)了解可能的原因。 + +关于响应包体中的字段的描述,详见[通过用户 ID 和密码获取 token 的 API](#通过用户 ID 和密码获取用户 token) 中的响应字段的描述。 + +### 示例 + +#### 请求示例 + +```shell +# 将 替换为你在服务端生成的 App Token + +curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer ' -d '{ + "username": "test2333", + "grant_type": "inherit", + "autoCreateUser": true, + "ttl": 1024000 + }' 'http://XXXX/XXXX/XXXX/token' +``` + +#### 响应示例 + +自动创建用户并获取 token 的响应如下: + +```json +{ + "access_token": "YWMthyeiFhbyEe2eMGeYZSLlT7sMrFep3U6BvVj7KSnNonUiDB-wFvIR7a5Ttx2-01MYAwMAAAGCfIeryQAPoAAsuveDfkUrePkEM2Hgy6SaOTeTx3ETgh5cnXcP_HfBPg", + "expires_in": 1024000, + "user": { + "uuid": "220c1fb0-XXXX-XXXX-ae53-b71dbed35318", + "type": "user", + "created": 1659946472753, + "modified": 1659946472753, + "username": "test2333", + "activated": true + } +} +``` + +## 生成动态的用户 Token + +动态 Token 的生成方法依赖 `AppSecret`,因此生成逻辑务必在客户的服务器侧完成,以免 `AppSecret` 泄露。 + +动态 Token 临时有效,有效期由你自行设置,建议不要太长。 + +你可以按照如下步骤生成动态用户 token: + +1. 在环信即时通讯控制台 创建应用,生成 `AppKey`、`Client ID` 和 `ClientSecret`。 + +2. 基于 `AppKey、AppSecret` 和 `userId`(即注册用户时传入的 `username`),参考如下示例生成 token。 + +``` +a. 获取当前时间戳,单位为秒。 + CurTime = 1686207557 +b. 设置过期时间,单位为秒。 + ttl = 600 +c. 生成 signature,将 clientId、appkey、userId、curTime、ttl、clientSecret 六个字段拼成一个字符串,进行 sha1 编码并将编码内容得到的字节转换为十六进制字符串。 + str = clientId + appkey + userId + curTime + ttl + clientSecret + shaBytes = sha1(str) + signature = fmt.Sprintf("%x", shaBytes) +d. 组装为 json。 + json = {"signature": "xx", "appkey":"xx#xx", "userId":"xx", "curTime":1686207557, "ttl": 600} +e. 将 token 类型 "dt-" 放到 json 转成的字符串前,生成最终的字符串。 + str = "dt-" + jsonStr +f. 进行 base64 编码,生成最终的 token。 + token = base64.urlEncode.encode(str) +``` + +3. 使用上述方法生成 Token 后,客户端 SDK 将该 Token 填入并登录,服务器校验成功后即登录成功。 + diff --git a/docs/document/v1/privatization/faq_integration_issues.md b/docs/document/v1/privatization/faq_integration_issues.md new file mode 100644 index 000000000..f7544a9a3 --- /dev/null +++ b/docs/document/v1/privatization/faq_integration_issues.md @@ -0,0 +1,53 @@ +# 集成类问题 + + + +## 如何实现跨 app 聊天 + +如果您需要两个 app 之间可以互相通信,只要将 AppKey 写成同一个就可以实现跨 app 聊天。同时,您需要在环信即时通讯云控制台上传对应 app 的推送证书(可以是多个),这样可以确保您的两个 app 都能收到推送。 + +## 获取设备本地日志文件 + +在排查移动端集成或者使用问题的时候,会遇到需要查看设备本地 SDK 的 log 来确认问题,在此提供移动端获取本地 log 的方法。 + +### Android + +#### 通过 API 获取 + +SDK 的 log 文件在 app 的安装目录中,可以通过 API 获取,获取时需要确保 SDK 已经完成初始化。 + +通过 API 获取 log 文件路径, 返回格式为 `xxxxx/xxxx/log.gz` + +```java +logPath = EMClient.getInstance().compressLogs(); +``` + +#### 从手机或者模拟器获取日志文件 + +前提条件 + +- 确保电脑上安装了 adb 工具,可以参考 [SDK Platform Tools](https://developer.android.com/studio/releases/platform-tools) +- 手机连接到电脑,adb 的使用可以参考:[Android Debug Bridge]( https://developer.android.com/studio/command-line/adb) + +```shell +adb pull /sdcard/android/data/(your_package_name)/(appkey)/core_log/easemob.log +``` + +### iOS + +#### 通过 API 获取 + +SDK 的 Log 文件在 app 的 sandbox 中,如需获取可通过 SDK 提供的`getLogFilesPath:` 获取,获取时需要确保SDK已经完成初始化。 + +``` +EMError *error = nil; +NSString *logPath = [EMClient.sharedClient getLogFilesPath:&error]; +``` + +返回格式为 `xxxxx/xxxx/log.gz`。 `error` 为错误信息,无错误是返回`nil`。 + +#### 从手机或者模拟器获取日志文件 + +通过 XCode debug 时,可以连接手机或者模拟器,找到应用的 sandbox 目录,然后提取日志文件。 + +App_Sandbox_path/Application Support/HyphenateSDK/easemobLog \ No newline at end of file diff --git a/docs/document/v1/privatization/faq_quality_issues.md b/docs/document/v1/privatization/faq_quality_issues.md new file mode 100644 index 000000000..dd0fe35f8 --- /dev/null +++ b/docs/document/v1/privatization/faq_quality_issues.md @@ -0,0 +1,90 @@ +# 质量类问题 + + + +## 如何排查 环信即时通讯 IM 单聊消息丢失 + +### 问题描述 + +在使用 环信即时通讯 IM 聊天的过程中,如果遇到用户 A 给用户 B 发消息,用户 B 没有接收到的情况(视为消息丢失),可以按照下面的说明进行排查。 + +### 问题原因 + +可能是以下原因: + +- 用户 A 消息发送失败; +- 接受消息的用户 ID 错误; +- 用户 B 把 A 设为黑名单了; +- 用户 B 在其他设备上登录时接收了消息; +- 用户 B 离线消息数量超过 500 条等。 + +### 排查方案 + +#### 在使用环信即时通讯 IM SDK 集成阶段测试用户出现消息丢失 + +分为用户 B 在线和不在线两种情况: + +- 用户 B 在线的情况下收不到用户 A 发的消息: + 1. 检查用户 A 发送的消息是否成功,可以根据 SDK 发消息方法返回的结果判断消息是否发送成功,如果发送失败,则用户 B 收不到消息。 + 2. 检查用户 A 给用户 B 发消息时,B 的 ID 是否正确,如果传的不是用户 B 的 环信即时通讯 IM ID,那么用户 B 收不到消息。 + 3. 检查用户 B 是否将用户 A 加入黑名单 ,如果用户 B 将用户 A 加入黑名单,那么用户 B 将收不到用户 A 发的消息,详见 [获取黑名单](/document/v1/server-side/user_relationship.html#获取黑名单列表)。 +- 用户 B 不在线时,用户 A 给用户 B 发消息,用户 B 重新登录后收不到消息: + 1. 可能存在用户 B 有在其他设备上登录的情况,把消息接收走了,所以在当前设备登录时将不再接收消息。 + 2. 确认用户 B 的离线数量是不是很大,如果超过 500 条,那么用户 B 只会收到最新的 500 条消息,超过500条的那部分消息将接收不到。 + + + +## 排查环信即时通讯 IM 群聊消息丢失 + +### 问题描述 + +用户有时反馈环信即时通讯 IM 丢消息,在用户 A 与用户 B 在同一个群组,用户 A 向群组中发消息这种情况下,我们建议先按以下步骤自查。如果没发现问题,可以提交工单由技术支持同事协助排查。 + +### 问题原因 + +可能的原因包括用户 A 构建消息时传的消息类型不是群聊类型、用户 A 消息发送失败、用户 B 不在群组中、用户 B 屏蔽了该群组消息、用户 B 被加入了群组黑名单、用户 B 在其他设备上登录时接收了消息以及用户 B 群组离线消息数量超过 200 条等。 + +### 排查方案 + +#### 一、App 未上线时,使用环信即时通讯 IM SDK 集成阶段测试用户出现消息丢失 + +- 用户 B 在线的情况下收不到用户 A 发的群组消息: + 1. 检查用户 A 在构建消息时,传的消息类型是不是群聊类型的,如果不是则用户 B 收不到用户 A 发的群组消息,详见 [Android 版构建消息](/document/v1/android/message_send_receive.html#发送文本消息) 或 [iOS 版构建消息](/document/v1/ios/message_send_receive.html#发送文本消息)。 + 2. 检查用户 A 发送的消息是否成功,可以根据 SDK 发消息方法返回的结果判断消息是否发送成功,如果发送失败,则用户 B 收不到用户 A 发送的群组消息。 + 3. 检查用户 A 给用户 B 发消息时,传的群组 ID 是否正确(是否为 A 与 B 共同加入的群组 ID),如果传的不是正确的群组 ID,那么用户 B 收不到消息用户 A 发的群组消息。 + 4. 检查用户 B 是否在群组中,可以获取群组详情,看群组中是否有用户 B,详见 [获取群组详情](/document/v1/server-side/group.html#获取群组详情)。 + 5. 检查用户 B 是否屏蔽了该群组消息,如果用户 B 屏蔽了该群组消息,那么将收不到用户 A 发的群组消息,详见 [Android 屏蔽和解除群消息](/document/v1/android/group_manage.html#屏蔽和解除屏蔽群消息) 或 [iOS 屏蔽和解除群消息](/document/v1/ios/group_manage.html#屏蔽和解除屏蔽群消息)。 + 6. 检查用户 B 是否被加入了群组黑名单,如果用户 B 被加入到了群组黑名单,那么将收不到用户 A 发的群组消息,详见 [获取群组黑名单](/document/v1/server-side/group.html#查询群组黑名单)。 +- 用户 B 不在线时,用户 A 向群组中发送消息,用户 B 重新登录后收不到群组消息: + 1. 可能存在用户 B 在其他设备上登录把消息接收走了的情况,则在当前设备登录时将不再接收消息。 + 2. 确认用户 B 所在的群组的离线数量是不是很大,如果超过200条,那么用户 B 只会收到最新的 200 条群组消息,超过 200 条的那部分群组消息将接收不到。 + +#### 二、App 已经上线后,线上用户出现群组消息丢失 + +1.先与 App 的用户确认是否存在以下情况: +- “用户 B 在线的情况下收不到用户 A 发的群组消息”的 3、4 和 5 的情况 +- “用户 B 不在线时,用户 A 向群组中发送消息,用户 B 重新登录后收不到群组消息”的 1 和 2 的情况。 + +2.若排除以上情况,可根据 App Key、发送者 ID 或消息 ID、消息发送时间在 环信即时通讯云控制台自行查询消息投递状态,具体操作如下: + +1. 登录环信即时通讯云控制台。 +2. 在首页的 应用列表 区域中,点击具体应用的 **操作** 栏中的 **管理**。 +3. 在界面左侧导航栏中选择**实时查询** > **IM消息投递查询**。 + +![img](@static/images/privitization/faq-msgdeliveryquery.jpg) + +## 参考 + +### 如何判断用户是否在线 + +在使用环信即时通讯 IM 基础聊天业务的场景下,处理特定业务需求时需知晓某些用户是否在线。为此,环信即时通讯 IM 提供单个用户以及批量用户是否在线状态的查询,详见 [用户在线状态回调](/document/v1/server-side/user_status_callback.html)。 + +除此之外,可以在 环信即时通讯云控制台 上查询用户连接状态,具体操作如下: + +1. 登录环信即时通讯云控制台。 +2. 在首页的 **应用列表** 区域中,点击具体应用的 **操作** 栏中的 **管理**。 +3. 在界面左侧导航栏中选择 **实时查询** > **IM用户连接状态**。 + +![img](@static/images/privitization/faq-userconnectionstatus.jpg) + +说明: 环信即时通讯 IM SDK 未提供直接查询用户是否在线的方法,客户端可以封装查询用户是否在线的接口调用或者让自己服务器端来调用再与自己客户端交互。 \ No newline at end of file diff --git a/docs/document/v1/privatization/uc_configure.md b/docs/document/v1/privatization/uc_configure.md index 94eefb7bf..6aea17690 100644 --- a/docs/document/v1/privatization/uc_configure.md +++ b/docs/document/v1/privatization/uc_configure.md @@ -1,4 +1,4 @@ -# 开通配置环信即时通讯 IM 服务 +# Console服务开通与配置 @@ -94,7 +94,7 @@ ![img](@static/images/privitization/deploy_push_callback.png) -3. 点击 **添加回调地址** 按钮,打开回调配置对话框,在回调配置对话框中,填写回调相关配置信息,点击 **保存** 按钮,完成回调配置,具体配置内容说明见 [回调配置](/document/server-side/callback.html#实现步骤)。 +3. 点击 **添加回调地址** 按钮,打开回调配置对话框,在回调配置对话框中,填写回调相关配置信息,点击 **保存** 按钮,完成回调配置,具体配置内容说明见 [回调配置](/document/v1/server-side/callback.html#实现步骤)。 ![img](@static/images/privitization/deploy_push_window.png) @@ -132,3 +132,15 @@ ![img](@static/images/privitization/deploy_ip_allow_list.png) 3. 单击 **确认**,则删除该 IP 地址。 + +### 用户管理 + +console后台支持管理用户,包括:用户注册、用户删除、修改用户信息、查看用户好友、查看用户黑名单、重置密码、发送REST消息、封禁、强制下线等操作. + +1. 在环信即时通讯云的左侧导航栏中,选择 **运营服务** > **用户管理**。 + +2. 单击 **创建IM用户** 按钮,注册新用户。 + +3. 在 **用户名单** 列表中,单击操作列的 **更多** 执行更多操作。 + +![img](@static/images/privitization/deploy_user_manage.png) diff --git a/docs/document/v1/privatization/uc_deploy.md b/docs/document/v1/privatization/uc_deploy.md index 636cc6b5c..bb3152936 100644 --- a/docs/document/v1/privatization/uc_deploy.md +++ b/docs/document/v1/privatization/uc_deploy.md @@ -1,4 +1,4 @@ -# 私有化部署流程说明 +# 私有化服务部署 @@ -58,7 +58,7 @@ ## 3、集成测试 -当服务端验证完成后,可通过下载需要的客户端 SDK 及 Demo 进行集成体验。环信客户端 SDK 已对 IM 核心服务完成封装, 通过调用 SDK API 接口,即可快速获得消息收发 、会话管理 、群组 、好友 、聊天室等功能。目前客户端 SDK 已覆盖 Windows 、Linux 、MacOS 、Android 、iOS 、Web 、小程序等多种平台,服务器端 SDK 已覆盖 Java 、PHP 等平台,[下载私有化客户端 SDK](http://docs-im-beta.easemob.com/private/im/uc_private.html#私有化-sdk-下载)。 +当服务端验证完成后,可通过下载需要的客户端 SDK 及 Demo 进行集成体验。环信客户端 SDK 已对 IM 核心服务完成封装, 通过调用 SDK API 接口,即可快速获得消息收发 、会话管理 、群组 、好友 、聊天室等功能。目前客户端 SDK 已覆盖 Windows 、Linux 、MacOS 、Android 、iOS 、Web 、小程序等多种平台,服务器端 SDK 已覆盖 Java 、PHP 等平台,[下载私有化客户端 SDK](uc_private.html#私有化-sdk-下载)。 示例一:以 Android 端 demo 体验为例 @@ -96,13 +96,7 @@ ![img](@static/images/privitization/deploy_wechat_code.png) -2. 提交工单 - -登录[环信通讯云管理后台](https://console.easemob.com/user/login),点击“服务支持-工单支持”,点击“进入工单系统” - -![img](@static/images/privitization/deploy_ticket.png) - -3. Geek 社区 +2. Geek 社区 [Geek 开发者社区](http://www.imgeek.org/)里面的环信专区/环信技术交流板块提供了很多常见问题的讨论和解答,您也可以发帖提问,我们的技术和服务人员会尽力解答您的疑问! diff --git a/docs/document/v1/privatization/uc_glossary.md b/docs/document/v1/privatization/uc_glossary.md new file mode 100644 index 000000000..0dbac52bd --- /dev/null +++ b/docs/document/v1/privatization/uc_glossary.md @@ -0,0 +1,205 @@ +# 术语表 + + + +## 环信即时通讯 IM SDK + +环信即时通讯 IM SDK 是环信提供的用于实现即时通讯,比如:单聊、群聊、聊天室的 SDK。 + +### 环信即时通讯 IMKit + +IMKit 是环信即时通讯 IM SDK 的一个开源 UI 组件,提供应用内聊天的常用页面和 UI 组件,帮助开发者快速构建应用的 UI。 + + + +### 环信通讯云控制台(Easemob Console) + +[环信通讯云控制台](uc_configure.md)是环信提供给开发者管理环信各项服务的工具。 + +## Demo + +环信即时通讯 IM 示例开源项目,目前支持 Android、iOS 和 Web 平台。 + +## 会话和消息 + +### 会话 + +会话是一个单聊、群聊、聊天室或者子区所有消息的集合。用户需在会话中发送消息或查看历史消息或清空历史消息等操作。 + +### 会话列表 + +会话列表是指会话依照一定顺序排列的列表,会话的排列顺序依赖于会话中最近一条消息的接收时间等因素。 + +### 广播消息 + +广播消息是指通过 RESTful API 对应用内的所有用户发送消息。当用户离线时,消息会自动转换为系统离线推送。 + +### 离线消息 + +当接收方不在线时,环信即时通讯 IM 服务器会暂时保存消息,用户上线时,会接收到服务器保存的离线消息。私有部署即时通讯服务离线消息保存时长可支持自定义。单聊和群聊支持离线消息,聊天室不支持离线消息。 + +### 历史消息 + +环信即时通讯 IM 服务器会保存历史消息以供查询。开发者可以通过 RESTful API 下载历史消息压缩包文件。 + +### 漫游消息 + +多端登录时,用户在其中一端发送的消息会同步到所有其他客户端,此类消息称为漫游消息。 + +### 文本消息 + +消息内容是普通文本,其中可以包括超链接,客户端收到消息后存入数据库、计入未读消息数。表情消息为开发者自定义。实质上是发文本消息。接收方收到文本消息后,首先查询文本消息是否是表情消息,如果是,则显示该文本消息为对应的表情图片。 + +### 图片消息 + +图片消息内容属于附件类型消息,内容图片 URL 地址、尺寸、图片大小等信息。最大支持 10 MB。 + +### 位置消息 + +消息内容为地理位置标题、经度和纬度信息。 + +### 语音消息 + +语音数据属于附件类型,需要提供时长信息,以秒为单位。最大支持 10 MB。 + +### 视频消息 + +消息内容为视频文件的 URL 地址、时长、大小、格式等信息,默认支持 10 MB。 + +### 文件消息 + +消息内容为文件的 URL 地址、大小、格式等信息,格式不限,默认支持 10 MB。 + +### 透传消息 + +透传消息可视为一条指令,通过发送这条指令给对方,通知对方要执行的操作,对方收到消息可自定义处理。透传消息不会存入本地数据库中,在 UI 上不显示,也不计入未读消息。具体功能可以根据自身业务需求自定义,例如实现头像或昵称的更新等。 + +### 消息自定义扩展 + +当基础的消息类型不满足需求时,可以使用消息自定义扩展增强基础消息类型,例如消息中需要携带被回复的消息内容等场景。 + +使用扩展后,消息大小不能超过原类型消息的大小。消息自定义扩展作为消息内容会存入本地数据库。 + +### 自定义消息 + +发者自定义的消息类型,例如红包消息、石头剪刀布等形式的消息。 + +### 消息回调 + +消息回调,即聊天服务器会在事件发生之前或之后,向客户的应用服务器发送请求,应用服务器可据此进行必要的数据同步,或者根据业务需求干预事件的后续处理流程。 + +### 消息云存储 + +将用户发送的单聊、群聊、聊天室消息存储到聊天服务器,方便用户在更换设备或删除本地消息后,通过服务端获取历史消息。私有部署即时通讯服务消息存储时间可支持自定义。 + +## 用户相关 + +### 用户 ID + +用户 ID 即用户名,是 App Key 内用户的唯一标识,不同于即时通讯系统服务器为用户创建的 UUID。 + +### UUID + +即时通讯服务器为 App Key 内用户创建的唯一 ID,不同于用户 ID。 + +### 用户属性 + +用户属性指用户的信息,如用户昵称、头像、邮箱、电话、性别、签名、生日等。例如,在招聘场景下,利用用户属性功能,可以存储性别、邮箱、用户类型(面试者)、职位类型(Web 研发)等。当查看用户信息时,可以直接查询服务器存储的用户属性信息。 + +### 离线 + +离线是指用户成功登出环信即时通讯 IM 系统或与即时通讯 IM 系统断开连接后的状态。用户登出即时通讯 IM 系统之后,无法发送和接受消息,在下次登录后可以接收到离线消息。 + +## 封禁用户 + +禁止用户使用即时通讯 IM 服务。封禁后,用户无法连接即时通讯 IM 服务器。 + +### 用户黑名单 + +用户将不会接收黑名单中用户发送的消息。 + +## 单聊 + +单聊即一对一聊天,支持全类型消息。参与聊天的双方可以是好友也可以是陌生人。 + +## 群组 + +群组是支持多人沟通的即时通讯系统,成员关系相对稳定。所有群成员可在群中收发送消息。当群成员离线时,可以收到推送消息。群组分为公开群和私有群,公开群可以被搜索到,非群成员可以加入;私有群不能被搜索到,需要群主或群管理员添加用户进入。群组成员支持多种角色:群主、群管理员、群成员。群组提供丰富的管理能力,例如,群组禁言、黑名单和白名单等。 + +### 群主 + +群主即群组的创建者,在群中拥有最高权限,可以指定管理员、解散群组、更改群组信息以及对群组成员进行管理。 + +群主也可以将群主权限转移给群组其他成员。 + +### 群管理员 + +由群主授权,协助进行管理,拥有一定管理权限。可以对群组成员进行管理。 + +### 群成员 + +群组的普通成员,可以收发消息和查看群组描述信息,不具备群组管理权限。 + +### 群组黑名单 + +群主和管理员可以将群组成员加入黑名单,加入群黑名单的用户不能在群中发送消息。 + +### 群组白名单 + +群主和管理员可以将群组成员加入白名单。群组开启全局禁言时,只有白名单中的用户可以在群组中发送消息。 + +## 聊天室 + +聊天室是支持多人加入的组织。聊天室中的成员没有固定关系,用户离线后,超过 2 分钟会自动退出聊天室。聊天室成员在离线后,不会收到推送消息。聊天室可以应用于直播、消息广播等。 + +### 聊天室黑名单 + +聊天室创建者和管理员可以将聊天室成员加入黑名单,被加入聊天室黑名单的用户不能在聊天室中发送消息。 + +### 聊天室白名单 + +聊天室创建者和管理员可以将聊天室成员加入白名单,聊天室开启全局禁言时,只有白名单中的用户可以在聊天室中发送消息。 + +### 聊天室创建者 + +聊天室的创建者,在聊天室中拥有最高权限。可以指定管理员、解散聊天室、更改聊天室信息、对聊天室成员进行管理。 + +### 聊天室管理员 + +由聊天室所有者授权,协助进行管理,拥有一定管理权限。可以对聊天室成员进行管理。 + +### 聊天室成员 + +聊天室的普通成员,不具备聊天室管理权限。 + +## RESTful 接口 + +环信即时通讯 IM 的服务器端接口都是通过 RESTful 服务方式提供的,RESTful API 基于最简单的 HTTP 协议,在各个编程语言中都提供了良好的支持。 + +环信即时通讯 IM RESTful 平台提供一个多租户用户体系,以集合(Collection)的形式的形式管理资源,一个集合包括数据库、企业、应用、用户、群组、消息和文件等。 + +## 离线推送 + +离线推送是指当应用被杀死时,通过厂商推送接收消息。iOS 设备使用苹果推送通知服务(APNs),Android 设备为谷歌云消息传递服务(FCM)、华为推送、小米推送、魅族推送、OPPO 推送和 vivo 推送。 + + \ No newline at end of file diff --git a/docs/document/v1/privatization/uc_introduction.md b/docs/document/v1/privatization/uc_introduction.md new file mode 100644 index 000000000..3e3378990 --- /dev/null +++ b/docs/document/v1/privatization/uc_introduction.md @@ -0,0 +1,127 @@ +# 产品概述 + + + +环信即时通讯私有化服务是基于 IM 核心技术实现的可私有化部署解决方案。本方案可适配内网物理服务器集群、公有云以及私有云等任意部署环境,提供功能完备、安全可靠、易于扩展的即时通讯平台。整体通讯平台架构主要由三部分组成,分别为客户端、服务端、Web 控制台。 + +- **客户端**:采用 SDK 形式,对核心通信模块进行封装,提供场景功能接口,覆盖多种平台(包括:Android、iOS、Web、小程序、 Windows/Mac OS、Linux),支持快速集成终端用户应用。 +- **服务端**:采用 Java 和 Erlang 语言编写,可支持用户高并发连接和系统动态调配,高效处理用户长连接相关的服务和用户管理、推送等无状态服务。同时提供服务端 REST API 和 Java Server SDK 接口,便于完成即时通讯软件中服务的控制、数据的转发存储工作。 +- **Web 控制台**:是基于 B/S 模式的可视化操作平台,可支持开通与配置应用功能,查询各类 IM 服务情况,管理与维护用户体系(增、删、改、查),满足系统管理员、开发者等多种业务角色使用需求,提升业务集成与运营管理效率。 + + +## 平台架构 + +![环信 IM 后台](@static/images/privitization/framework.jpg?w=50) + + +## 集成概述 + +当私有化服务部署后,开发者主要需要了解服务器端集成和客户端集成内容。 + +![img](@static/images/product/integration-overview.png) + +服务端集成请看:[环信即时通讯 REST API 概览](/document/v1/server-side/overview.html)。 + + +客户端集成请查看相应的环信 SDK 开发文档: + +[环信即时通讯 IM Android 快速开始](/document/v1/android/quickstart.html); + +[环信即时通讯 IM iOS 快速开始](/document/v1/ios/quickstart.html); + +[环信即时通讯 IM Web 快速开始](/document/v1/web/quickstart.html)。 + +## 功能概述 + +用环信即时通讯能实现以下功能: + +### 单聊 + +环信单聊,支持丰富的消息类型,以及离线消息、漫游消息等功能。 + +### 群聊 + +环信群聊,支持丰富的消息类型,支持完整的群组管理能力,包含发布群公告、设置群角色等。 + +### 用户管理 + +提供用户体系管理能力,如:好友管理、黑名单管理等。支持用户资料存储,包括:头像、昵称、自定义用户信息等。 + +### 丰富的消息类型 + +支持单聊/群聊中,发送文本、表情、图片、语音、视频、地理位置、文件,以及红包和礼物等的自定义消息。 + +### 第三方消息推送 + +消息推送指当应用在后台运行,或进程被杀时,用户处于离线状态,新消息在发送至环信服务器后,会被转发至第三方推送服务器进行推送,以确保该消息依然可以送达客户端。推送消息在安卓端是使用 Firebase Cloud Message(FCM) 实现,在 iOS 端使用 Apple Push Notification service(APNs) 实现。 + +### 多端消息同步 + +环信支持一个账号同时登录多台设备,可实现终端用户的消息通过服务器保存和同步,保证各端均能收发消息同步。 + +### 消息撤回 + +消息发出后可以进行消息撤回,提供 SDK 和 REST API 端两种撤回方式。 + +## 适用场景 + +环信适用于端到端实时消息沟通的场景: + +- 应用内聊天(如:陌生人社交、相亲等) + - 支持丰富的消息类型、好友关系管理 + - 支持群管理能力、群公告设置、群角色设置等 +- 应用内通知 + - 支持广播消息、自定义通知消息等 + - 支持用户管理,包括储存用户信息、用户封禁等 +- 视频/语音直播 + - 支持聊天室管理能力 + - 支持丰富类型的聊天室消息,包括弹幕、红包、礼物等 +- 企业协作 + - 支持用户管理,设置企业组织架构、好友关系管理 + - 支持群管理能力、群公告设置、群附件发送、群角色设置等 +- 买家卖家沟通 + - 支持订单通知、问候语设置、自定义消息发送 + - 支持卖家内部管理、公告设置、成员管理等 +- 线上问诊 + - 支持丰富的消息类型,图文病情描述、语音消息等 + - 支持用户信息存储、用户身份管理等 + +## 产品优势 + +环信主要有以下优势: + +### 部署多样化 + +环信即时通讯系统支持 Linux 裸系统、容器化等多种部署方式。不仅可以提供更灵活、更便捷、更稳定的平台性能,同时容器化部署可实现自动部署,具备服务自动发现、服务自动负载均衡等特点。 + +### 高可用 + +环信即时通讯系统具备高可用特性,当系统内某一个节点或主机出现宕机后,该故障节点上的所有服务会自动转移到其他节点上而不会引发服务中断,保障系统可用性。 + +### 易扩展 + +环信即时通讯系统服务架构支持弹性扩展,系统内所有资源可在各节点之间实现灵活调度,当 CPU、内存等计算资源利用率较高时,可通过横向添加 node 实现平滑扩容。 + +### 安全性 + +环信即时通讯系统实现通讯全流程安全加密,支持客户端敏感信息加密存储、服务器密钥权限管理、消息传输过程私有协议加密以及用户信息隐私保护等措施。 + +### 国产化 + +环信即时通讯系统严格遵循国家法律法规和技术标准规范,积极响应国内自主可控、安全可控要求,从 IT 基础设置、操作系统、数据库等方面进行国产化升级,满足信创环境部署要求。 + +### 多平台 + +环信即时通讯 IM 支持 Android、iOS、Web 等平台,而且各平台之间可互通。下表为即时通讯支持的各平台版本: + +| 平台 | 支持的版本 | +| ------------ | ------------------------------------------------------------ | +| Android | Android 5.0 或以上版本(API 级别 21 或以上) | +| iOS | iOS 10.0 或以上版本 | +| Web |
- Internet Explorer 9 或以上
- FireFox 10 或以上
- Chrome 54 或以上 Safari 6 或以上
- Edge 12 或以上
- Opera 58 或以上
- iOS Safari 7 或以上
- Android Browser 4.4 (KitKat) 或以上 | diff --git a/docs/document/v1/privatization/uc_limitation.md b/docs/document/v1/privatization/uc_limitation.md new file mode 100644 index 000000000..e09779593 --- /dev/null +++ b/docs/document/v1/privatization/uc_limitation.md @@ -0,0 +1,88 @@ +# 限制条件 + + + +本文简要介绍环信即时通讯 IM 的使用限制条件,包括调用频率、字符串大小和编码格式等。 + +## 用户注册 + +- 用户 ID:长度不能超过 64 字节,支持以下字符集: + - 26 个小写英文字母 a-z; + - 26 个大写英文字母 A-Z; + - 10 个数字 0-9; + - “_”, “-”, “.”。 + +:::notice +- 该参数不区分大小写,因此 Aa 和 aa 为相同用户名; +- 请确保同一个 app 下,用户 ID 唯一; +- 用户 ID 是会公开的信息,请勿使用 UUID、邮箱地址、手机号等敏感信息。 +::: +- 批量注册每次最多 60 个用户 ID。 + +## 好友数限制 + +私有部署用户好友数无上限 + +## 消息存储时长限制 + +私有部署消息存储时长支持自定义,默认配置14天,可在部署前约定存储时间: + +## 群组限制 + +私有部署群组有如下限制: + +- 群组总数上限:100,000 个 +- 群成员数:2000人/群,可支持调整至8000人/群 +- 用户可加入群组数:无限制 + + +群组属性和群成员属性的限制如下: +- 群组名称,字符串类型,最大长度为 128 字符。 +- 群组描述,字符串类型,最大长度为 512 字符。 +- 群组扩展信息,例如可以给群组添加业务相关的标记,最大长度为 1,024 字符。 +- 单个群成员的自定义属性(key-value)总长度不能超过 4 KB。对于单个自定义属性,属性 key 不能超过 16 字节,value 不能超过 512 个字节。 + +## 聊天室限制 + +私有部署聊天室有如下限制: +- 聊天室总数:无限制。 +- 聊天室名称,用户自定义,字符串类型,最大长度为 128 字符。 +- 聊天室描述,用户自定义,字符串类型,最大长度为 512 字符。 + +### 聊天室自定义属性(key-value) + +每个聊天室最多可有 100 个自定义属性,每个应用的聊天室自定义属性总大小不超过 10 GB。 + +聊天室自定义属性为键值对(key-value)结构,单个 key 不能超过 128 个字符,支持以下字符集: +- 26 个小写英文字母 a-z; +- 26 个大写英文字母 A-Z; +- 10 个数字 0-9; +- “_”, “-”, “.”。 + +每个聊天室属性 value 不能超过 4096 个字符。 + +## 调用频率限制 + +私有部署Rest API 调用频率支持设置无限制。 + +## 消息大小限制 + +对于不同的消息类型,消息长度限制如下: + +| 消息类型 | 消息长度限制 | +| :------------- | :----------------------------------- | +| 文本消息 | 3 KB | +| 图片消息 | 图片不能超过 10 MB,图片消息大小限制为 3 KB。 | +| 语音消息 | 音频文件不能超过 10 MB,语音消息大小限制为 3 KB。 | +| 视频消息 | 视频文件不能超过 10 MB,视频消息大小限制为 3 KB。 | +| 文件消息 | 附件大小不能超过 10 MB,文件消息大小限制为 3 KB。 | +| 透传消息 | 3 KB | +| 自定义消息 | 3 KB | + +## 用户属性大小限制 + +默认单一用户的属性总长不得超过 2 KB。默认一个 app 下所有用户的属性总长度不得超过 10 GB。 + +## 消息撤回 + +默认撤回时限为 2 分钟,可根据 App Key 在环信即时通讯云管理后台单独设置。 diff --git a/docs/document/v1/privatization/uc_private.md b/docs/document/v1/privatization/uc_private.md index 468bb6df4..5d5cbe6bc 100644 --- a/docs/document/v1/privatization/uc_private.md +++ b/docs/document/v1/privatization/uc_private.md @@ -1,46 +1,14 @@ -# 私有化即时通讯 +# 私有化 SDK 下载 - -[下载私有化 SDK >>](#私有化-sdk-下载)。 -环信即时通讯私有化服务是基于 IM 核心技术实现的可私有化部署解决方案。本方案可适配内网物理服务器集群、公有云以及私有云等任意部署环境,提供功能完备、安全可靠、易于扩展的即时通讯平台。整体通讯平台架构主要由三部分组成,分别为客户端、服务端、Web 控制台。 - -- **客户端**:采用 SDK 形式,对核心通信模块进行封装,提供场景功能接口,覆盖多种平台(包括:Android、iOS、Web、小程序、 Windows/Mac OS、Linux),支持快速集成终端用户应用。 -- **服务端**:采用 Java 和 Erlang 语言编写,可支持用户高并发连接和系统动态调配,高效处理用户长连接相关的服务和用户管理、推送等无状态服务。同时提供服务端 REST API 和 Java Server SDK 接口,便于完成即时通讯软件中服务的控制、数据的转发存储工作。 -- **Web 控制台**:是基于 B/S 模式的可视化操作平台,可支持开通与配置应用功能,查询各类 IM 服务情况,管理与维护用户体系(增、删、改、查),满足系统管理员、开发者等多种业务角色使用需求,提升业务集成与运营管理效率。 - -## 私有化服务优势 - -### 部署多样化 - -环信即时通讯系统支持 Linux 裸系统、容器化等多种部署方式。不仅可以提供更灵活、更便捷、更稳定的平台性能,同时容器化部署可实现自动部署,具备服务自动发现、服务自动负载均衡等特点。 - -### 高可用 - -环信即时通讯系统具备高可用特性,当系统内某一个节点或主机出现宕机后,该故障节点上的所有服务会自动转移到其他节点上而不会引发服务中断,保障系统可用性。 - -### 易扩展 - -环信即时通讯系统服务架构支持弹性扩展,系统内所有资源可在各节点之间实现灵活调度,当 CPU、内存等计算资源利用率较高时,可通过横向添加 node 实现平滑扩容。 - -### 安全性 - -环信即时通讯系统实现通讯全流程安全加密,支持客户端敏感信息加密存储、服务器密钥权限管理、消息传输过程私有协议加密以及用户信息隐私保护等措施。 - -### 国产化 - -环信即时通讯系统严格遵循国家法律法规和技术标准规范,积极响应国内自主可控、安全可控要求,从 IT 基础设置、操作系统、数据库等方面进行国产化升级,满足信创环境部署要求。 - -## 私有化 SDK 下载 环信客户端及服务端 SDK 已对 IM 核心服务完成封装,通过调用 SDK API 接口,即可快速获得消息收发、会话管理、群组、好友、聊天室等功能,目前客户端 SDK 已覆盖 Windows、Linux、MacOS、Android、iOS、Web、小程序等多种平台,服务器端 SDK 已覆盖 Java、PHP 等平台,各端 SDK 下载及开发指南如下所示。 :::tip -1. 若要体验环信即时通讯 IM 的功能,可下载[公有云 Demo](https://www.easemob.com/download/demo)。 -2. 若要体验私有化 Demo,需下载下表中对应平台的 Demo,然后在登录页面的**服务器配置**区域完成配置。 -3. 若要集成,需选择下表中的 SDK 及 Demo 版本,按照下表中**开发指南**一列的文档配置私有化环境信息。 +1. 若要体验私有化 Demo,需下载下表中对应平台的 Demo,然后在登录页面的**服务器配置**区域完成配置。 +2. 若要集成,需选择下表中的 SDK 及 Demo 版本,按照下表中**开发指南**一列的文档配置私有化环境信息。 :::
单端/多端登录
@@ -73,41 +41,41 @@

Android

@@ -129,13 +97,13 @@

Windows(C#)

@@ -149,7 +117,7 @@

下载 SDK

@@ -163,7 +131,7 @@

下载 SDK

@@ -171,13 +139,13 @@

uni-app

@@ -185,13 +153,13 @@

小程序

@@ -199,25 +167,27 @@

Unity

+ - @@ -229,13 +199,13 @@

Java

@@ -249,7 +219,7 @@

下载 SDK

diff --git a/docs/document/v1/server-side/account_system.md b/docs/document/v1/server-side/account_system.md index 575c1979e..4118b54fc 100644 --- a/docs/document/v1/server-side/account_system.md +++ b/docs/document/v1/server-side/account_system.md @@ -12,9 +12,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :------------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | ### 响应参数 @@ -43,7 +43,7 @@ - 已在环信即时通讯云控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 - 已从服务端获取 app token,详见 [使用 App Token 鉴权](easemob_app_token.html)。 -- 了解环信 IM API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 认证方式 @@ -57,7 +57,7 @@ ### 开放注册单个用户 -开放注册指用户可以在登录客户端 SDK 后自行通过账号密码注册账号。一般在体验 Demo 和测试开发环境时使用,使用前需先在[环信即时通讯云控制后台](https://console.easemob.com/user/login)打开相应应用的开放注册开关,即在控制台首页的 **应用列表** 下点击目标应用的 **操作** 一栏中的 **查看**,然后选择 **即时通讯** > **服务概览**,在页面的 **设置** 区域中将 **用户注册模式** 设置为 **开放注册**。 +开放注册指用户可以在登录客户端 SDK 后自行通过账号密码注册账号。一般在体验 Demo 和测试开发环境时使用,使用前需先在环信即时通讯云控制后台打开相应应用的开放注册开关,即在控制台首页的 **应用列表** 下点击目标应用的 **操作** 一栏中的 **管理**,然后选择 **应用概览** > **应用详情**,在页面的 **应用设置** 区域中将 **用户注册模式** 设置为 **开放注册**。 #### HTTP 请求 @@ -136,7 +136,7 @@ curl -X POST -i "https://XXXX.com/XXXX-demo/XXXX/users" -d '{"username":"user1", 要使用该注册方式,你需要在环信控制台进行如下配置: -在控制台首页的 **应用列表** 下点击目标应用的 **操作** 一栏中的 **查看**,然后选择 **即时通讯** > **服务概览**,在页面的 **设置** 区域中将**用户注册模式**设置**授权注册**,然后单击**保存**。 +即在控制台首页的 **应用列表** 下点击目标应用的 **操作** 一栏中的 **管理**,然后选择 **应用概览** > **应用详情**,在页面的 **应用设置** 区域中将 **用户注册模式** 设置**授权注册**,然后单击**保存**。 推荐使用该模式,因为该模式较为安全,可防止已获取了注册 URL 和了解注册流程的某些人恶意向服务器大量注册垃圾用户。 @@ -222,7 +222,7 @@ curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' - "applicationName": "XXXX" } ``` - + ## 获取用户详情 ### 获取单个用户的详情 @@ -1051,8 +1051,8 @@ curl --location 'http://XXXX/XXXX/XXXX/users/XXXX/resources' \ 该功能可广泛用于实时互动 app 中,例如发现某用户频繁向多个聊天室发送违规广告,则可以对该用户开启全局聊天室禁言 15 天;发现某用户发表触犯红线的政治言论,则可以全局永久禁言,用户申诉通过后可以解禁。 -使用该功能前,你需先查看你的 IM 套餐版本是否开通了该功能。该功能与 IM 套餐包版本之间的开通关系,详见[产品计费](introduction.html#增值服务费用)。 + ### 查询单个用户 ID 全局禁言 查询单个用户的单聊、群聊和聊天室的全局禁言详情。 diff --git a/docs/document/v1/server-side/callback.md b/docs/document/v1/server-side/callback.md index 4805fa2ee..a6fd7c27a 100644 --- a/docs/document/v1/server-side/callback.md +++ b/docs/document/v1/server-side/callback.md @@ -4,7 +4,7 @@ 回调功能,即环信 IM 服务器会在事件发生之前或之后,向你的应用服务器发送请求,你可以根据业务需求来干预事件的后续处理流程(发送前回调),或据此进行必要的数据同步(发送后回调)。 -一般发送前回调是对用户发送的消息内容的处理,发送后回调还包括送达回执和已读回执、群组或聊天室操作、好友关系操作和用户状态变化等事件,具体见 [用户在线状态回调](user_status_callback.html) 和发送后回调过滤规则设置。 +一般发送前回调是对用户发送的消息内容的处理,发送后回调还包括送达回执和已读回执、群组或聊天室操作、好友关系操作和用户状态变化等事件,具体见 [用户状态回调](user_status_callback.html) 和发送后回调过滤规则设置。 设置消息内容回调的规则可以在环信即时通讯云控制台实现,如需单独设置特定类型不回调,请联系环信商务经理。 @@ -36,7 +36,7 @@ - 回调的方向是环信 IM 服务器向应用服务器发起 HTTP/HTTPS POST 请求。 - 若同时设置了消息发送前和发送后两种回调,且消息发送前回调返回拒绝,则消息发送后回调将不会被触发。 -- 对同一个 app,可以针对不同类型的消息(“TEXT”,“IMAGE”,“VIDEO”,“LOCATION”,“VOICE” 和 ”FILE”)做配置;规则支持选择两种以上消息类型同时回调至一个指定服务器地址,接收到消息后,你可以区分消息的类型以便进行分类处理(详见 [消息管理 REST API](message.html))。 +- 对同一个 app,可以针对不同类型的消息(“TEXT”,“IMAGE”,“VIDEO”,“LOCATION”,“VOICE” 和 ”FILE”)做配置;规则支持选择两种以上消息类型同时回调至一个指定服务器地址,接收到消息后,你可以区分消息的类型以便进行分类处理(详见 [消息管理 REST API](message_single.html))。 - 环信 IM 服务器执行发送前回调后,如果你的应用服务器没有返回 valid 状态或者返回其他错误码,该条消息会根据默认设置(console 后台发送前回调中 ”调用失败时默认策略”)处理,不会再重试;后续消息依然正常执行回调。 - 消息发送到你的应用服务器后,应用服务器需返回 HTTP 响应码 200 和 valid 属性,根据 valid 状态决定是否进行下发。 @@ -85,7 +85,7 @@ | `msg_id` | 消息的 ID。 | | `payload` | 消息内容,与通过 REST API 发送过来的一致,查看 [消息格式文档](message_historical.html#历史消息记录的内容)。 | | `securityVersion` | 安全校验版本,目前为 1.0.0。忽略此参数,以后会改成 Console 后台做设置。 | -| `security` | 签名,格式如下: MD5(callId+Secret+timestamp)。Secret 见 [环信即时通讯云控制台](https://console.easemob.com/user/login)回调规则。 | +| `security` | 签名,格式如下: MD5(callId+Secret+timestamp)。Secret 见 环信即时通讯云控制台 回调规则。 | #### 响应 body @@ -148,7 +148,7 @@ 以下是需要了解的发送后回调功能说明,包括在高并发可用性的基础上的使用限制说明,请按照此限制正确使用回调。 -- 消息回调属于增值服务,需要开通相应版本后才能使用,具体见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im)。 +- 开通消息回调服务。 - 消息回调规则设置成功即可正常使用。最多支持 4 个回调规则(包含发送前回调和发送后回调),如果需要再增加回调规则,需要联系商务经理开通。 - 发送后回调范围,所有上行消息有效(包含 REST 发送的消息),包含单聊/群聊;如果 app 开通了反垃圾/敏感词过滤,被识别的消息会在服务器被拦截并禁止发送,将不会回调。 - 发送后回调接收延时,是指消息服务器接收到客户端上行消息、再将消息成功回调至客户指定服务器地址的时间间隔。消息接收延时保障是 99.95% 的消息在 30s 内。 @@ -165,7 +165,7 @@ 具体如下: -1. App Key 可以配置回调规则的数据格式,可以配置多个回调规则(默认最多开通 4 个规则),开通服务后才允许用户配置,前往 [环信即时通讯云控制台](https://console.easemob.com/) 配置: +1. App Key 可以配置回调规则的数据格式,可以配置多个回调规则(默认最多开通 4 个规则),开通服务后才允许用户配置,前往 [环信即时通讯云控制台](enable_and_configure_IM.html#配置消息回调) 配置: | 参数
| 说明 | | :----------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -265,8 +265,8 @@ app 的响应内容不能超过 1,000 个字符,否则环信服务器会认为 | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | #### 请求 header @@ -339,8 +339,8 @@ curl -X GET 'https://a1.easemob.com/easemob-demo/easeim/callbacks/storage/info' | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | #### 请求 header diff --git a/docs/document/v1/server-side/callback_configurations.md b/docs/document/v1/server-side/callback_configurations.md index 927ea55c9..3d268b052 100644 --- a/docs/document/v1/server-side/callback_configurations.md +++ b/docs/document/v1/server-side/callback_configurations.md @@ -2435,7 +2435,7 @@ payload 示例: "status":"offline" } ``` - + \ No newline at end of file diff --git a/docs/document/v1/server-side/chatroom.md b/docs/document/v1/server-side/chatroom.md index 7db2119f0..0b3138af2 100644 --- a/docs/document/v1/server-side/chatroom.md +++ b/docs/document/v1/server-side/chatroom.md @@ -13,7 +13,7 @@ 要调用环信即时通讯 RESTful API,请确保满足以下要求: - 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见[接口频率限制](limitationapi.html)。 + ## 聊天室成员角色 @@ -29,9 +29,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :------------ | :----- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | | `chatroom_id` | String | 是 | 聊天室 ID。 | | `username` | String | 是 | 用户 ID。 | | `name` | String | 是 | 聊天室名称,最大长度为 128 个字符。 | @@ -518,8 +518,6 @@ GET https://{host}/{org_name}/{app_name}/chatrooms/{chatroom_id} | `data.owner` | String | 聊天室所有者的用户 ID。例如:{“owner”: “user1”}。 | | `data.created` | Long | 创建聊天室时间,Unix 时间戳,单位为毫秒。 | | `data.custom` | String | 聊天室扩展信息。 | -| `data.affiliations_count` | Int | 现有聊天室成员总数。 | -| `data.affiliations` | Array | 现有聊天室成员列表,包含聊天室所有者和成员(包括聊天室管理员)。例如:“affiliations”:[{“owner”: “user1”},{“member”:”user2”},{“member”:”user3”}]。 | | `data.public` | Bool | 预留字段,无需关注。 | 其他字段及描述详见 [公共参数](#公共参数)。 @@ -919,7 +917,7 @@ curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' - "applicationName": "testapp" } ``` - + ## 管理聊天室成员 -环信即时通讯 IM 提供多个接口实现聊天室成员管理,包括添加和移除聊天室成员、转让聊天室所有权以及聊天室黑名单、白名单和禁言列表相关操作。 +环信即时通讯 IM 提供多个接口实现聊天室成员管理,包括添加和移除聊天室成员、聊天室黑名单、白名单和禁言列表相关操作。 ### 分页获取聊天室成员列表 @@ -2701,7 +2699,7 @@ curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' - "applicationName": "testapp" } ``` - + ### 解除聊天室禁言成员 解除对一个或多个聊天室成员的禁言。你一次最多可对 60 个成员解除禁言。 @@ -2839,7 +2837,7 @@ curl -X DELETE HTTP://XXXX/XXXX/XXXX/chatrooms/12XXXX11/mute/user1 -H 'Authoriz "applicationName": "testapp" } ``` - + \ No newline at end of file diff --git a/docs/document/v1/server-side/easemob_app_token.md b/docs/document/v1/server-side/easemob_app_token.md index d517b3cb1..58f1a8d3d 100644 --- a/docs/document/v1/server-side/easemob_app_token.md +++ b/docs/document/v1/server-side/easemob_app_token.md @@ -1,6 +1,6 @@ --- { - pageUri: "/product/easemob_app_token.html", + pageUri: "/document/v1/privatization/easemob_app_token.html", title: "使用环信 App Token 鉴权" } --- \ No newline at end of file diff --git a/docs/document/v1/server-side/easemob_user_token.md b/docs/document/v1/server-side/easemob_user_token.md index cb2a72c95..abbf7887c 100644 --- a/docs/document/v1/server-side/easemob_user_token.md +++ b/docs/document/v1/server-side/easemob_user_token.md @@ -1,6 +1,6 @@ --- { - pageUri: "/product/easemob_user_token.html", + pageUri: "/document/v1/privatization/easemob_user_token.html", title: "使用环信用户 token 鉴权" } --- \ No newline at end of file diff --git a/docs/document/v1/server-side/enable_and_configure_IM.md b/docs/document/v1/server-side/enable_and_configure_IM.md index f94b58f39..6fd82457a 100644 --- a/docs/document/v1/server-side/enable_and_configure_IM.md +++ b/docs/document/v1/server-side/enable_and_configure_IM.md @@ -1,6 +1,6 @@ --- { - pageUri: "/product/enable_and_configure_IM.html", + pageUri: "/document/v1/privatization/uc_configure.html", title: "开通配置环信即时通讯 IM 服务" } --- \ No newline at end of file diff --git a/docs/document/v1/server-side/error.md b/docs/document/v1/server-side/error.md index c6e434831..99032da2d 100644 --- a/docs/document/v1/server-side/error.md +++ b/docs/document/v1/server-side/error.md @@ -53,7 +53,7 @@ | 400 | illegal_argument | “target_type can only be 'users' or 'chatgroups' or 'chatrooms'” | 发送消息时,对象类型(`target_type`)只能传入 `users`、`chatgroups` 或 `chatrooms`。若传入其他值,提示该错误。 | | 400 | illegal_argument | “username is not legal” | 注册用户时传入的 username 不合法,详见 [用户体系集成](account_system.html#注册用户) | | 400 | illegal_argument | “This chatmessage request is not supported” | 查询历史消息时传入的时间格式不正确,正确的格式为 YYYYMMDDHH。例如,要获取 2018 年 02 月 09 日 12 点到 13 点的历史消息,传入的时间为 `2018020912`。 | -| 400 | illegal_argument | “illegal arguments: appkey: easemob-demo#chatdemoui, time: 2018020918, maybe chat message history is expired or unstored” | 查询的历史消息未生成或已过期。消息的保留时间取决于产品套餐,详见[消息存储时长限制](limitation.html#消息存储时长限制)。 | +| 400 | illegal_argument | “illegal arguments: appkey: easemob-demo#chatdemoui, time: 2018020918, maybe chat message history is expired or unstored” | 查询的历史消息未生成或已过期。消息的保留时间取决于初始设置。 | | 400 | invalid_parameter | “some of [groupid] are not valid fields” | 修改的群组信息时,传入的参数不支持,例如修改 `groupid`。修改群信息目前只支持修改“群名称”、“群描述” 和 “群最大人数”。 | | 400 | required_property_not_found | “Entity user requires a property named username” | 修改用户密码请求未提供用户 ID(`username`)。 | | 400 | duplicate_unique_property_exists | “Application null Entity user requires that property named username be unique, value of hxtest1 exists” | 注册用户时,用户 ID 已存在,请更换用户 ID 重新注册。 注:如果是批量注册,若一次调用返回一个 ID 已存在,则此次调用注册的其他不存在的 ID 不会注册,需将已存在的 ID 从数组中移除重新调用注册。 | @@ -69,7 +69,7 @@ | 401 | unauthorized | “registration is not open, please contact the app admin” | 授权注册模式下,调用[注册单个用户](account_system.html#授权注册单个用户)和[批量注册用户](account_system.html#批量注册用户)的 RESTful 接口时,未传入 App Token 或传入了错误的 App Token 时提示该错误,例如 Token 已过期或格式不正确。 | | 401 | unauthorized | “Unable to authenticate due to expired access token” | 调用 RESTful 接口发送请求时使用的 App Token 过期或未传入 App Token。
该错误码针对除[注册单个用户](account_system.html#授权注册单个用户)和[批量注册用户](account_system.html#批量注册用户)之外的 RESTful 接口有效。 | | 401 | auth_bad_access_token | “Unable to authenticate due to corrupt access token” | 调用 RESTful 接口发送请求时使用的 App Token 格式错误。
该错误码针对除[注册单个用户](account_system.html#授权注册单个用户)和[批量注册用户](account_system.html#批量注册用户)之外的 RESTful 接口有效。 | -| 401 | auth_bad_access_token | “Unable to authenticate” | 调用 RESTful 接口发送请求时使用的 App Token 无效。App Token 的格式正确,但不是由接收请求的服务器生成的,导致服务器无法识别该 Token。
该错误码针对除[注册单个用户](./agora_chat_restful_regiration#注册单个用户)和[批量注册用户](./agora_chat_restful_regiration#注册单个用户)两个 RESTful 接口之外的接口有效。 | +| 401 | auth_bad_access_token | “Unable to authenticate” | 调用 RESTful 接口发送请求时使用的 App Token 无效。App Token 的格式正确,但不是由接收请求的服务器生成的,导致服务器无法识别该 Token。
该错误码针对除[注册单个用户](account_system.html#授权注册单个用户)和[批量注册用户](account_system.html#批量注册用户)两个 RESTful 接口之外的接口有效。 | | 403 | forbidden_op | “can not join this group, reason:user: hxtest1 already in group: 40659491815425\n” | 添加群组或聊天室成员时,被添加用户已在群组或聊天室内。 | | 403 | forbidden_op | “users [hxtest100] are not members of this group!” | 踢除群组或聊天室成员时,被踢除的用户不在群组或聊天室内。 | | 403 | forbidden_op | “user: username1 doesn't exist in group: 40659491815425” | 转让群组时,被转让的用户不是群组内成员。 | @@ -85,7 +85,7 @@ | 413 | Request Entity Too Large | “Request Entity Too Large” | 请求体过大,如上传文件时文件过大,需要拆成几个更小的请求体重试。 | | 415 | web_application | “Unsupported Media Type” | 请求体的类型不支持,请检查请求头是否添加了 `Content-Type`: `application/json`,请求包体是否符合标准的 JSON 格式,以及请求头中是否有接口不需要的参数。 | | 429 | resource_limited | “You have exceeded the limit of the Free edition. Please upgrade to higher edition.” | 超过免费版套餐包限制。如需开通其他版本套餐包,需联系环信商务。 | -| 429 | reach_limit | “This request has reached api limit” | 超过即时通讯 RESTful API 的[调用频率限制](/product/limitation.html)。如果限制条件无法满足你的实际业务需求,需联系请联系环信商务。 | +| 429 | reach_limit | “This request has reached api limit” | 超过即时通讯 RESTful API 的调用频率限制。 | | 500 | no_full_text_index | “Entity ‘user’ with property named ‘username’ is not full text indexed. You cannot use the ‘contains’ operand on this field” | username 不支持全文索引,不可以对该字段进行 `contains` 操作。 | | 500 | unsupported_service_operation | “Service operation not supported” | 请求 URL 不支持该请求方式。 | | 500 | web_application | “javax.ws.rs.WebApplicationException” | 请求 URL 错误。 | \ No newline at end of file diff --git a/docs/document/v1/server-side/group.md b/docs/document/v1/server-side/group.md index 1192f7902..538baa6de 100644 --- a/docs/document/v1/server-side/group.md +++ b/docs/document/v1/server-side/group.md @@ -4,14 +4,14 @@ 环信即时通讯 IM 提供了 RESTful API 管理 App 中的群组。 -单个 App 创建群组数量有限制,而且单个用户可加入群组的数量视版本而定,详见 [使用限制](limitation.html#群组限制)。 +单个 App 创建群组数量有限制,而且单个用户可加入群组的数量视版本而定,详见 [使用限制](/document/v1/privatization/uc_limitation.html#群组限制)。 ## 前提条件 要调用环信即时通讯 RESTful API,请确保满足以下要求: - 已在环信即时通讯 IM 管理后台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM RESTful API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -19,9 +19,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :--------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | | `group_id` | String | 是 | 群组 ID。 | | `username` | String | 是 | 用户 ID。 | @@ -91,7 +91,7 @@ POST https://{host}/{org_name}/{app_name}/chatgroups | `description` | String | 是 | 群组描述,最大长度为 512 字符。| | `public` | Bool | 是 | 是否是公开群。公开群可以被搜索到,用户可以申请加入公开群;私有群无法被搜索到,因此需要群主或群管理员添加,用户才可以加入。
- `true`:公开群;
- `false`:私有群。 | | `scale` | String | 否 | 群组规模,取决于群成员总数 `maxusers` 参数。
- (默认)`normal`:普通群,即群成员总数不超过 3000。
- `large`:大型群,群成员总数超过 3000。**创建大型群时,该参数必传。**大型群不支持离线推送。如需默认创建大型群,请联系环信商务。| -| `maxusers` | Int | 否 | 群组最大成员数(包括群主),值为数值类型,默认值 200。不同套餐支持的人数上限不同,详见 [产品价格](https://www.easemob.com/pricing/im)。 | +| `maxusers` | Int | 否 | 群组最大成员数(包括群主),值为数值类型,默认值 2000。不同套餐支持的人数上限不同,详见[使用限制](/document/v1/privatization/uc_limitation.html#群组限制)。 | | `allowinvites` | Bool | 是 | 是否允许群成员邀请用户加入群组:
- `true`:群成员可拉人入群;
- (默认)`false`:只有群主或者管理员才可以拉人入群。
注:该参数仅对私有群有效,因为公开群不允许群成员邀请其他用户入群。 | | `membersonly` | Bool | 否 | 用户申请入群是否需要群主或者群管理员审批。
- `true`:需要;
- (默认)`false`:不需要,用户直接进群。 | | `invite_need_confirm` | Bool | 否 | 邀请用户入群时是否需要被邀用户同意。
- (默认)`true`:是;
- `false`:否。 | @@ -1257,7 +1257,7 @@ curl -X DELETE -H 'Content-Type: application/json' -H 'Accept: application/json' ## 管理群组成员 -环信即时通讯 IM 提供多个接口实现对群组成员的管理,包括添加和移除群组成员、转让群组所有权以及群组黑名单、白名单和禁言列表相关操作。 +环信即时通讯 IM 提供多个接口实现对群组成员的管理,包括添加和移除群组成员、群组黑名单、白名单和禁言列表相关操作。 ### 分页获取群成员列表 @@ -1645,7 +1645,7 @@ curl -X DELETE -H 'Accept: application/json' -H 'Authorization: Bearer ### 获取群管理员列表 获取群组管理员列表。 @@ -2052,7 +2052,7 @@ curl -X DELETE HTTP://XXXX/XXXX/XXXX/chatgroups/10XXXX85/admin/user1 -H 'Authori "applicationName": "testapp" } ``` - + ## 管理黑名单 环信即时通讯 IM 提供多个接口完成群组黑名单管理,包括查看黑名单中的用户以及将用户加入和移除黑名单等。 @@ -2960,7 +2960,7 @@ curl -X POST HTTP://XXXX/XXXX/XXXX/chatgroups/10XXXX85/mute -d '{"usernames":["u "applicationName": "testapp" } ``` - + + \ No newline at end of file diff --git a/docs/document/v1/server-side/java_server_sdk.md b/docs/document/v1/server-side/java_server_sdk.md index 63aa05071..7b235f73e 100644 --- a/docs/document/v1/server-side/java_server_sdk.md +++ b/docs/document/v1/server-side/java_server_sdk.md @@ -12,7 +12,7 @@ Server SDK 提供了用户、消息、群组、聊天室等资源的操作管理 - Java 1.8 - [Reactor](https://projectreactor.io/)(io.projectreactor:reactor-bom:2020.0.4) -- 有效的环信即时通讯 IM 开发者账号和 App Key、Client ID、ClientSecret,登录 [环信管理后台](https://console.easemob.com/user/login) 到“应用列表” → 点击“查看”即可获取到 App Key、Client ID、ClientSecret。 +- 有效的环信即时通讯 IM 开发者账号和 App Key、Client ID、ClientSecret,登录 [环信管理后台](enable_and_configure_IM.html) 到“应用列表” → 点击“管理”即可获取到 App Key、Client ID、ClientSecret。 ## 实现方法 @@ -128,7 +128,7 @@ public class Config { ## 参考 - [Server SDK 的 API 文档](https://easemob.github.io/easemob-im-server-sdk/)。 -- [Server SDK 开源地址](https://github.com/easemob/easemob-im-server-sdk)。 +- [Server SDK 开源地址](https://github.com/easemob/easemob-im-server-sdk/tree/v0.7.5)。 ## 常见问题 diff --git a/docs/document/v1/server-side/limitation.md b/docs/document/v1/server-side/limitation.md index c65aa2812..a85f10ada 100644 --- a/docs/document/v1/server-side/limitation.md +++ b/docs/document/v1/server-side/limitation.md @@ -1,6 +1,6 @@ --- { - pageUri: "/product/limitation.html", + pageUri: "/document/v1/privatization/uc_limitation.html", title: "限制条件" } --- \ No newline at end of file diff --git a/docs/document/v1/server-side/message_chatroom.md b/docs/document/v1/server-side/message_chatroom.md index 4eed22ad0..671486fbc 100644 --- a/docs/document/v1/server-side/message_chatroom.md +++ b/docs/document/v1/server-side/message_chatroom.md @@ -18,7 +18,6 @@ 要调用环信即时通讯 REST API,请确保满足以下要求: - 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 ## 公共参数 @@ -26,9 +25,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :----------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | ### 响应参数 @@ -88,7 +87,7 @@ POST https://{host}/{org_name}/{app_name}/messages/chatrooms | `body` | JSON | 是 | 消息内容。body 包含的字段见下表说明。 | | `sync_device` | Bool | 否 | 消息发送成功后,是否将消息同步到发送方。
- `true`:是;
- (默认)`false`:否。 | | `routetype` | String | 否 | 若传入该参数,其值为 `ROUTE_ONLINE`,表示接收方只有在线时才能收到消息,若接收方离线则无法收到消息。若不传入该参数,无论接收方在线还是离线都能收到消息。 | -| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/android/push.html#自定义显示)。 | +| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/v1/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/v1/android/push.html#自定义显示)。 | 请求体中的 `body` 字段说明详见下表。 @@ -823,7 +822,7 @@ POST https://{host}/{org_name}/{app_name}/messages/chatrooms/users | `type` | String | 是 | 消息类型:
- `txt`:文本消息;
- `img`:图片消息;
- `audio`:语音消息;
- `video`:视频消息;
- `file`:文件消息;
- `loc`:位置消息;
- `cmd`:透传消息;
- `custom`:自定义消息。 | | `body` | JSON | 是 | 消息内容。body 包含的字段见下表说明。 | | `sync_device` | Bool | 否 | 消息发送成功后,是否将消息同步到发送方。
- `true`:是;
- (默认)`false`:否。 | -| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/android/push.html#自定义显示)。 | +| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/v1/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/v1/android/push.html#自定义显示)。 | | `users` | Array | 是 |接收消息的聊天室成员的用户 ID 数组。每次最多可传 20 个用户 ID。| 请求体中的 `body` 字段说明详见下表。 diff --git a/docs/document/v1/server-side/message_download.md b/docs/document/v1/server-side/message_download.md index a265c6706..cadd9e9ca 100644 --- a/docs/document/v1/server-side/message_download.md +++ b/docs/document/v1/server-side/message_download.md @@ -14,7 +14,7 @@ 要调用环信即时通讯 REST API,请确保满足以下要求: - 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -22,9 +22,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :----------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | ### 响应参数 @@ -83,8 +83,8 @@ POST https://{host}/{org_name}/{app_name}/chatfiles | 参数 | 类型 | 是否必需 | 描述 | | :----------------- | :----- | :------- | :--------------- | | `file` | String | 是 | 文件本地路径。 | -| `thumbnail-height` | Int | 否 | 缩略图的高度,单位为像素。
- 若上传的原图或视频缩略图小于 10 KB,上传的图片即为缩略图。
- 若上传的图片超过 10 KB,缩略图的高度取决于该参数的设置。
- 若不传该参数,缩略图的高度默认为 170 像素。你也可以在 [环信即时通讯控制台](https://console.easemob.com/user/login)的 `服务概览` 页面的 `设置` 区域修改该默认值。 | -| `thumbnail-width` | Int | 否 | 缩略图的宽度,单位为像素。
- 若上传的原图或视频缩略图小于 10 KB,图片原图即为缩略图。
- 若上传的图片超过 10 KB,缩略图的宽度取决于该参数的设置。
- 若不传该参数,缩略图的宽度默认为 170 像素。你也可以在 [环信即时通讯控制台](https://console.easemob.com/user/login)的 `服务概览` 页面的 `设置` 区域修改该默认值。 | +| `thumbnail-height` | Int | 否 | 缩略图的高度,单位为像素。
- 若上传的原图或视频缩略图小于 10 KB,上传的图片即为缩略图。
- 若上传的图片超过 10 KB,缩略图的高度取决于该参数的设置。
- 若不传该参数,缩略图的高度默认为 170 像素。你也可以在 环信即时通讯控制台的 `应用概览>应用详情` 页面的 `应用设置` 区域修改该默认值。 | +| `thumbnail-width` | Int | 否 | 缩略图的宽度,单位为像素。
- 若上传的原图或视频缩略图小于 10 KB,图片原图即为缩略图。
- 若上传的图片超过 10 KB,缩略图的宽度取决于该参数的设置。
- 若不传该参数,缩略图的宽度默认为 170 像素。你也可以在 环信即时通讯控制台的 `应用概览>应用详情` 页面的 `应用设置` 区域修改该默认值。 | ### HTTP 响应 diff --git a/docs/document/v1/server-side/message_group.md b/docs/document/v1/server-side/message_group.md index 9a899112d..8656da027 100644 --- a/docs/document/v1/server-side/message_group.md +++ b/docs/document/v1/server-side/message_group.md @@ -17,7 +17,7 @@ 要调用环信即时通讯 REST API,请确保满足以下要求: - 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -25,9 +25,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :----------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | ### 响应参数 @@ -86,7 +86,7 @@ POST https://{host}/{org_name}/{app_name}/messages/chatgroups | `body` | JSON | 是 | 消息内容。body 包含的字段见下表说明。 | | `sync_device` | Bool | 否 | 消息发送成功后,是否将消息同步到发送方。
- `true`:是;
- (默认)`false`:否。 | | `routetype` | String | 否 | 若传入该参数,其值为 `ROUTE_ONLINE`,表示接收方只有在线时才能收到消息,若接收方离线则无法收到消息。若不传入该参数,无论接收方在线还是离线都能收到消息。 | -| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/android/push.html#自定义显示)。 | +| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/v1/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/v1/android/push.html#自定义显示)。 | | `ext.em_ignore_notification` | Bool | 否 | 是否发送静默消息:
- `true`:是;
- (默认)`false`:否。
发送静默消息指用户离线时,环信即时通讯 IM 服务不会通过第三方厂商的消息推送服务向该用户的设备推送消息通知。因此,用户不会收到消息推送通知。当用户再次上线时,会收到离线期间的所有消息。发送静默消息和免打扰模式下均为不推送消息,区别在于发送静默消息为发送方设置不推送消息,而免打扰模式为接收方设置在指定时间段内不接收推送通知。| 请求体中的 `body` 字段说明详见下表。 @@ -829,7 +829,7 @@ POST https://{host}/{org_name}/{app_name}/messages/chatgroups/users | `type` | String | 是 | 消息类型:
- `txt`:文本消息;
- `img`:图片消息;
- `audio`:语音消息;
- `video`:视频消息;
- `file`:文件消息;
- `loc`:位置消息;
- `cmd`:透传消息;
- `custom`:自定义消息。 | | `body` | JSON | 是 | 消息内容。body 包含的字段见下表说明。 | | `sync_device` | Bool | 否 | 消息发送成功后,是否将消息同步到发送方。
- `true`:是;
- (默认)`false`:否。 | -| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/android/push.html#自定义显示)。 | +| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/v1/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/v1/android/push.html#自定义显示)。 | | `ext.em_ignore_notification` | Bool | 否 | 是否发送静默消息:
- `true`:是;
- (默认)`false`:否。
发送静默消息指用户离线时,环信即时通讯 IM 服务不会通过第三方厂商的消息推送服务向该用户的设备推送消息通知。因此,用户不会收到消息推送通知。当用户再次上线时,会收到离线期间的所有消息。发送静默消息和免打扰模式下均为不推送消息,区别在于发送静默消息为发送方设置不推送消息,而免打扰模式为接收方设置在指定时间段内不接收推送通知。| | `users` | Array | 是 |接收消息的群成员的用户 ID 数组。每次最多可传 20 个用户 ID。| diff --git a/docs/document/v1/server-side/message_historical.md b/docs/document/v1/server-side/message_historical.md index 4926b27d1..99d26ee40 100644 --- a/docs/document/v1/server-side/message_historical.md +++ b/docs/document/v1/server-side/message_historical.md @@ -6,14 +6,14 @@ - 单次请求获取从指定起始时间开始一小时内的发送的历史消息记录。 - 查询历史消息记录时存在一定延时,无法实时获取。 -- 过期的历史消息记录无法获取。对于不同的套餐版本,历史消息记录的默认存储时间不同,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 +- 过期的历史消息记录无法获取。历史消息记录的默认存储时间14天,支持联系商务调整。 ## 前提条件 要调用环信即时通讯 REST API,请确保满足以下要求: - 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -21,9 +21,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。| +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | ### 响应参数 diff --git a/docs/document/v1/server-side/message_import.md b/docs/document/v1/server-side/message_import.md index 421792bea..a5341d84e 100644 --- a/docs/document/v1/server-side/message_import.md +++ b/docs/document/v1/server-side/message_import.md @@ -9,7 +9,7 @@ 要调用环信即时通讯 REST API,请确保满足以下要求: - 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -17,9 +17,10 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :----------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | + ### 响应参数 diff --git a/docs/document/v1/server-side/message_recall.md b/docs/document/v1/server-side/message_recall.md index c15710421..2d32c0c9e 100644 --- a/docs/document/v1/server-side/message_recall.md +++ b/docs/document/v1/server-side/message_recall.md @@ -8,7 +8,7 @@ ## 撤回消息 -发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在[环信即时通讯云控制台](https://console.easemob.com/user/login)的**功能配置** > **功能配置总览** > **基础功能** 页面设置消息撤回时长,该时长不超过 7 天。 +发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在 环信即时通讯云控制台的**服务管理** > **服务概览** 页面设置消息撤回时长,该时长不超过 7 天。 ### HTTP 请求 @@ -36,7 +36,7 @@ POST https://{host}/{org_name}/{app_name}/messages/msg_recall | `to` | String | 是 | 要撤回消息的接收方。
- 单聊为接收方用户 ID;
- 群聊为群组 ID;
- 聊天室聊天为聊天室 ID。
若不传入该参数,请求失败。 | | `chat_type` | String | 是 | 要撤回消息的会话类型:
- `chat`:单聊;
- `groupchat`:群聊 ;
- `chatroom`:聊天室 。 | | `from` | String | 否 | 消息撤回方的用户 ID。若不传该参数,默认为 `admin`。 | -| `force` | Bool | 是 | 是否支持撤回超过服务器存储时长的消息。服务器存储时长详见[服务器消息保存时长](/product/limitation.html#消息存储时长限制)。
- `true`:是。这种情况下,你可以撤回在撤回时长内的消息,也可以撤回超过服务器存储时长的消息。对于后者,该接口会撤回接收方在本地保存的消息。若消息发送的时间介于你的撤回时长和服务器存储时长之间,则撤回失败。例如,如果消息的撤回时长为 2 分钟,在服务器上的存储时长为 7 天,你可以撤回 2 分钟以内发送的消息或发送时间超过 7 天的消息;若消息发送了 3 分钟,则撤回失败。
- `false`:否,不支持撤回超过服务器存储时长的消息。如果你采用默认的 2 分钟撤回时长或联系了商务设置了撤回时长,服务器只能撤回指定时长内发送的消息,超过该时长的消息无法撤回。例如,你设置的撤回时长为 3 分钟,若消息发送了 4 分钟,则撤回失败。 | +| `force` | Bool | 是 | 是否支持撤回超过服务器存储时长的消息。
- `true`:是。这种情况下,你可以撤回在撤回时长内的消息,也可以撤回超过服务器存储时长的消息。对于后者,该接口会撤回接收方在本地保存的消息。若消息发送的时间介于你的撤回时长和服务器存储时长之间,则撤回失败。例如,如果消息的撤回时长为 2 分钟,在服务器上的存储时长为 7 天,你可以撤回 2 分钟以内发送的消息或发送时间超过 7 天的消息;若消息发送了 3 分钟,则撤回失败。
- `false`:否,不支持撤回超过服务器存储时长的消息。如果你采用默认的 2 分钟撤回时长或联系了商务设置了撤回时长,服务器只能撤回指定时长内发送的消息,超过该时长的消息无法撤回。例如,你设置的撤回时长为 3 分钟,若消息发送了 4 分钟,则撤回失败。 | ### HTTP 响应 diff --git a/docs/document/v1/server-side/message_single.md b/docs/document/v1/server-side/message_single.md index 18bbd74db..f95a1d5d6 100644 --- a/docs/document/v1/server-side/message_single.md +++ b/docs/document/v1/server-side/message_single.md @@ -28,7 +28,7 @@
@@ -36,7 +36,7 @@

图片/语音/视频/文件消息

@@ -57,7 +57,7 @@ 要调用环信即时通讯 REST API,请确保满足以下要求: - 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -65,9 +65,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :----------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | | `username` | String | 是 | 用户 ID。 | ### 响应参数 @@ -123,7 +123,7 @@ POST https://{host}/{org_name}/{app_name}/messages/users | `body` | JSON | 是 | 消息内容。body 包含的字段见下表说明。 | | `sync_device` | Bool | 否 | 消息发送成功后,是否将消息同步到发送方。
- `true`:是;
- (默认)`false`:否。 | | `routetype` | String | 否 | 若传入该参数,其值为 `ROUTE_ONLINE`,表示接收方只有在线时才能收到消息,若接收方离线则无法收到消息。若不传入该参数,无论接收方在线还是离线都能收到消息。 | -| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/android/push.html#自定义显示)。 | +| `ext` | JSON | 否 | 消息支持扩展字段,可添加自定义信息。不能对该参数传入 `null`。同时,推送通知也支持自定义扩展字段,详见 [APNs 自定义显示](/document/v1/ios/push.html#自定义显示) 和 [Android 推送字段说明](/document/v1/android/push.html#自定义显示)。 | | `ext.em_ignore_notification` | Bool | 否 | 是否发送静默消息:
- `true`:是;
- (默认)`false`:否。
发送静默消息指用户离线时,环信即时通讯 IM 服务不会通过第三方厂商的消息推送服务向该用户的设备推送消息通知。因此,用户不会收到消息推送通知。当用户再次上线时,会收到离线期间的所有消息。发送静默消息和免打扰模式下均为不推送消息,区别在于发送静默消息为发送方设置不推送消息,而免打扰模式为接收方设置在指定时间段内不接收推送通知。| 请求体中的 `body` 字段说明详见下表。 diff --git a/docs/document/v1/server-side/overview.md b/docs/document/v1/server-side/overview.md index fe83cd8c7..c34a9feb4 100644 --- a/docs/document/v1/server-side/overview.md +++ b/docs/document/v1/server-side/overview.md @@ -4,7 +4,7 @@ 环信即时通讯通过 REST 平台提供 REST API,你可以通过你的业务服务器向环信 REST 服务器发送 HTTP 请求,在服务端实现实时通信。 -另外环信 Server SDK 提供了用户、消息、群组、聊天室等资源的操作管理能力,具体参见:[Java Server SDK](java_server_sdk.html) 和 [PHP Server SDK](php_server_sdk.html)。 + ## REST 平台架构 @@ -41,7 +41,8 @@ ## 请求域名 -环信不同数据中心的 REST API 请求域名 {host}: +请参照私有化部署文档 **5.2应用信息** 章节获取REST API请求信息。 + ### 通信协议 环信即时通讯 REST API 支持 HTTP 和 HTTPS 协议。 @@ -73,7 +74,6 @@ | 名称 | 方法 | 请求 | 描述 | | :----------- | :----- | :----------------------------------------------- | :-------------------- | | [开放](account_system.html#开放注册单个用户) 和 [授权](account_system.html#授权注册单个用户)注册单个用户 | POST | /{org_name}/{app_name}/users | 开放注册和授权注册一个用户。 | -| 批量注册用户 | POST | /{org_name}/{app_name}/users | 授权注册多个用户。 | | 获取单个用户详情 | GET | /{org_name}/{app_name}/users/{username} | 获取单个用户的信息。 | | 批量获取用户详情 | GET | /{org_name}/{app_name}/users | 获取多个用户的信息。 | | 删除单个用户账号| DELETE | /{org_name}/{app_name}/users/{username} | 删除单个用户。 | @@ -121,7 +121,6 @@ | :------------------------- | :----- | :---------------------------------------------- | :------------------------------------------- | | 设置用户属性 | PUT | /{org_name}/{app_name}/metadata/user/{username} | 对指定的用户设置用户属性。 | | 获取指定用户的所有用户属性 | GET | /{org_name}/{app_name}/metadata/user/{username} | 获取指定用户的所有用户属性。 | -| 批量获取用户属性 | POST | /{org_name}/{app_name}/metadata/user/get | 根据指定的用户名列表和属性列表查询用户属性。 | | 删除用户属性 | DELETE | /{org_name}/{app_name}/metadata/user/{username} | 删除指定用户的所有用户属性。 | | 获取 app 下的用户属性总大小 | GET | /{org_name}/{app_name}/metadata/user/capacity | 获取该 app 下所有用户的用户属性总大小。 | @@ -166,7 +165,6 @@ | 获取群管理员列表 | GET | /{org_name}/{app_name}/chatgroups/{group_id}/admin | 获取群组管理员列表。 | | 添加群管理员 | POST | /{org_name}/{app_name}/chatgroups/{group_id}/admin | 添加用户至群组管理员列表。 | | 移除群管理员| DELETE | /{org_name}/{app_name}/chatgroups/{group_id}/admin/{oldadmin} | 从群组管理员列表中移除用户。| -| 转让群组 | PUT | /{org_name}/{app_name}/chatgroups/{group_id} | 转让群主权限。 | | 查询群组黑名单 | GET | /{org_name}/{app_name}/chatgroups/{group_id}/blocks/users | 查询群组的黑名单列表。 | | 添加单个用户至群组黑名单 | POST | /{org_name}/{app_name}/chatgroups/{group_id}/blocks/users/{username} | 将用户添加至群组的黑名单列表。 | | 批量添加用户至群组黑名单 | POST | /{org_name}/{app_name}/chatgroups/{group_id}/blocks/users | 将用户批量添加至群组的黑名单列表。 | @@ -178,10 +176,11 @@ | 将用户移除群组白名单 | DELETE | {org_name}/{app_name}/chatgroups/{group_id}/white/users/{username} | 将指定用户从群组白名单中移除。 | | 获取禁言列表 | GET | /{org_name}/{app_name}/chatgroups/{group_id}/{mute} | 获得指定群组的禁言列表。 | | 禁言指定群成员 | POST | /{org_name}/{app_name}/chatgroups/{group_id}/mute | 将指定群成员禁言。 | -| 禁言全体成员 | POST | /{org_name}/{app_name}/chatgroups/{group_id}/ban | 对所有群组成员一键禁言。 | + + ### 聊天室管理 [聊天室管理](chatroom.html) 包括创建、获取、修改、删除聊天室。 @@ -219,11 +218,13 @@ | 删除聊天室 | DELETE | /{org_name}/{app_name}/chatrooms/{chatroom_id} | 删除一个聊天室。 | | 获取聊天室公告 | GET | /{org_name}/{app_name}/chatrooms/{chatroom_id}/announcement | 获取指定聊天室 ID 的聊天室公告。 | | 修改聊天室公告 | PUT | /{org_name}/{app_name}/chatrooms/{chatroom_id}/announcement | 修改指定聊天室 ID 的聊天室公告。 | + ### 聊天室成员管理 @@ -250,10 +251,9 @@ | 将用户移除聊天室白名单 | DELETE | /{org_name}/{app_name}/chatrooms/{chatroom_id}/white/users/{username} | 将指定用户从聊天室白名单移除。 | | 获取聊天室的禁言列表 | GET | /{org_name}/{app_name}/chatrooms/{chatroom_id}/mute | 获取当前聊天室的禁言用户列表。 | | 禁言聊天室成员 | POST | /{org_name}/{app_name}/chatrooms/{chatroom_id}/mute | 将聊天室成员禁言。 | -| 禁言聊天室全体成员 | POST | /{org_name}/{app_name}/chatrooms/{chatroom_id}/ban | 对所有聊天室成员一键禁言。 | | 解除聊天室禁言成员 | DELETE | /{org_name}/{app_name}/chatrooms/{chatroom_id}/mute/{member1}(,{member2},…) | 将指定用户从禁言列表中移除。 | -| 解除聊天室全员禁言 | PUT | /{org_name}/{app_name}/chatrooms/{chatroom_id}/ban | 一键取消对聊天室全体成员的禁言。 | + \ No newline at end of file diff --git a/docs/document/v1/server-side/php_server_sdk.md b/docs/document/v1/server-side/php_server_sdk.md index 3e64193d6..911179e49 100644 --- a/docs/document/v1/server-side/php_server_sdk.md +++ b/docs/document/v1/server-side/php_server_sdk.md @@ -33,9 +33,7 @@ composer require maniac/easemob-php 使用 PHP SDK 之前,需准备环信 App Key、Client ID 和 Client Secret。 -如果你有环信管理后台账号并创建过应用,请先登录环信管理后台,点击 [这里](https://console.easemob.com/user/login),然后在 “应用列表” 中点击 “查看” 即可获取 appkey、Client ID 和 ClientSecret。 - -如果你没有环信管理后台账号,请先注册账号,点击 [这里](https://console.easemob.com/user/register),注册成功后请登录,然后点击 “添加应用”,添加成功后点击 “查看” 即可获取 appkey、Client ID 和 ClientSecret。 +- 有效的环信即时通讯 IM 开发者账号和 App Key、Client ID、ClientSecret,登录 [环信管理后台](enable_and_configure_IM.html) 到“应用列表” → 点击“管理”即可获取到 App Key、Client ID、ClientSecret。 ## 使用 @@ -107,7 +105,7 @@ $user->create($data); ## 参考 - PHP SDK 的 API 文档在 [这里](https://easemob.github.io/im-php-server-sdk/annotated.html) -- PHP SDK 开源地址在 [这里](https://github.com/easemob/im-php-server-sdk) +- PHP SDK 开源地址在 [这里](https://github.com/easemob/im-php-server-sdk/tree/1.0.0) ## 常见问题 diff --git a/docs/document/v1/server-side/presence.md b/docs/document/v1/server-side/presence.md index 687f85380..9b052fce4 100644 --- a/docs/document/v1/server-side/presence.md +++ b/docs/document/v1/server-side/presence.md @@ -4,9 +4,6 @@ 在线状态(Presence)表示用户的当前状态信息。除了环信 IM 内置的在线和离线状态,你还可以添加自定义在线状态,例如忙碌、马上回来、离开、接听电话、外出就餐等。本文展示如何调用环信即时通讯 RESTful API 实现用户在线状态(Presence)订阅,包括设置用户在线状态信息、批量订阅和获取在线状态、取消订阅以及查询订阅列表。 -:::notice -使用该特性前,你需要联系商务开通。 -::: ## 前提条件 @@ -14,7 +11,7 @@ - 已在环信即时通讯云控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 - 已从服务端获取 app token,详见 [使用 App Token 鉴权](easemob_app_token.html)。 -- 了解环信 IM API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -24,9 +21,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :------------ | :----- | :------ | :---------------- | -| `host`| String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。| -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。| +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | | `username` | String | 是 |用户在即时通讯服务器上的唯一 ID。 | ## 认证方式 diff --git a/docs/document/v1/server-side/push.md b/docs/document/v1/server-side/push.md index 1c95425c6..b85295230 100644 --- a/docs/document/v1/server-side/push.md +++ b/docs/document/v1/server-side/push.md @@ -2,10 +2,10 @@ -本文展示如何调用环信即时通讯 RESTful API 实现离线推送,包括设置离线推送通知显示的昵称、推送通知方式及免打扰模式。调用以下方法前,请先参考 [接口频率限制](limitationapi.html) 了解即时通讯 RESTful API 的调用频率限制。 +本文展示如何调用环信即时通讯 RESTful API 实现离线推送,包括设置离线推送通知显示的昵称、推送通知方式及免打扰模式。 :::tip -若要使用离线推送的高级功能,即设置推送通知模式、免打扰模式和自定义推送模板,你需要在[环信即时通讯云控制后台](https://console.easemob.com/user/login)中点击你的应用后选择 **即时通讯** > **功能配置** > **功能配置总览** 开通离线推送高级功能。 +若要使用离线推送的高级功能,即设置推送通知模式、免打扰模式和自定义推送模板,你需要在环信即时通讯云控制后台中点击你的应用后选择 **服务管理** > **服务概览** 开通离线推送高级功能。 ::: ## 公共参数 @@ -16,9 +16,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | | `username` | String | 是 | 环信用户 ID。 | ### 响应参数 @@ -258,7 +258,7 @@ PUT https://{host}/{org_name}/{app_name}/users/{username} | `entities.created` | Number | 用户注册的 Unix 时间戳,单位为毫秒。 | | `entities.modified` | Number | 最近一次修改用户信息的 Unix 时间戳,单位为毫秒。 | | `entities.username` | String | 用户 ID。用户登录的唯一账号。 | -| `entities.activated` | Boolean | 用户是否为活跃状态:
  • `true`:用户为活跃状态。
  • `false`:用户为封禁状态。如要使用已被封禁的用户账户,你需要调用[解禁用户](/document/server-side/account_system.html#账号封禁)解除封禁。
| +| `entities.activated` | Boolean | 用户是否为活跃状态:
  • `true`:用户为活跃状态。
  • `false`:用户为封禁状态。如要使用已被封禁的用户账户,你需要调用[解禁用户](account_system.html#账号解禁)解除封禁。
| | `entities.nickname` | String | 推送通知中显示的昵称。 | 其他参数及说明详见 [公共参数](#公共参数)。 @@ -340,7 +340,7 @@ PUT https://{host}/{org_name}/{app_name}/users/{username} | `entities.created` | Long | 用户创建的 Unix 时间戳,单位为毫秒。 | | `entities.modified` | Long | 最近一次修改用户信息的 Unix 时间戳,单位为毫秒。 | | `entities.username` | String | 用户 ID。用户登录的唯一账号。 | -| `entities.activated` | Boolean | 用户是否为活跃状态:
  • `true`:用户为活跃状态。
  • `false`:用户为封禁状态。如要使用已被封禁的用户账户,你需要调用[解禁用户](/document/server-side/account_system.html#账号封禁)解除封禁。
| +| `entities.activated` | Boolean | 用户是否为活跃状态:
  • `true`:用户为活跃状态。
  • `false`:用户为封禁状态。如要使用已被封禁的用户账户,你需要调用[解禁用户](account_system.html#账号封禁)解除封禁。
| | `entities.notification_no_disturbing` | Boolean | 是否设置为免打扰模式:
  • `true`:是;
  • `false`:否。
| | `entities.notification_no_disturbing_start` | Int | 免打扰时间段的开始时间。 | | `entities.notification_no_disturbing_end` | Int | 免打扰时间段的结束时间。 | @@ -446,7 +446,7 @@ PUT https://{host}/{org_name}/{app_name}/users/{username} | `entities.created` | Long | 用户创建的 Unix 时间戳,单位为毫秒。 | | `entities.modified` | Long | 最近一次修改用户信息的 Unix 时间戳,单位为毫秒。 | | `entities.username` | String | 用户 ID。用户登录的唯一账号。 | -| `entities.activated` | Boolean | 用户是否为活跃状态:
  • `true`:用户为活跃状态。
  • `false`:用户为封禁状态。如要使用已被封禁的用户账户,你需要调用[解禁用户](/document/server-side/account_system.html#账号封禁)解除封禁。
| +| `entities.activated` | Boolean | 用户是否为活跃状态:
  • `true`:用户为活跃状态。
  • `false`:用户为封禁状态。如要使用已被封禁的用户账户,你需要调用[解禁用户](account_system.html#账号封禁)解除封禁。
| | `entities.notification_no_disturbing` | Boolean | 是否设置为免打扰模式:
  • `true`:是;
  • `false`:否。
| | `entities.notification_no_disturbing_start` | Int | 免打扰时间段的开始时间。 | | `entities.notification_no_disturbing_end` | Int | 免打扰时间段的结束时间。 | diff --git a/docs/document/v1/server-side/reaction.md b/docs/document/v1/server-side/reaction.md index 47bb3b360..a03c7ac32 100644 --- a/docs/document/v1/server-side/reaction.md +++ b/docs/document/v1/server-side/reaction.md @@ -2,7 +2,7 @@ -消息表情回复(“Reaction”)指用户在单聊和群聊场景中对单条消息回复表情,可丰富用户聊天时的互动方式。对于单个消息,一个消息表情即为一个 Reaction,若不同用户重复添加同一消息表情,Reaction 数量计为 1。每条消息默认可添加 20 个 Reaction,若需提升该上限,需联系环信商务。 +消息表情回复(“Reaction”)指用户在单聊和群聊场景中对单条消息回复表情,可丰富用户聊天时的互动方式。对于单个消息,一个消息表情即为一个 Reaction,若不同用户重复添加同一消息表情,Reaction 数量计为 1。每条消息默认可添加 20 个 Reaction。 本页介绍如何使用即时通讯 IM RESTful API 实现 Reaction 功能。 @@ -12,7 +12,7 @@ - 已在环信即时通讯云控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 - 已从服务端获取 app token,详见 [使用 App Token 鉴权](easemob_app_token.html)。 -- 了解环信 IM RESTful API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -20,9 +20,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | | `username` | String | 是 | 用户 ID。 | ## 认证方式 diff --git a/docs/document/v1/server-side/user_relationship.md b/docs/document/v1/server-side/user_relationship.md index 140504478..7effe8ec9 100644 --- a/docs/document/v1/server-side/user_relationship.md +++ b/docs/document/v1/server-side/user_relationship.md @@ -9,7 +9,7 @@ 要调用环信即时通讯 RESTful API,请确保满足以下要求: - 已在环信即时通讯控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 认证方式 @@ -25,9 +25,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | | `username` | String | 是 | 用户 ID。 | ### 响应参数 @@ -55,7 +55,7 @@ 添加好友,好友必须是和当前用户在一个 App Key 下的用户。 -对于免费版即时通讯服务,单个 App Key 下的每个用户的好友数量上限为 1000,不同服务版本的 App Key 的该数量上限不同,具体可参考[版本功能介绍](https://www.easemob.com/pricing/im)。 +对于免费版即时通讯服务,单个 App Key 下的每个用户的好友数量上限为 1000,私有部署用户好友数无上限。 ### HTTP 请求 diff --git a/docs/document/v1/server-side/user_status_callback.md b/docs/document/v1/server-side/user_status_callback.md index 2f49b2df8..25f719a2f 100644 --- a/docs/document/v1/server-side/user_status_callback.md +++ b/docs/document/v1/server-side/user_status_callback.md @@ -17,13 +17,12 @@ ## 前提条件 -- 该服务为增值服务,需要开通相应版本后才能使用,具体见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im); - 服务开通后,若用户状态变更(在线、离线),环信即时通讯 IM 服务器会实时将状态同步到开发者设置的应用服务器地址,开发者接收到状态后自行进行业务处理。 - 某些情况下,例如进入隧道等特殊网络情况,依赖心跳超时,用户进入离线状态最长会有 5 分钟延时。 ## 实现方法 -直接在发送后回调添加规则页配置,具体见 [环信即时通讯云控制台](https://console.easemob.com/user/login)。 +直接在发送后回调添加规则页配置,具体见 [环信即时通讯云控制台](uc_configure.html#配置消息回调)。 ## 应答要求 diff --git a/docs/document/v1/server-side/userprofile.md b/docs/document/v1/server-side/userprofile.md index 4cfbe3437..4a7f08029 100644 --- a/docs/document/v1/server-side/userprofile.md +++ b/docs/document/v1/server-side/userprofile.md @@ -18,7 +18,6 @@ | :------------------------- | :------------------------------------------- | | 设置用户属性 | 设置指定的用户属性。 | | 获取指定用户的所有用户属性 | 获取指定用户的所有用户属性。 | -| 批量获取用户属性 | 根据指定的用户名列表和属性列表查询用户属性。 | | 删除用户属性 | 删除指定用户的所有属性。 | | 获取 app 下用户属性总大小 | 获取该 app 下所有用户的属性总大小。 | @@ -27,7 +26,7 @@ 要调用环信即时通讯 RESTful API,请确保满足以下条件: - 已在环信即时通讯云控制台 [开通配置环信即时通讯 IM 服务](enable_and_configure_IM.html)。 -- 了解环信 IM REST API 的调用频率限制,详见 [接口频率限制](limitationapi.html)。 + ## 公共参数 @@ -35,9 +34,9 @@ | 参数 | 类型 | 是否必需 | 描述 | | :--------- | :----- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------- | -| `host` | String | 是 | 环信即时通讯 IM 分配的用于访问 RESTful API 的域名。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `org_name` | String | 是 | 环信即时通讯 IM 为每个公司(组织)分配的唯一标识。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | -| `app_name` | String | 是 | 你在环信即时通讯云控制台创建应用时填入的应用名称。详见 [获取环信即时通讯 IM 的信息](enable_and_configure_IM.html#获取环信即时通讯-im-的信息)。 | +| `host` | String | 是 | 访问 RESTful API 的域名或服务器信息。
-公有云集成为 环信即时通讯控制台的 `即时通讯->服务概览`页面下的 `域名配置- Rest Api`。
-私有化集成为部署后 `服务器地址:端口`。 | +| `org_name` | String | 是 | 每个公司(组织)分配的唯一标识。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Orgname`。 | +| `app_name` | String | 是 | 创建应用时填入的应用名称。详见 环信即时通讯控制台的 `应用概览->应用详情`页面下的 `应用信息-Appname`。 | | `username` | String | 是 | 用户 ID。 | ### 响应参数 @@ -206,7 +205,7 @@ curl -X GET -H 'Content-Type: application/json' -H 'Authorization: Bearer ## 获取 app 下用户属性总大小 获取该 app 下所有用户的属性数据大小,单位为字节。 diff --git a/docs/document/v1/web/chatroom.md b/docs/document/v1/web/chatroom.md new file mode 100644 index 000000000..82d61b434 --- /dev/null +++ b/docs/document/v1/web/chatroom.md @@ -0,0 +1,500 @@ +# 聊天室管理 + +更新时间:2021-12-31 + +新版文档见:[聊天室管理](https://docs-im.easemob.com/ccim/web/chatroom1)。 + +环信聊天室模型支持默认最大成员数为5000,聊天室成员数可调整,请联系商务。 环信 Web IM SDK 支持聊天室管理功能的集成,集成后可以进行如下操作: + +- 获取聊天室列表 + +- 加入聊天室 + +- 退出聊天室 + +- 发送消息 + +- 接收及处理消息 + +- 聊天室相关回调 + +通过这些操作,可以组合帮助您完成多种场景下的 IM 需求。 + +## 创建聊天室 + +创建聊天室需要 [超级管理员权限](http://docs-im.easemob.com/im/server/basics/chatroom#管理超级管理员), 调用“createChatRoom”函数创建聊天室,示例如下: + +``` +let options = { + name: 'chatRoomName', // 聊天室名称 + description: 'description', // 聊天室描述 + maxusers: 200, // 聊天室成员最大数(包括聊天室创建者),默认值200,聊天室人数最大默认5000。 + members: ['user1', 'user2'] // 聊天室成员,此属性为可选的,但是如果加了此项,数组元素至少一个 +} +conn.createChatRoom(options).then((res) => { + console.log(res) +}) +``` + +------ + +## 销毁聊天室 + +销毁聊天室需要 [超级管理员权限](http://docs-im.easemob.com/im/server/basics/chatroom#管理超级管理员), 调用“destroyChatRoom”函数销毁聊天室,示例如下: + +``` +let options = { + chatRoomId: '1234567890' // 聊天室id +} +conn.destroyChatRoom(options).then((res) => { + console.log(res) +}) +``` + +## 获取聊天室列表 + +调用`getChatRooms`函数获取聊天室列表,示例如下: + +``` +// 列出所有聊天室,支持分页查询 +let option = { + pagenum: 1, // 页数 + pagesize: 20 // 每页个数 +}; +conn.getChatRooms(option).then((res) => { + console.log(res) +}) +``` + +------ + +## 获取聊天室详情 + +调用`getChatRoomDetails`函数获取聊天室详情,示例如下: + +``` +let options = { + chatRoomId: 'chatRoomId' // 聊天室id +} +conn.getChatRoomDetails(options).then((res) => { + console.log(res) +}) +``` + +## 更改聊天室详情 + +调用`modifyChatRoom`函数更改聊天室详情,示例如下: + +``` +let options = { + chatRoomId: 'chatRoomId', // 聊天室id + chatRoomName: 'chatRoomName', // 聊天室名称 + description: 'description', // 聊天室描述 + maxusers: 200 // 聊天室最大人数 +} +conn.modifyChatRoom(options).then((res) => { + console.log(res) +}) +``` + +## 加入聊天室 + +调用`joinChatRoom`加入聊天室,示例如下: + +``` +let options = { + roomId: 'roomId', // 聊天室id + message: 'reason' // 原因(可选参数) +} +conn.joinChatRoom(options).then((res) => { + console.log(res) +}) +``` + +------ + +## 退出聊天室 + +调用`quitChatRoom`退出聊天室,示例如下: + +``` +let options = { + roomId: 'roomId' // 聊天室id +} +conn.quitChatRoom(options).then((res) => { + console.log(res) +}) +``` + +------ + +## 获取聊天室成员 + +调用`listChatRoomMember`分页获取聊天室成员,示例如下: + +``` +let options = { + pageNum: 1, + pageSize: 10, + chatRoomId: 'chatRoomId' +} +conn.listChatRoomMember(options).then((res) => { + console.log(res) +}) +``` + +## 设置聊天室管理员 + +调用`setChatRoomAdmi`设置聊天室管理员,示例如下: + +``` +let options = { + chatRoomId: 'chatRoomId', // 聊天室id + username: 'user1' // 用户id +} +conn.setChatRoomAdmin(options).then((res) => { + console.log(res) +}) +``` + +## 移除聊天室管理员 + +调用`removeChatRoomAdmin`移除聊天室管理员,示例如下: + +``` +let options = { + chatRoomId: 'chatRoomId', // 聊天室id + username: 'user1' // 用户id +} +conn.removeChatRoomAdmin(options).then((res) => { + console.log(res) +}) +``` + +## 获取聊天室下所有管理员 + +调用`getChatRoomAdmin`获取聊天室下所有管理员,示例如下: + +``` +let options = { + chatRoomId: 'chatRoomId' // 聊天室id +} +conn.getChatRoomAdmin(options).then((res) => { + console.log(res) +}) +``` + +## 发送消息 + +见[发送消息](https://docs-im.easemob.com/im/web/basics/message#发送消息)。 + +------ + +## 聊天室公告 + +聊天室公告管理包含以下处理操作: + +- 上传/修改聊天室公告 + +- 获取聊天室公告 + +所有处理操作的示例下面会一一说明。 + +### 上传/修改聊天室公告 + +调用updateChatRoomAnnouncement函数上传/修改聊天室公告,示例如下: + +``` +let options = { + roomId: 'roomId', // 聊天室id + announcement: 'hello everyone' // 公告内容 +}; +conn.updateChatRoomAnnouncement(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 获取聊天室公告 + +调用`fetchChatRoomAnnouncement`函数获取聊天室公告,示例如下: + +``` +var options = { + roomId: 'roomId' // 聊天室id +}; +conn.fetchChatRoomAnnouncement(options).then((res) => { + console.log(res) +}) +``` + +------ + +## 聊天室禁言 + +### 将成员禁言 + +调用`muteChatRoomMember`禁止聊天室用户发言,示例如下: + +``` +let options = { + chatRoomId: "chatRoomId", // 聊天室id + username: 'username', // 被禁言的聊天室成员的id + muteDuration: -1000 // 被禁言的时长,单位ms,如果是“-1000”代表永久 +}; +conn.muteChatRoomMember(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 将成员解除禁言 + +调用`removeMuteChatRoomMember`解除聊天室用户禁言,示例如下: + +``` +let options = { + chatRoomId: "1000000000000", // 聊天室id + username: 'username' // 解除禁言的聊天室成员的id +}; +conn.removeMuteChatRoomMember(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 获取聊天室所有禁言成员 + +调用`getChatRoomMuted`获取聊天室下所有被禁言的成员,示例如下: + +``` +let options = { + chatRoomId: "chatRoomId" // 聊天室id +}; +conn.getChatRoomMuted(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 开启和关闭全员禁言 + +owner和管理员可以开启和关闭全员禁言。 + +``` +// 聊天室中禁言所有成员 +let options = { + chatRoomId: "chatRoomId" // 聊天室id +}; +conn.disableSendChatRoomMsg(options).then((res) => { + console.log(res) +}) + +// 聊天室中解除所有成员禁言 +conn.enableSendChatRoomMsg(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 白名单管理 + +可以将用户添加到白名单中,用户白名单在管理员开启了全员禁言时生效,可以运行白名单用户发出消息。 另外可以将用户移出白名单,检查自己是否在白名单中以及获取白名单列表。 + +``` +// 添加用户到白名单 +let options = { + chatRoomId: "chatRoomId", // 聊天室id + users: ["user1", "user2"] // 成员id列表 +}; +conn.addUsersToChatRoomWhitelist(options); + +// 将用户从白名单移除 +let options = { + chatRoomId: "chatRoomId", // 群组id + userName: "user" // 要移除的成员 +} +conn.rmUsersFromChatRoomWhitelist(options); + +// 从服务器获取白名单成员列表 +let options = { + chatRoomId: "chatRoomId" // 聊天室id +} +conn.getChatRoomWhitelist(options); + +// 查询成员是否是白名单用户,操作权限:app admin可查询所有用户;app user可查询自己 +let options = { + chatRoomId: "chatRoomId", // 聊天室id + userName: "user" // 要查询的成员 +} +conn.isChatRoomWhiteUser(options); +``` + +------ + +## 黑名单管理 + +黑名单管理包含以下处理操作: + +- 将成员加入群黑名单(单个) + +- 将成员加入群黑名单(批量) + +- 将成员移除群组黑名单(单个) + +- 将成员移除群组黑名单(批量) + +- 获取聊天室黑名单 + +所有处理操作的示例下面会一一说明。 + +### 将成员加入聊天室黑名单(单个) + +调用chatRoomBlockSingle将单个成员加入聊天室黑名单,示例如下: + +``` +let options = { + chatRoomId: 'chatRoomId', // 聊天室id + username: 'username' // 将要被加入黑名单的用户名 +}; +conn.chatRoomBlockSingle(options); +``` + +------ + +### 将成员加入聊天室黑名单(批量) + +调用chatRoomBlockMulti将单个成员加入聊天室黑名单,示例如下: + +``` +let options = { + chatRoomId: 'chatRoomId', // 聊天室id + usernames: ['user1', 'user2'] // 用户id数组 +}; +conn.chatRoomBlockMulti(options); +``` + +------ + +### 将成员移除聊天室黑名单(单个) + +调用`removeChatRoomBlockSingle`将单个成员从聊天室黑名单中移除,示例如下: + +``` +let options = { + chatRoomId: "chatRoomId", // 群组id + username: "user" // 需要移除的用户名 +} +conn.removeChatRoomBlockSingle(options); +``` + +------ + +### 将成员移除聊天室黑名单(批量) + +调用`removeChatRoomBlockMulti`将成员批量从聊天室黑名单中移除,示例如下: + +``` +let options = { + chatRoomId: "chatRoomId", // 聊天室id + usernames: ["user1", "user2"] // 需要移除的用户名数组 +} +conn.removeChatRoomBlockMulti(options); +``` + +------ + +### 获取聊天室黑名单 + +调用`getChatRoomBlacklistNew`获取聊天室黑名单,示例如下: + +``` +let options = { + chatRoomId: "chatRoomId", // 聊天室id +}; +conn.getChatRoomBlacklistNew(options); +``` + +------ + +## 接收及处理消息 + +- 群聊接收及处理消息同单聊; + +- 消息体与单聊消息根据 message 的 type 进行区分; + +- 单聊为:chat,群聊为:groupchat,聊天室为:chatroom; + +- 根据消息的类型进行不同处理即可。 + +## 聊天室事件监听 + +可以在注册的监听事件onPresence里监听聊天室相关的事件: + +``` +conn.listen({ + onPresence: function(msg){ + switch(msg.type){ + case 'rmChatRoomMute': + // 解除聊天室一键禁言 + break; + case 'muteChatRoom': + // 聊天室一键禁言 + break; + case 'rmUserFromChatRoomWhiteList': + // 删除聊天室白名单成员 + break; + case 'addUserToChatRoomWhiteList': + // 增加聊天室白名单成员 + break; + case 'deleteFile': + // 删除聊天室文件 + break; + case 'uploadFile': + // 上传聊天室文件 + break; + case 'deleteAnnouncement': + // 删除聊天室公告 + break; + case 'updateAnnouncement': + // 更新聊天室公告 + break; + case 'removeMute': + // 解除禁言 + break; + case 'addMute': + // 禁言 + break; + case 'removeAdmin': + // 移除管理员 + break; + case 'addAdmin': + // 添加管理员 + break; + case 'changeOwner': + // 转让聊天室 + break; + case 'leaveChatRoom': + // 退出聊天室 + break; + case 'memberJoinChatRoomSuccess': + // 加入聊天室 + break; + case 'leave': + // 退出群 + break; + case 'join': + // 加入群 + break; + default: + break; + }} +}) +``` + +------ \ No newline at end of file diff --git a/docs/document/v1/web/demo_react.md b/docs/document/v1/web/demo_react.md index d0c6aff9a..d8d873ef4 100644 --- a/docs/document/v1/web/demo_react.md +++ b/docs/document/v1/web/demo_react.md @@ -4,23 +4,23 @@ 环信即时通讯 Web 端提供示例应用可供体验。你可以按以下步骤体验: -1. [登录 Demo](https://webim-h5.easemob.com/#/login)。 +1. [登录 Demo](https://zq-im-management-hsb.easemob.com/)。 -![img](@static/images/demo/web_react_login.png) + -2. 输入你的手机号,获取验证码,然后输入。 +2. 输入你的登录账号和密码,然后输入。 3. 点击 **登录** 登录 Demo。 ## 代码下载 -下载源代码:[github 源码地址](https://github.com/easemob/webim) +下载源代码:[源码地址](https://downloadsdk.easemob.com/mp/downloads/sdk/private-react-20230918.zip) 欢迎大家提交 PR 改进和修复 Web IM 中的问题。 ## 运行 Web IM 项目 -从 [IM SDK 及 Demo 下载](https://www.easemob.com/download/im) 下载 Web SDK 压缩包,然后解压。解压后在 `demo` 文件夹即为 Web IM 的项目目录。 +下载 Web SDK 压缩包,然后解压。解压后在 `demo` 文件夹即为 Web IM 的项目目录。 1. 安装 Demo 所需的依赖:在终端中运行 `cd demo` 和 `npm install` 命令。 diff --git a/docs/document/v1/web/demo_vue.md b/docs/document/v1/web/demo_vue.md index a63796147..f627af04d 100644 --- a/docs/document/v1/web/demo_vue.md +++ b/docs/document/v1/web/demo_vue.md @@ -2,7 +2,7 @@ -环信即时通讯 Web 端提供示例应用可供体验。你可以按以下步骤体验: + ## 代码下载 -- Vue 2 下载源代码:[github 源码地址](https://github.com/easemob/webim-vue-demo/tree/dev-4.0) -- Vue 3 下载源代码:[github 源码地址](https://github.com/easemob/webim-vue-demo/tree/demo-vue3) +- Vue 2 下载源代码:[github 源码地址](https://downloadsdk.easemob.com/mp/downloads/sdk/private-vue2-20230918.zip) +- Vue 3 下载源代码:[github 源码地址]() 欢迎大家提交 PR 改进和修复 Web IM 中的问题。 ## 运行 Web IM 项目 -从 [github 下载](https://github.com/easemob/webim-vue-demo/tree/dev-4.0) 下载项目代码压缩包,然后解压。解压后,`webim-vue-demo` 文件夹即为 Web IM 的项目目录。 +下载项目代码压缩包,然后解压。解压后,`webim-vue-demo` 文件夹即为 Web IM 的项目目录。 1. 安装 Demo 所需的依赖:在终端中运行 `cd demo` 和 `npm install` 命令。 diff --git a/docs/document/v1/web/group.md b/docs/document/v1/web/group.md new file mode 100644 index 000000000..fea710396 --- /dev/null +++ b/docs/document/v1/web/group.md @@ -0,0 +1,825 @@ +# 群组 + +更新时间:2021-12-31 + +新版文档见:[群组管理](https://docs-im.easemob.com/ccim/web/group1)。 + +环信 Web IM SDK 支持群组功能的集成,集成后可以进行如下操作: + +- 群组管理 + +- 群成员管理 + +- 加群处理 + +- 禁言管理 + +- 黑名单管理 + +- 群消息管理 + +通过这些操作,可以组合帮助您完成多种场景下的 IM 需求。 + +**注意:** + +从 Web SDK V1.4.11 开始,群组管理的接口都已更新了 Rest 版本,V1.4.10 (包括V1.4.10)以下版本仍然保留 XMPP 版本,如果需要继续使用XMPP 版本的接口,请参考[群组管理](https://docs-im.easemob.com/im/400webimintegration/40groupchat) + +**SDK从3.3.0版本开始支持promise, 3.3.0版本之前采用回调的方式,如使用promise报错请检查SDK版本。** + +**注意**:`1、群主+管理员 一起一共不超过100个,也就是不超过99个管理员。2、群组成员最大数(包括群主)取决于所选择的版本,不同版本最大数不同。` + +------ + +------ + +## 群组管理 + +群组管理包含以下处理操作: + +- 获取用户加入的群组列表 + +- 分页获取公开群 + +- 创建群组 + +- 获取群组信息 + +- 修改群组信息 + +- 移除成员 + +- 解散群组 + +- 退出群组 + +所有处理操作的示例下面会一一说明。 + +### 获取用户加入的群组列表 + +调用`getGroup`函数获取当前登录用户加入的群组列表,示例如下: + +``` +// 列出当前登录用户加入的所有群组 +conn.getGroup().then((res) => { + console.log(res) +}) +``` + +------ + +### 分页获取公开群 + +调用`listGroups`函数分页获取APP下所有的公开群组列表,示例如下: + +``` +let limit = 20, + cursor = globalCursor; +let options = { + limit: limit, // 预期每页获取的记录数 + cursor: cursor, // 游标 +}; +conn.listGroups(options).then((res) => { + console.log(res) +}) +``` + +**注意:** + +- cursor: 如果数据还有下一页,API 返回值会包含此字段,传递此字段可获取下一页的数据,默认为`null`,为`null`时获取第一页数据 + +------ + +### 创建群组 + +调用`createGroupNew`函数创建群组,示例代码如下 + +``` +let options = { + data: { + groupname: 'groupName', // 群组名 + desc: 'group description', // 群组描述 + members: ['user1', 'user2'], // 用户名组成的数组 + public: true, // pub等于true时,创建为公开群 + approval: true, // approval为true,加群需审批,为false时加群无需审批 + allowinvites: allowInvites, // true:允许群成员邀请人加入此群,false:只有群主才可以往群里加人 注意公开群(public:true),则不允许群成员邀请别人加入此群 + inviteNeedConfirm: false // 邀请加群,被邀请人是否需要确认。true 为需要被邀请者同意才会进群 + }, + success(res){}, + error(err){}, +}; +conn.createGroupNew(options).then((res) => { + console.log(res) +}) +``` + +**注意:** + +- 创建群组成功后会在回调函数里调用`onCreateGroup`函数 + +------ + +### 获取群组信息 + +调用 `getGroupInfo` 根据群组 ID 获取群组详情,示例如下: + +``` +let options = { + groupId: 'groupId' // 群组id +}; +conn.getGroupInfo(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 修改群组信息 + +只有群组的管理员可以修改群组名称和群组简介,调用`modifyGroup`修改群组信息,示例如下: + +``` +// 修改群信息 +let option = { + groupId: 'groupId', + groupName: 'ChangeTest', // 群组名称 + description: 'Change group information test' // 群组简介 +}; +conn.modifyGroup(option).then((res) => { + console.log(res) +}) +``` + +**注意:** + +- 在获取群组时候就可以获取群管理员的 ID ,从而前端可决定是否显示修改信息按钮。 + +------ + +### 移除群组成员 + +只有群组的管理员可以移除群组成员,调用`removeSingleGroupMember`移除群组成员,示例如下: + +``` +// 移除群组成员 +let option = { + groupId: 'groupId', + username: 'username' // 群组成员名称 +}; +conn.removeSingleGroupMember(option).then((res) => { + console.log(res) +}) +``` + +------ + +### 解散群组 + +- 只有群组的管理员有权限将成员踢出群组; + +- 群组解散后,所有群成员均退出该群。 + +调用`dissolveGroup`解散群组,示例如下: + +``` +// 解散一个群组 +let option = { + groupId: 'groupId' +}; +conn.dissolveGroup(option).then((res) => { + console.log(res) +}) +``` + +**注意:** + +- 在获取群组时候就可以获取群管理员的ID,从而前端可决定是否显示解散按钮。 + +------ + +### 退出群组 + +群成员可以主动退出群组,调用`quitGroup`退出群组,示例如下: + +``` +// 成员主动退出群 +let option = { + groupId: 'groupId' +}; +conn.quitGroup(option).then((res) => { + console.log(res) +}) +``` + +------ + +## 群公告管理 + +群公告管理包含以下处理操作: + +- 上传/修改群公告 + +- 获取群公告 + +所有处理操作的示例下面会一一说明。 + +### 上传/修改群公告 + +调用updateGroupAnnouncement函数上传/修改群公告,示例如下: + +``` +let options = { + groupId: 'groupId', // 群组id + announcement: 'announcement' // 公告内容 +}; +conn.updateGroupAnnouncement(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 获取群公告 + +调用fetchGroupAnnouncement函数获取群公告,示例如下: + +``` +let options = { + groupId: 'groupId' // 群组id +}; +conn.fetchGroupAnnouncement(options).then((res) => { + console.log(res) +}) +``` + +------ + +## 群文件管理 + +群文件管理包含以下处理操作: + +- 上传群文件 + +- 下载群文件 + +- 删除群文件 + +- 获取群文件列表 + +所有处理操作的示例下面会一一说明。 + +### 上传群文件 + +调用uploadGroupSharedFile函数上传群文件,示例如下: + +``` +let options = { + groupId: 'groupId', // 群组id + file: file, // 获取的file文件对象 + onFileUploadProgress: function(resp) {}, // 上传进度的回调 + onFileUploadComplete: function(resp) {}, // 上传完成时的回调 + onFileUploadError: function(e) {}, // 上传失败的回调 + onFileUploadCanceled: function(e) {} // 上传取消的回调 +}; +conn.uploadGroupSharedFile(options); +``` + +------ + +### 下载群文件 + +调用downloadGroupSharedFile函数下载群文件,示例如下: + +``` +let options = { + groupId: 'groupId', // 群组id + fileId: 'fileId', // 文件id + onFileDownloadComplete: function(resp) {}, // 下载成功的回调 + onFileDownloadError: function(e) {}, // 下载失败的回调 +}; +conn.downloadGroupSharedFile(options); +``` + +------ + +### 删除群文件 + +调用deleteGroupSharedFile函数删除群文件,示例如下: + +``` +let options = { + groupId: 'groupId', // 群组id + fileId: 'fileId' // 文件id +}; +conn.deleteGroupSharedFile(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 获取群文件列表 + +调用fetchGroupSharedFileList函数获取群文件列表,示例如下: + +``` +let options = { + groupId: 'groupId' // 群组id +}; +conn.fetchGroupSharedFileList(options).then((res) => { + console.log(res) +}) +``` + +------ + +## 群成员管理 + +群成员管理包含以下处理操作: + +- 查询群组成员 + +- 将成员设为管理员 + +- 将管理员撤销 + +- 获取群组下所有管理员 + +所有处理操作的示例下面会一一说明。 + +### 查询群组成员 + +调用`listGroupMember`函数分页获取当前群组的所有成员,示例如下: + +``` +let pageNum = 1, + pageSize = 1000; +let options = { + pageNum: pageNum, // 页码 + pageSize: pageSize, // 预期每页获取的记录数 + groupId: 'groupId' +}; +conn.listGroupMember(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 将成员设为管理员 + +调用`setAdmin`将成员设为管理员,示例如下: + +``` +let options = { + groupId: "groupId", // 群组id + username: "user" // 用户名 +}; +conn.setAdmin(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 将管理员撤销 + +调用`removeAdmin`将管理员撤销,示例如下: + +``` +let options = { + groupId: "groupId", // 群组id + username: "user" // 用户名 +}; +conn.removeAdmin(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 获取群组所有管理员 + +调用`getGroupAdmin`获取群组下所有管理员,示例如下: + +``` +let options = { + groupId: "groupId" // 群组id +}; +conn.getGroupAdmin(options).then((res) => { + console.log(res) +}) +``` + +------ + +## 加群处理 + +加群包含以下处理操作: + +- 将好友加入群组 + +- 向群组发出入群申请 + +- 同意用户加入群 + +- 拒绝用户加入群 + +所有处理操作的示例下面会一一说明。 + +### 将好友加入群组 + +管理员可以将好友加入群组。调用`inviteToGroup`将好友加入群组,示例如下: + +``` +let option = { + users: ['user1', 'user2'], + groupId: 'groupId' +}; +conn.inviteToGroup(option).then((res) => { + console.log(res) +}) +``` + +------ + +### 向群组发出入群申请 + +调用`joinGroup`向群组发出入群申请,示例如下: + +``` +let options = { + groupId: "groupId", // 群组ID + message: "I am Tom" // 请求信息 +}; +conn.joinGroup(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 同意用户加入群 + +只有管理员才有权限同意用户加入群组的请求。 + +调用`agreeJoinGroup`同意用户加群请求,示例如下: + +``` +let options = { + applicant: 'userId', // 申请加群的用户名 + groupId: 'groupId' // 群组ID +}; +conn.agreeJoinGroup(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 拒绝用户加入群 + +只有管理员才有权限拒绝用户加入群组的请求。 + +调用`rejectJoinGroup`拒绝用户加群请求,示例如下: + +``` +let options = { + applicant: 'user', // 申请加群的用户名 + groupId: 'groupId' // 群组ID +}; +conn.rejectJoinGroup(options).then((res) => { + console.log(res) +}) +``` + +------ + +## 禁言管理 + +禁言管理包含以下处理操作: + +- 将成员禁言 + +- 将成员解除禁言 + +- 获取群组下禁言成员 + +所有处理操作的示例下面会一一说明。 + +### 将成员禁言 + +调用`mute`将成员禁言,示例如下: + +``` +let options = { + username: "user", // 成员用户名 + muteDuration: 886400000, // 禁言的时长,单位是毫秒 + groupId: "groupId" +}; +conn.mute(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 将成员解除禁言 + +调用`removeMute`将成员解除禁言,示例如下: + +``` +let options = { + groupId: "groupId", // 群组ID + username: "user" // 成员用户名 +}; +conn.removeMute(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 获取群组下禁言成员 + +调用`getMuted`获取群组下所有被禁言的成员,示例如下: + +``` +let options = { + groupId: "groupId" // 群组ID +}; +conn.getMuted(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 开启和关闭全员禁言 + +owner和管理员可以开启和关闭全员禁言。 + +``` +//群组中禁言所有成员 +let options = { + groupId: "groupId", //群组id +}; +conn.disableSendGroupMsg(options).then((res) => { + console.log(res) +}) + +//群组中解除所有成员禁言 +conn.enableSendGroupMsg(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 白名单管理 + +可以将用户添加到白名单中,用户白名单在管理员开启了全员禁言时生效,可以运行白名单用户发出消息。 另外可以将用户移出白名单,检查自己是否在白名单中以及获取白名单列表。 + +``` +//添加用户到白名单 +let options = { + groupId: "groupId", // 群组id + users: ["user1", "user2"] // 成员id列表 +}; +conn.addUsersToGroupWhitelist(options); + +//将用户从白名单移除 +let options = { + groupId: "groupId", // 群组id + userName: "user" // 要移除的成员 +} +conn.rmUsersFromGroupWhitelist(options); + +//从服务器获取白名单成员列表 +let options = { + groupId: "groupId" // 群组id +} +conn.getGroupWhitelist(options); + +//查询群成员是否是白名单用户,操作权限:app admin可查询所有用户;app user可查询自己 +let options = { + groupId: "groupId", // 群组id + userName: "user" // 要查询的成员 +} +conn.isGroupWhiteUser(options); +``` + +------ + +## 黑名单管理 + +黑名单管理包含以下处理操作: + +- 将成员加入群黑名单(单个) + +- 将成员加入群黑名单(批量) + +- 将成员移除群组黑名单(单个) + +- 将成员移除群组黑名单(批量) + +- 获取群组黑名单 + +所有处理操作的示例下面会一一说明。 + +### 将成员加入群黑名单(单个) + +调用`groupBlockSingle`将单个成员加入群组黑名单,示例如下: + +``` +let options = { + groupId: 'groupId', // 群组ID + username: 'username' // 将要被加入黑名单的用户名 +}; +conn.groupBlockSingle(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 将成员加入群黑名单(批量) + +调用`groupBlockMulti`将成员批量加入群组黑名单,示例如下: + +``` +let options = { + groupId: 'groupId', // 群组ID + usernames: ['user1', 'user2', ...users] // 将要被加入黑名单的用户名数组 +}; +conn.groupBlockMulti(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 将成员移除群组黑名单(单个) + +调用`removeGroupBlockSingle`将单个成员从群组黑名单中移除,示例如下: + +``` +let options = { + groupId: "groupId", // 群组ID + username: "user" // 需要移除的用户名 +} +conn.removeGroupBlockSingle(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 将成员移除群组黑名单(批量) + +调用`removeGroupBlockMulti`将成员批量从群组黑名单中移除,示例如下: + +``` +let options = { + groupId: "groupId", // 群组ID + username: ["user1", "user2"] // 需要移除的用户名数组 +} +conn.removeGroupBlockMulti(options).then((res) => { + console.log(res) +}) +``` + +------ + +### 获取群组黑名单 + +调用`getGroupBlacklistNew`获取群组黑名单,示例如下: + +``` +// 获取群组黑名单 +let option = { + groupId: 'groupId', +}; +conn.getGroupBlacklistNew(option).then((res) => { + console.log(res) +}) +``` + +------ + +## 群组事件监听 + +可以在注册的监听事件onPresence里监听群组相关的事件: + +``` +conn.listen({ + onPresence: function(msg){ + switch(msg.type){ + case 'rmGroupMute': + // 解除群组一键禁言 + break; + case 'muteGroup': + // 群组一键禁言 + break; + case 'rmUserFromGroupWhiteList': + // 删除群白名单成员 + break; + case 'addUserToGroupWhiteList': + // 增加群白名单成员 + break; + case 'deleteFile': + // 删除群文件 + break; + case 'uploadFile': + // 上传群文件 + break; + case 'deleteAnnouncement': + // 删除群公告 + break; + case 'updateAnnouncement': + // 更新群公告 + break; + case 'removeMute': + // 解除禁言 + break; + case 'addMute': + // 禁言 + break; + case 'removeAdmin': + // 移除管理员 + break; + case 'addAdmin': + // 添加管理员 + break; + case 'changeOwner': + // 转让群组 + break; + case 'direct_joined': + // 直接被拉进群 + break; + case 'leaveGroup': + // 退出群 + break; + case 'memberJoinPublicGroupSuccess': + // 加入公开群成功 + break; + case 'removedFromGroup': + // 从群组移除 + break; + case 'invite_decline': + // 拒绝加群邀请 + break; + case 'invite_accept': + // 接收加群邀请(群含权限情况) + break; + case 'invite': + // 接收加群邀请 + break; + case 'joinPublicGroupDeclined': + // 拒绝入群申请 + break; + case 'joinPublicGroupSuccess': + // 同意入群申请 + break; + case 'joinGroupNotifications': + // 申请入群 + break; + case 'leave': + // 退出群 + break; + case 'join': + // 加入群 + break; + case 'deleteGroupChat': + // 解散群 + break; + default: + break; + }} +}) +``` + +------ + +## 群消息 + +群消息包含以下处理操作: + +- 发送消息 + +- 接收及处理消息 + +所有处理操作下面会一一说明。 + +### 发送消息 + +见[发送消息](https://docs-im.easemob.com/im/web/basics/message#发送消息)。 + +### 接收及处理消息 + +- 群聊接收及处理消息同单聊; + +- 消息体与单聊消息根据 message 的 type 进行区分; + +- 单聊为:chat,群聊为:groupchat,聊天室为:chatroom; + +- 根据消息的类型进行不同处理即可。 \ No newline at end of file diff --git a/docs/document/v1/web/group_attributes.md b/docs/document/v1/web/group_attributes.md index 0bde21297..ebe8b3d82 100644 --- a/docs/document/v1/web/group_attributes.md +++ b/docs/document/v1/web/group_attributes.md @@ -15,7 +15,7 @@ ## 前提条件 - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的接口调用频率限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 diff --git a/docs/document/v1/web/group_manage.md b/docs/document/v1/web/group_manage.md index a402d071d..01051093f 100644 --- a/docs/document/v1/web/group_manage.md +++ b/docs/document/v1/web/group_manage.md @@ -22,8 +22,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的接口调用频率限制,详见 [使用限制](/product/limitation.html)。 -- 了解群组和群成员数量限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 diff --git a/docs/document/v1/web/group_members.md b/docs/document/v1/web/group_members.md index e9c6a123e..c30a65378 100644 --- a/docs/document/v1/web/group_members.md +++ b/docs/document/v1/web/group_members.md @@ -9,18 +9,18 @@ 环信即时通讯 IM Web SDK 提供以下群成员管理功能: - 加入、退出群组 -- 管理群成员自定义属性 - 管理群主及群管理员 - 管理群组白名单 - 管理群组黑名单 - 管理群组禁言 + ## 前提条件 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM API 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 - 了解群成员角色,详见 [群组概述](group_overview.html)。 ## 实现方法 @@ -102,7 +102,7 @@ let option = { }; conn.removeGroupMember(option).then(res => console.log(res)) ``` - + ### 管理群主及群管理员 #### 变更群主 diff --git a/docs/document/v1/web/message.md b/docs/document/v1/web/message.md new file mode 100644 index 000000000..ebb84b93d --- /dev/null +++ b/docs/document/v1/web/message.md @@ -0,0 +1,993 @@ +# 消息管理 + +消息是客户端集成中最重要的功能之一,WebIM 消息的使用方法主要为 : + +- 构造消息 + +- 发送消息 + +- 消息撤回 + +- 接收消息 + +- 处理消息 + +- 消息漫游 + +- 新消息提醒 + +- 消息回执 + +通过对消息的集成,您可以最快速的集成体验 IM 收发消息的流畅体验。 + +## 构造消息 + +``` +let msg = new WebIM.message('txt', id); +msg.set(option); //消息内容option,下面会有详细介绍 +msg.setChatType('groupChat'); //用于设置当前聊天模式为单聊、群聊(groupChat)、聊天室(chatRoom),不设置默认为单聊 +``` + +**注意:** 发送ext 扩展消息,可以没有这个字段,但是如果有,值不能是“ext:null”这种形式,否则出错 + +## 发送消息 + +环信支持向**单聊**、**群组**及**聊天室**中发送: + +- 文本消息 + +- 表情消息 + +- 贴图消息 + +- URL图片消息 + +- 命令消息 + +- 附件消息 + +- 自定义消息 + +多样化的消息类型,覆盖多种场景下的消息需求。 + +### 发送文本消息(单聊、扩展) + +单聊发送文本消息示例如下: + +``` +// 单聊发送文本消息 +function sendPrivateText() { + let id = conn.getUniqueId(); // 生成本地消息id + let msg = new WebIM.message('txt', id); // 创建文本消息 + msg.set({ + msg: 'message content', // 消息内容 + to: 'username', // 接收消息对象(用户id) + chatType: 'singleChat', // 设置为单聊 + ext: { + key: value, + key2: { + key3: value2 + } + }, //扩展消息 + success: function (id, serverMsgId) { + console.log('send private text Success'); + }, + fail: function(e){ + // 失败原因: + // e.type === '603' 被拉黑 + // e.type === '605' 群组不存在 + // e.type === '602' 不在群组或聊天室中 + // e.type === '504' 撤回消息时超出撤回时间 + // e.type === '505' 未开通消息撤回 + // e.type === '506' 没有在群组或聊天室白名单 + // e.type === '501' 消息包含敏感词 + // e.type === '502' 被设置的自定义拦截捕获 + // e.type === '503' 未知错误 + console.log("Send private text error"); + } + }); + conn.send(msg.body); +}; +``` + +### 发送文本消息(群组) + +群组发送文本消息示例如下: + +``` +// 群组发送文本消息 +function sendGroupText() { + let id = conn.getUniqueId(); // 生成本地消息id + let msg = new WebIM.message('txt', id); // 创建文本消息 + let option = { + msg: 'message content', // 消息内容 + to: 'group id', // 接收消息对象(群组id) + chatType: 'groupChat', // 群聊类型设置为群聊 + ext: {}, // 扩展消息 + success: function () { + console.log('send room text success'); + }, // 对成功的相关定义,sdk会将消息id登记到日志进行备份处理 + fail: function () { + console.log('failed'); + } // 对失败的相关定义,sdk会将消息id登记到日志进行备份处理 + }; + msg.set(option); + conn.send(msg.body); +}; +``` + +### 发送文本消息(聊天室) + +聊天室发送文本消息示例如下: + +``` +// 聊天室发送文本消息 +function sendRoomText() { + let id = conn.getUniqueId(); // 生成本地消息id + let msg = new WebIM.message('txt', id); // 创建文本消息 + let option = { + msg: 'message content', // 消息内容 + to: 'chatroom id', // 接收消息对象(聊天室id) + chatType: 'chatRoom', // 群聊类型设置为聊天室 + ext: {}, // 扩展消息 + success: function () { + console.log('send room text success'); + }, // 对成功的相关定义,sdk会将消息id登记到日志进行备份处理 + fail: function () { + console.log('failed'); + } // 对失败的相关定义,sdk会将消息id登记到日志进行备份处理 + }; + msg.set(option); + conn.send(msg.body); +}; +``` + +:::tip +单聊和群聊的表现示例基本一样,区别在于接受消息的对象不同,单聊 to 的对象为**用户 ID** ,群组/聊天室 to 的对象为**群组/聊天室 ID** +::: +------ + +### 发送表情消息 + +发送表情同发送文本消息,需要在对方客户端将表情文本进行解析成图片。 + +单聊发送表情消息的代码示例如下: + +``` +conn.listen({ + onEmojiMessage: function (message) { + console.log('Emoji'); + var data = message.data; + for(var i = 0 , l = data.length ; i < l ; i++){ + console.log(data[i]); + } + }, //收到表情消息 +}); +// 单聊发送文本消息 +var sendPrivateText = function () { + var id = conn.getUniqueId(); // 生成本地消息id + var msg = new WebIM.message('txt', id); // 创建文本消息 + msg.set({ + msg: 'message content', // 消息内容 + to: 'username', // 接收消息对象(用户id) + chatType: 'singleChat', + success: function (id, serverMsgId) { + console.log('send private text Success'); + }, + fail: function(e){ + console.log("Send private text error"); + } + }); + conn.send(msg.body); +}; +``` + +:::tip +当为 WebIM 添加了 Emoji 属性后,若发送的消息含 WebIM.Emoji 里特定的字符串,connection 就会自动将这些字符串和其它文字按顺序组合成一个数组,每一个数组元素的结构为 {type:'emoji(或者txt)',data:'msg(或者src)'} + +当 type='emoji' 时,data 表示**表情图像的路径**; + +当 type='txt' 时,data 表示**文本消息**。 +::: +------ + +### 发送贴图消息 + +Web IM SDK本身不支持截图,使用下述代码可以实现用户粘贴图片至输入框后发送。 + +单聊发送贴图消息的代码示例如下: + +``` +// 单聊贴图发送 +document.addEventListener('paste', function (e) { + if (e.clipboardData && e.clipboardData.types) { + if (e.clipboardData.items.length > 0) { + if (/^image\/\w+$/.test(e.clipboardData.items[0].type)) { + var blob = e.clipboardData.items[0].getAsFile(); + var url = window.URL.createObjectURL(blob); + var id = conn.getUniqueId(); // 生成本地消息id + var msg = new WebIM.message('img', id); // 创建图片消息 + msg.set({ + file: {data: blob, url: url}, + to: 'username', // 接收消息对象 + chatType: 'singleChat', + onFileUploadError: function (error) { + console.log('Error'); + }, + onFileUploadComplete: function (data) { + console.log('Complete'); + }, + success: function (id) { + console.log('Success'); + }, + fail: function(e){ + console.log("Fail"); //如禁言、拉黑后发送消息会失败 + } + }); + conn.send(msg.body); + } + } + } +}); +``` + +------ + +### 发送URL图片消息 + +App端需要开发者自己实现下载,Web端需要在 WebIMConfig.js中 设置 `useOwnUploadFun: true`。 + +单聊通过URL发送图片消息的代码示例如下: + +``` +// 单聊通过URL发送图片消息 + var sendPrivateUrlImg = function () { + var id = conn.getUniqueId(); // 生成本地消息id + var msg = new WebIM.message('img', id); // 创建图片消息 + var option = { + body: { + type: 'file', + url: url, + size: { + width: msg.width, + height: msg.height, + }, + length: msg.length, + filename: msg.file.filename, + filetype: msg.filetype + }, + to: 'username', // 接收消息对象 + }; + msg.set(option); + conn.send(msg.body); + } +``` + +------ + +### 发送命令消息 + +发送命令消息的代码示例如下: + +``` +var id = conn.getUniqueId(); //生成本地消息id +var msg = new WebIM.message('cmd', id); //创建命令消息 + +msg.set({ + to: 'username', //接收消息对象 + action : 'action', //用户自定义,cmd消息必填 + ext :{'extmsg':'extends messages'}, //用户自扩展的消息内容(群聊用法相同) + success: function ( id,serverMsgId ) {}, //消息发送成功回调 + fail: function(e){ + console.log("Fail"); //如禁言、拉黑后发送消息会失败 + } +}); + +conn.send(msg.body); +``` + +------ + +### 发送附件消息 + +附件消息是消息中重要的消息类型,附件消息主要包括以下几种: + +- 图片消息 + +- 文件消息 + +- 音频消息 + +- 视频消息 + +#### 发送附件消息,SDK 自动分两步完成: + +1. 上传附件到服务器,并得到服务返回的附件信息等; +2. 发送附件消息,消息体包含附件的基本信息、服务器路径、secret 等。 + +:::tip +web端和小程序发送附件消息是有区别的,小程序发送附件消息需要自己将附件上传到环信服务器,下面以发送图片消息展示小程序怎样发送附件消息 +::: + +单聊发送图片消息示例如下: + +``` +// web单聊发送图片消息 +var sendPrivateImg = function () { + var id = conn.getUniqueId(); // 生成本地消息id + var msg = new WebIM.message('img', id); // 创建图片消息 + var input = document.getElementById('image'); // 选择图片的input + var file = WebIM.utils.getFileUrl(input); // 将图片转化为二进制文件 + var allowType = { + 'jpg': true, + 'gif': true, + 'png': true, + 'bmp': true + }; + if (file.filetype.toLowerCase() in allowType) { + var option = { + file: file, + length: '3000', // 视频文件时,单位(ms) + ext: { + file_length: file.data.size // 文件大小 + }, + to: 'username', // 接收消息对象 + chatType: 'singleChat', // 设置为单聊 + onFileUploadError: function () { // 消息上传失败 + console.log('onFileUploadError'); + }, + onFileUploadProgress: function (e) { // 上传进度的回调 + console.log(e) + }, + onFileUploadComplete: function () { // 消息上传成功 + console.log('onFileUploadComplete'); + }, + success: function () { // 消息发送成功 + console.log('Success'); + }, + fail: function(e){ + console.log("Fail"); //如禁言、拉黑后发送消息会失败 + }, + flashUpload: WebIM.flashUpload + }; + msg.set(option); + conn.send(msg.body); + } +}; + +// 小程序单聊发送图片消息 +sendImage(){ + const me = this; + wx.chooseImage({ + count: 1, + sizeType: ["original", "compressed"], + sourceType: ["album"], + success(res){ + me.upLoadImage(res); + } + }); +} +upLoadImage(res){ + const me = this; + let tempFilePaths = res.tempFilePaths; + let token = WebIM.conn.context.accessToken + wx.getImageInfo({ + src: res.tempFilePaths[0], + success(res){ + let allowType = {jpg: true, gif: true, png: true, bmp: true}; + let str = WebIM.config.appkey.split("#"); + let width = res.width; + let height = res.height; + let index = res.path.lastIndexOf("."); + let filetype = (~index && res.path.slice(index + 1)) || ""; + let domain = wx.WebIM.conn.apiUrl + '/' + if(filetype.toLowerCase() in allowType){ + wx.uploadFile({ + url: domain + str[0] + "/" + str[1] + "/chatfiles", + filePath: tempFilePaths[0], + name: "file", + header: { + "Content-Type": "multipart/form-data", + Authorization: "Bearer " + token + }, + success(res){ + if(res.statusCode === 400){ + // 图片上传阿里云检验不合法 + let errData = JSON.parse(res.data); + if (errData.error === 'content improper') { + wx.showToast({ + title: '图片不合法' + }); + return + } + } + let data = res.data; + let dataObj = JSON.parse(data); + let id = WebIM.conn.getUniqueId(); // 生成本地消息 id + let msg = new WebIM.message(msgType.IMAGE, id); + let file = { + type: msgType.IMAGE, + size: { + width: width, + height: height + }, + url: dataObj.uri + "/" + dataObj.entities[0].uuid, + filetype: filetype, + filename: tempFilePaths[0] + }; + msg.set({ + apiUrl: WebIM.config.apiURL, + body: file, + from: me.data.username.myName, + to: me.getSendToParam(), + chatType: me.data.chatType, + success: function (argument) {}, + fail: function(e){ + console.log("Fail"); //如禁言、拉黑后发送消息会失败 + } + }); + WebIM.conn.send(msg.body); + } + }); + } + } +}); +} +``` + +单聊发送文件消息示例如下: + +``` +// 单聊发送文件消息 +var sendPrivateFile = function () { + var id = conn.getUniqueId(); // 生成本地消息id + var msg = new WebIM.message('file', id); // 创建文件消息 + var input = document.getElementById('file'); // 选择文件的input + var file = WebIM.utils.getFileUrl(input); // 将文件转化为二进制文件 + var allowType = { + 'jpg': true, + 'gif': true, + 'png': true, + 'bmp': true, + 'zip': true, + 'txt': true, + 'doc': true, + 'pdf': true + }; + if (file.filetype.toLowerCase() in allowType) { + var option = { + file: file, + to: 'username', // 接收消息对象 + chatType: 'singleChat', // 设置单聊 + onFileUploadError: function () { // 消息上传失败 + console.log('onFileUploadError'); + }, + onFileUploadProgress: function (e) { // 上传进度的回调 + console.log(e) + }, + onFileUploadComplete: function () { // 消息上传成功 + console.log('onFileUploadComplete'); + }, + success: function () { // 消息发送成功 + console.log('Success'); + }, + fail: function(e){ + console.log("Fail"); //如禁言、拉黑后发送消息会失败 + }, + flashUpload: WebIM.flashUpload, + ext: {file_length: file.data.size} + }; + msg.set(option); + conn.send(msg.body); + } +}; +``` + +单聊发送音频消息示例如下: + +``` +// 单聊发送音频消息 +var sendPrivateAudio = function () { + var id = conn.getUniqueId(); // 生成本地消息id + var msg = new WebIM.message('audio', id); // 创建音频消息 + var input = document.getElementById('audio'); // 选择音频的input + var file = WebIM.utils.getFileUrl(input); // 将音频转化为二进制文件 + var allowType = { + 'mp3': true, + 'amr': true, + 'wmv': true + }; + if (file.filetype.toLowerCase() in allowType) { + var option = { + file: file, + length: '3', // 音频文件时长,单位(s) + to: 'username', // 接收消息对象 + chatType: 'singleChat', // 设置单聊 + onFileUploadError: function () { // 消息上传失败 + console.log('onFileUploadError'); + }, + onFileUploadProgress: function (e) { // 上传进度的回调 + console.log(e) + }, + onFileUploadComplete: function () { // 消息上传成功 + console.log('onFileUploadComplete'); + }, + success: function () { // 消息发送成功 + console.log('Success'); + }, + fail: function(e){ + console.log("Fail"); //如禁言、拉黑后发送消息会失败 + }, + flashUpload: WebIM.flashUpload, + ext: {file_length: file.data.size} + }; + msg.set(option); + conn.send(msg.body); + } +}; +``` + +单聊发送视频消息示例如下: + +``` +// 单聊发送视频消息 +var sendPrivateVideo = function () { + var id = conn.getUniqueId(); // 生成本地消息id + var msg = new WebIM.message('video', id); // 创建视频消息 + var input = document.getElementById('video'); // 选择视频的input + var file = WebIM.utils.getFileUrl(input); // 将视频转化为二进制文件 + var allowType = { + 'mp4': true, + 'wmv': true, + 'avi': true, + 'rmvb':true, + 'mkv':true + }; + if (file.filetype.toLowerCase() in allowType) { + var option = { + file: file, + to: 'username', // 接收消息对象 + chatType: 'singleChat', // 设置为单聊 + onFileUploadError: function () { // 消息上传失败 + console.log('onFileUploadError'); + }, + onFileUploadProgress: function (e) { // 上传进度的回调 + console.log(e) + }, + onFileUploadComplete: function () { // 消息上传成功 + console.log('onFileUploadComplete'); + }, + success: function () { // 消息发送成功 + console.log('Success'); + }, + fail: function(e){ + console.log("Fail"); // 如禁言、拉黑后发送消息会失败 + }, + flashUpload: WebIM.flashUpload, + ext: {file_length: file.data.size} + }; + msg.set(option); + conn.send(msg.body); + } +}; +``` + +### 发送自定义消息 + +单聊发送自定义消息示例如下: + +``` +var sendCustomMsg = function () { + var id = conn.getUniqueId(); // 生成本地消息id + var msg = new WebIM.message('custom', id); // 创建自定义消息 + var customEvent = "customEvent"; // 创建自定义事件 + var customExts = {}; // 消息内容,key/value 需要 string 类型 + msg.set({ + to: 'username', // 接收消息对象(用户id) + customEvent, + customExts, + ext:{}, // 消息扩展 + chatType: 'singleChat', // 设置聊天类型 单聊 群聊 聊天室 + success: function (id, serverMsgId) {}, + fail: function(e){} + }); + conn.send(msg.body); +}; +``` + +------ + +## 消息撤回 + + +``` +/** + * 发送撤回消息 + * @param {Object} option - + * @param {Object} option.mid - 回撤消息id + * @param {Object} option.to - 消息的接收方 + * @param {Object} option.type - chat(单聊) groupchat(群组) chatroom(聊天室) + * @param {Object} option.success - 撤回成功的回调 + * @param {Object} option.fail- 撤回失败的回调(超过两分钟) + */ +WebIM.conn.recallMessage(option) +``` + +------ + +## 接收消息 + +查看回调函数,接收各类消息的回调函数代码如下: + +``` +conn.listen({ + onOpened: function () {}, //连接成功回调 + onClosed: function () {}, //连接关闭回调 + onTextMessage: function ( message ) {}, //收到文本消息 + onEmojiMessage: function ( message ) {}, //收到表情消息 + onPictureMessage: function ( message ) {}, //收到图片消息 + onCmdMessage: function ( message ) {}, //收到命令消息 + onAudioMessage: function ( message ) {}, //收到音频消息 + onLocationMessage: function ( message ) {},//收到位置消息 + onFileMessage: function ( message ) {}, //收到文件消息 + onCustomMessage: function ( message ) {}, //收到自定义消息 + onVideoMessage: function (message) { + var node = document.getElementById('privateVideo'); + var option = { + url: message.url, + headers: { + 'Accept': 'audio/mp4' + }, + onFileDownloadComplete: function (response) { + var objectURL = WebIM.utils.parseDownloadResponse.call(conn, response); + node.src = objectURL; + }, + onFileDownloadError: function () { + console.log('File down load error.') + } + }; + WebIM.utils.download.call(conn, option); + }, //收到视频消息 + onPresence: function ( message ) {}, //处理“广播”或“发布-订阅”消息,如联系人订阅请求、处理群组、聊天室被踢解散等消息 + onRoster: function ( message ) {}, //处理好友申请 + onInviteMessage: function ( message ) {}, //处理群组邀请 + onOnline: function () {}, //本机网络连接成功 + onOffline: function () {}, //本机网络掉线 + onError: function ( message ) {}, //失败回调 + onBlacklistUpdate: function (list) { //黑名单变动 + // 查询黑名单,将好友拉黑,将好友从黑名单移除都会回调这个函数,list则是黑名单现有的所有好友信息 + console.log(list); + }, + onRecallMessage: function( message ){}, //收到消息撤回回执 + onReceivedMessage: function(message){}, //收到消息送达服务器回执 + onDeliveredMessage: function(message){}, //收到消息送达客户端回执 + onReadMessage: function(message){}, //收到消息已读回执 + onCreateGroup: function(message){}, //创建群组成功回执(需调用createGroupNew) + onMutedMessage: function(message){}, //如果用户在A群组被禁言,在A群发消息会走这个回调并且消息不会传递给群其它成员 + onChannelMessage: function(message){} //收到整个会话已读的回执,在对方发送channel ack时会在这个回调里收到消息 +}); +``` + +------ + +## 处理消息 + +这里主要介绍几种特殊的消息处理示例 + +- 表情消息 + +- 图片消息 + +- 音频消息 + +### 表情消息 + +收到表情消息的处理示例: + +``` +conn.listen({ + onEmojiMessage: function (message) { + console.log('Emoji'); + var data = message.data; + for(var i = 0 , l = data.length ; i < l ; i++){ + console.log(data[i]); + } + }, //收到表情消息 +}); +``` + +**注意:**当为 WebIM 添加了 Emoji 属性后,若发送的消息含 WebIM.Emoji 里特定的字符串,connection 就会自动将这些字符串和其它文字按顺序组合成一个数组,每一个数组元素的结构为 **{type:'emoji(或者txt)',data:type}** + +当 type='emoji' 时,data 表示**表情图像的路径**; + +当 type='txt' 时,data 表示**文本消息**。 + +### 图片消息 + +收到图片消息的处理示例: + +``` +conn.listen({ + onPictureMessage: function (message) { + console.log("Location of Picture is ", message.url); + }, //收到图片消息 +}); +``` + +### 音频消息 + +收到音频消息的处理示例: + +``` +conn.listen({ + onAudioMessage: function ( message ) { + // 在这里接收音频消息 + } +}) +// 小程序播放 +playAudio(message){ + let audioCtx = wx.createInnerAudioContext(); + let curl = '' + wx.downloadFile({ + url: message.url, + header: { + "X-Requested-With": "XMLHttpRequest", + Accept: "audio/mp3", + Authorization: "Bearer " + this.data.msg.msg.token + }, + success(res){ + curl = res.tempFilePath; + audioCtx.src = curl; + audioCtx.play(); + }, + fail(e){ + wx.showToast({ + title: "下载失败", + duration: 1000 + }); + } +}); + +// web +addAudioMessage: (message, bodyType) => { + return (dispatch, getState) => { + let options = { + url: message.url, + headers: { + Accept: 'audio/mp3' + }, + onFileDownloadComplete: function (response) { + let objectUrl = WebIM.utils.parseDownloadResponse.call(WebIM.conn, response) + message.audioSrcUrl = message.url + message.url = objectUrl + }, + onFileDownloadError: function () {} + } + WebIM.utils.download.call(WebIM.conn, options) + } +} +``` + +**注意:** + +- 对于图片、语音消息需要先进行下载,然后进行显示或者播放处理。 + +#### API + +示例中使用到的 API + +- [listen](http://webim-h5.easemob.com/jsdoc/out/connection.html#listen) + +------ + +## 消息漫游 + +漫游消息,`SDK增值功能`。 + +``` +/** + * 获取对话历史消息 支持Promise返回 + * @param {Object} options + * @param {String} options.queue - 对方用户id(如果用户id内含有大写字母请改成小写字母)/群组id/聊天室id + * @param {String} options.count - 每次拉取条数 + * @param {Boolean} options.isGroup - 是否是群聊,默认为false + * @param {String} options.start - (非必需)起始位置的消息id,默认从最新的一条开始 + * @param {Function} options.success + * @param {Funciton} options.fail + */ +var options = { + queue: "test1", //需特别注意queue属性值为大小写字母混合,以及纯大写字母,会导致拉取漫游为空数组,因此注意将属性值装换为纯小写 + isGroup: false, + count: 10, + success: function(res){ + console.log(res) //获取拉取成功的历史消息 + }, + fail: function(){} +} +WebIM.conn.fetchHistoryMessages(options) +``` + +PS:如需重置拉取历史消息接口的游标可以通过:“WebIM.conn.mr_cache = []” 方法重置。 + +------ + +## 新消息提示 + +SDK 在收到新消息时会直接转发给登录用户,接收到消息后,Demo 中会在好友或者群组的后面显示红色消息数,具体样式开发者可自行处理。 + +------ + +## 会话列表 + +``` +需联系商务同事单独开通 +``` + +### 获取会话列表 + +当和一个用户或者在一个群中发消息后,就会自动把对方加到会话列表中,可以通过调用getSessionList去查询会话列表。建议一个页面只需要在初始时调用一次。使用该功能需要联系您的商务经理进行开通。(您可以在环信通讯云管理后台首页,扫描二维码联系您的商务经理) 特别注意:登陆ID不要为大小写混用的ID,拉取会话列表大小写ID混用会出现拉取会话列表为空。 + +``` +WebIM.conn.getSessionList().then((res) => { + console.log(res) + /** + 返回参数说明 + channel_infos - 所有会话 + channel_id - 会话id, username@easemob.com表示单聊,groupid@conference.easemob.com表示群聊 + meta - 最后一条消息 + unread_num - 当前会话的未读消息数 + + data{ + channel_infos:[ + { + channel_id: 'easemob-demo#chatdemoui_username@easemob.com', + meta: {}, + unread_num: 0 + }, + { + channel_id: 'easemob-demo#chatdemoui_93734273351681@conference.easemob.com', + meta: { + from: "easemob-demo#chatdemoui_zdtest@easemob.com/webim_1610159114836", + id: "827197124377577640", + payload: "{"bodies":[{"msg":"1","type":"txt"}],"ext":{},"from":"zdtest","to":"93734273351681"}", + timestamp: 1610161638919, + to: "easemob-demo#chatdemoui_93734273351681@conference.easemob.com" + }, + unread_num: 0 + } + ] + } + */ + +}) +``` + +当需要清空会话的未读消息数时,可以查看消息回执中channel ack + +### 删除会话 + +可以通过调用 deleteSession 去删除一个会话。 + +``` +WebIM.conn.deleteSession({ + channel: 'userID', // 会话 ID(对方的 userID 或群组 ID)。 + chatType: 'singleChat', // 会话类型 singleChat(单聊) groupChat(群聊)。 + deleteRoam: true, // 是否同时删除服务端漫游消息。 +}) +``` + +------ + +## 消息回执 + +单聊: + +- 已送达回执:在 webim.config.js 中配置 delivery 为 true ,在收到消息时会自动发送已送达回执,对方收到已送达回执的回调函数是 onDeliveredMessage + +- 已读回执: + +1. 当认为用户已读某条(些)消息时,可以生成已读回执,发送给对方,对方会在 onReadMessage 回调里收到已读回执 +2. 也可以针对整个会话回复channel ack消息,表示整个会话的消息都已读。此回执消息是为了清空通过getSessionList获取会话列表中未读数的,比如调用getSessionList获取到会话列表,其中一个会话的未读消息数是5,那么可以在点击这个会话的时候回复一个channel消息,这个会话的未读数就会清零。 + +**单聊发送已读回执** + +``` +var bodyId = message.id; // 需要发送已读回执的消息id +var msg = new WebIM.message('read',conn.getUniqueId()); +msg.set({ + id: bodyId + ,to: message.from +}); +conn.send(msg.body); +``` + +**群聊已读回执**`SDK增值功能`: + +- 发送群可以收已读回执的消息 (需要群主或管理员权限) + +``` +sendGroupReadMsg = () => { + let id = conn.getUniqueId(); // 生成本地消息id + let msg = new WebIM.message('txt', id); // 创建文本消息 + msg.set({ + msg: 'message content', // 消息内容 + to: 'groupId' + chatType: 'groupChat', // 设置为群聊 + success: function (id, serverMsgId) { + console.log('send private text Success'); + }, + fail: function(e){ + console.log("Send private text error"); + } + }); + msg.body.msgConfig = { allowGroupAck: true } // 设置此消息需要已读回执 + conn.send(msg.body); +} + +``` + +- 收到需要回执的消息后发送回执 + +``` +sendReadMsg = () => { + let msg = new WebIM.message("read", WebIM.conn.getUniqueId()); + msg.set({ + id: message.id, // 需要发送已读回执的消息id + to: message.from, // 消息的发送方 + msgConfig: { allowGroupAck: true }, + ackContent: JSON.stringify({}) // 回执内容 + }) + msg.setChatType('groupChat') + WebIM.conn.send(msg.body); +} +``` + +- 监听收到群组消息回执:分两种情况 1、正常在线时可以在 onReadMessage 函数里监听到回执,2、离线时收到群组消息回执,登录后会在onStatisticMessage函数里监听到回执 + +``` +// 在线时可以在onReadMessage里监听 +onReadMessage: (message) => { + const { mid } = message; + const msg = { + id: mid + }; + if(message.groupReadCount){ + // 消息阅读数 + msg.groupReadCount = message.groupReadCount[message.mid]; + } +} + +// 离线时收到回执,登录后会在这里监听到 +onStatisticMessage: (message) => { + let statisticMsg = message.location && JSON.parse(message.location); + let groupAck = statisticMsg.group_ack || []; +} +``` + +- 查看读过消息的用户 + +``` +WebIM.conn.getGroupMsgReadUser({ + msgId, // 消息id + groupId // 群组id +}).then((res)=>{ + console.log(res) +}) +``` + +**发送整个会话已读回执** + +``` +var msg = new WebIM.message('channel',conn.getUniqueId()); +msg.set({ + to: 'username' +}); + +// 如果是群聊 +msg.set({ + to: 'groupid', + chatType: 'groupChat' +}); + +conn.send(msg.body); +``` \ No newline at end of file diff --git a/docs/document/v1/web/message_receipt.md b/docs/document/v1/web/message_receipt.md index 3f0694747..8b5050e1a 100644 --- a/docs/document/v1/web/message_receipt.md +++ b/docs/document/v1/web/message_receipt.md @@ -4,7 +4,7 @@ 单聊会话支持消息送达回执、会话已读回执和消息已读回执,发送方发送消息后可及时了解接收方是否及时收到并阅读了信息,也可以了解整个会话是否已读。 -群聊会话只支持消息已读回执。群主和群管理员在发送消息时,可以设置该消息是否需要已读回执。仅旗舰版及以上版本支持群消息已读回执功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +群聊会话只支持消息已读回执。群主和群管理员在发送消息时,可以设置该消息是否需要已读回执,私有部署即时通讯服务默认支持并开通该功能。 本文介绍如何使用环信即时通讯 IM Android SDK 实现单聊和群聊的消息回执功能。 @@ -35,9 +35,8 @@ 开始前,请确保满足以下要求: -- 已经集成和初始化环信 IM SDK,并实现了注册账号和登录功能。详情请参见 [快速开始](quickstart.html)。 -- 了解 [使用限制](/product/limitation.html) 中的 API 调用频率限制。 -- 群消息已读回执功能仅在环信 IM 旗舰版及以上版本支持该功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +- 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 @@ -147,7 +146,7 @@ conn.addEventHandler("customEvent", { 对于群聊,群主和群管理员发送消息时,可以设置该消息是否需要已读回执。若需要,每个群成员在阅读消息后,SDK 均会发送已读回执,即阅读该消息的群成员数量即为已读回执的数量。 -仅旗舰版及以上版本支持群消息已读回执功能。若要使用该功能,需在[环信即时通讯云控制台](https://console.easemob.com/user/login)开通。 +私有部署即时通讯服务默认支持并开通群消息已读回执功能。 1. 群主或群管理员发送消息时若需已读回执,需设置 `allowGroupAck` 为 `true`: diff --git a/docs/document/v1/web/message_retrieve.md b/docs/document/v1/web/message_retrieve.md index e1fc11af0..f879a8ae6 100644 --- a/docs/document/v1/web/message_retrieve.md +++ b/docs/document/v1/web/message_retrieve.md @@ -4,28 +4,26 @@ 环信即时通讯 IM 提供消息漫游功能,即将用户的所有会话的历史消息保存在消息服务器,用户在任何一个终端设备上都能获取到历史信息,使用户在多个设备切换使用的情况下也能保持一致的会话场景。本文介绍如何实现用户从消息服务器获取会话和消息。 -:::tip -本文介绍的功能均为增值服务,需在[环信即时通讯 IM 管理后台](https://console.easemob.com/user/login)开通。 - -::: ## 技术原理 利用环信即时通讯 IM SDK 可从服务器获取会话和历史消息。 - +- `getHistoryMessages` 按服务器接收消息的时间顺序获取服务器上保存的指定会话中的消息; + ## 前提条件 开始前,请确保已完成 SDK 初始化并连接到服务器,详见 [快速开始](quickstart.html)。 ## 实现方法 - + + +### 从服务器获取指定会话的历史消息 + +你可以调用 `getHistoryMessages` 方法从服务器获取指定会话的消息(消息漫游)。你可以指定消息查询方向,即明确按时间顺序或逆序获取。为确保数据可靠,我们建议你每次最多获取 50 条消息,可多次获取。拉取后,SDK 会自动将消息更新到本地数据库。 + +```javascript +let options = { + // 对方的用户 ID 或者群组 ID 或聊天室 ID。 + targetId: "user1", + // 每页期望获取的消息条数。取值范围为 [1,50],默认值为 20。 + pageSize: 20, + // 查询的起始消息 ID。若该参数设置为 `-1`、`null` 或空字符串,从最新消息开始。 + cursor: -1, + // 会话类型:(默认) `singleChat`:单聊;`groupChat`:群聊。 + chatType: "groupChat", + // 消息搜索方向:(默认)`up`:按服务器收到消息的时间的逆序获取;`down`:按服务器收到消息的时间的正序获取。 + searchDirection: "up", +}; +WebIM.conn + .getHistoryMessages(options) + .then((res) => { + // 成功获取历史消息。 + console.log(res); + }) + .catch((e) => { + // 获取失败。 + }); +``` \ No newline at end of file diff --git a/docs/document/v1/web/message_send_receive.md b/docs/document/v1/web/message_send_receive.md index 6b38471a7..de7489526 100644 --- a/docs/document/v1/web/message_send_receive.md +++ b/docs/document/v1/web/message_send_receive.md @@ -9,8 +9,8 @@ - 位置消息; - 透传消息; - 自定义消息; -- 合并消息; -- 定向消息。 + :::tip 对于聊天室消息,环信即时通讯提供消息分级功能,将消息的优先级划分为高、普通和低三种级别,高优先级的消息会优先送达。你可以在创建消息时对指定聊天室消息类型或指定成员的消息设置为高优先级,确保这些消息优先送达。这种方式确保在聊天室内消息并发量很大或消息发送频率过高时,重要消息能够优先送达,从而提升重要消息的可靠性。 @@ -42,7 +42,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 ## 实现方法 @@ -162,7 +162,7 @@ conn.addEventHandler("eventName", { ### 撤回消息 -发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在[环信即时通讯云控制台](https://console.easemob.com/user/login)的**功能配置** > **功能配置总览** > **基础功能** 页面设置消息撤回时长,该时长不超过 7 天。 +发送方可以撤回一条发送成功的消息。默认情况下,发送方可撤回发出 2 分钟内的消息。你可以在环信即时通讯云控制台的**服务管理** > **服务概览** 页面设置消息撤回时长,该时长不超过 7 天。 ```javascript let option = { @@ -267,7 +267,7 @@ function sendPrivateAudio() { #### 发送图片消息 -对于图片消息,服务器会根据用户设置的 `thumbnailHeight` 和 `thumbnailWidth` 参数自动生成图片的缩略图。若这两个参数未传,则图片的高度和宽度均默认为 170 像素。你也可以在 [环信即时通讯控制台](https://console.easemob.com/user/login)的 `服务概览` 页面的 `设置` 区域修改该默认值。 +对于图片消息,服务器会根据用户设置的 `thumbnailHeight` 和 `thumbnailWidth` 参数自动生成图片的缩略图。若这两个参数未传,则图片的高度和宽度均默认为 170 像素。你也可以在 环信即时通讯控制台的 **应用概览>应用详情** 页面的 `应用设置` 区域修改该默认值。 请参考以下代码示例创建和发送图片消息: @@ -656,7 +656,7 @@ function sendCustomMsg() { }); } ``` - + ### 使用消息扩展 如果上述消息类型无法满足要求,你可以使用消息扩展为消息添加属性。这种情况可用于更复杂的消息传递场景,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 diff --git a/docs/document/v1/web/multi_device.md b/docs/document/v1/web/multi_device.md index 6c1399035..fa2e4503d 100644 --- a/docs/document/v1/web/multi_device.md +++ b/docs/document/v1/web/multi_device.md @@ -9,11 +9,11 @@ - 子区相关操作; - 会话相关操作。 -环信服务器提供 RESTful 接口[查询每个账号已登录设备列表](account_system.html#获取指定账号的在线登录设备列表)以及[将账号从已登录设备强制下线](account_system.html#强制下线)。 +环信服务器提供 RESTful 接口[查询每个账号已登录设备列表](/document/v1/server-side/account_system.html#获取指定账号的在线登录设备列表)以及[将账号从已登录设备强制下线](/document/v1/server-side/account_system.html#强制下线)。 多端登录时,即时通讯 IM 每端默认最多支持 4 个设备同时在线。如需增加支持的设备数量,可以联系环信即时通讯 IM 的商务经理。 -你可以在环信控制台的**功能配置** > **功能配置总览**页面的**基础功能**页签下点击**多端多设备在线**操作栏中的**设置**,在弹出的对话框中设置设置各端设备的数量: +在环信控制台的**服务管理** > **服务概览**页面,点击**多端多设备在线**对应的**设置**。在弹出的对话框中点击 **新增自定义平台**,在**添加自定义平台**对话框中设置**设备平台**和**设备数量**。 ![img](@static/images/common/multidevice_device_count.png) @@ -26,7 +26,7 @@ -
-

3.9.1

+

4.1.2

-

下载 SDK 及 Demo 体验 Demo

+

下载 SDK 及 Demo 体验 Demo

-

查看

+

查看

-

Web

+

iOS

-

4.0.4

+

4.1.1

-

• React: 下载 SDK 及 Demo 体验 Demo
• Vue 2: 下载 SDK 及 Demo
• Vue 3: 下载 SDK 及 Demo

+

下载 SDK 及 Demo 

-

查看

+

查看

-

iOS

+

Web

-

3.9.1

+

4.2.0

-

下载 SDK 及 Demo 

+

• React: 下载 SDK 及 Demo 体验 Demo
• Vue 2: 下载 SDK 及 Demo
• Vue 3: 下载 SDK 及 Demo

-

查看

+

查看

-

1.0.2

+

1.2.0

-

下载 SDK

+

下载 SDK

-

查看

+

查看

-

查看

+

查看

-

查看

+

查看

-

4.0.4

+

4.2.0

-

下载 SDK 及 Demo

+

下载 SDK 及 Demo

-

查看

+

查看

-

4.0.4

+

4.2.0

-

下载 SDK 及 Demo

+

下载 SDK 及 Demo

-

查看

+

查看

-

3.9.0

+

1.2.0

+
+

下载 SDK

-

下载 SDK

+

查看

 

Flutter

-

3.9.0+2

+

4.1.0

-

下载 SDK

+

下载 SDK

-

查看

+

查看

-

0.6.3

+

0.7.5

-

下载 SDK

+

下载 SDK

-

查看

+

查看

-

查看

+

查看

1.发送消息时,可选的 `from` 字段用于指定发送方。

-

2. 消息支持扩展属性 `ext`,可添加自定义信息。同时,推送通知也支持自定义扩展字段,详见 APNs 自定义显示Android 推送字段说明

+

2. 消息支持扩展属性 `ext`,可添加自定义信息。同时,推送通知也支持自定义扩展字段,详见 APNs 自定义显示Android 推送字段说明

-

1. 调用文件上传方法上传图片、语音、视频或其他类型文件,并从响应 body 中获取文件 UUID。

+

1. 调用文件上传方法上传图片、语音、视频或其他类型文件,并从响应 body 中获取文件 UUID。

2. 调用发送消息方法,在请求 body 中传入该 UUID。

+
@@ -40,7 +40,7 @@ - +
单端/多端登录
多端登录若一端的登录设备数量达到了上限,最新登录的设备会将该端最早登录的设备踢下线。<br/>即时通讯 IM 仅支持同端互踢,不支持各端之间互踢。若一端的登录设备数量达到了上限,最新登录的设备会将该端最早登录的设备踢下线。
即时通讯 IM 仅支持同端互踢,不支持各端之间互踢。
diff --git a/docs/document/v1/web/overview.md b/docs/document/v1/web/overview.md index cd422d54c..b0d621778 100644 --- a/docs/document/v1/web/overview.md +++ b/docs/document/v1/web/overview.md @@ -1,252 +1,193 @@ -# 概述 +# SDK集成概述 - +## 初始化 -本页介绍 Web 集成相关内容。 +### 创建连接 -## 前提条件 - -开始前,请注册有效的环信即时通讯 IM 开发者账号且获得 App key,见 [环信即时通讯云管理后台](https://console.easemob.com/user/login)。 - -## 集成环境 - -具体见 [开发环境要求](quickstart.html#前提条件)。 - -## 引入 SDK - -对于 JavaScript SDK,导入代码如下: - -```javascript -import EC from "easemob-websdk"; ``` - -对于 TypeScript SDK,导入代码如下, EasemobChat 是 SDK 类型的命名空间。 - -```javascript -import EC, { EasemobChat } from "easemob-websdk"; +let conn = {}; +WebIM.config = config; +conn = WebIM.conn = new WebIM.connection({ + appKey: WebIM.config.appkey, + isHttpDNS: WebIM.config.isHttpDNS, + isMultiLoginSessions: WebIM.config.isMultiLoginSessions, + https: WebIM.config.https, + url: WebIM.config.socketServer, + apiUrl: WebIM.config.restServer, + isAutoLogin: WebIM.config.isAutoLogin, + autoReconnectNumMax: WebIM.config.autoReconnectNumMax, + autoReconnectInterval: WebIM.config.autoReconnectInterval, + delivery: WebIM.config.delivery, + useOwnUploadFun: WebIM.config.useOwnUploadFun +}) +// WebIM.config 为之前集成里介绍的WebIMConfig.js ``` -如果对 SDK 大小有要求,可根据功能按需导入 SDK 文件。 - -| 功能 | 导入文件 | 使用方式 | -| :--------------- | :---------------------------------------------------------------------------- | :---------------------------------------------------- | -| 联系人和消息管理 | import \* as contactPlugin from "easemob-websdk/contact/contact"; | miniCore.usePlugin(contactPlugin, "contact"); | -| 群组 | import \* as groupPlugin from "easemob-websdk/group/group"; | miniCore.usePlugin(groupPlugin, "group"); | -| 聊天室 | import \* as chatroomPlugin from "easemob-websdk/chatroom/chatroom"; | miniCore.usePlugin(chatroomPlugin, "chatroom"); | -| 子区 | import \* as threadPlugin from "easemob-websdk/thread/thread"; | miniCore.usePlugin(threadPlugin, "thread"); | -| 翻译 | import \* as translationPlugin from "easemob-websdk/translation/translation"; | miniCore.usePlugin(translationPlugin, "translation"); | -| 在线状态订阅 | import \* as presencePlugin from "easemob-websdk/presence/presence"; | miniCore.usePlugin(presencePlugin, "presence"); | - -示例代码如下: - -```javascript -import MiniCore from "easemob-websdk/miniCore/miniCore"; -import * as contactPlugin from "easemob-websdk/contact/contact"; - -const miniCore = new MiniCore({ - appKey: "your appKey", -}); - -// "contact" 为固定值 -miniCore.usePlugin(contactPlugin, "contact"); - -// 获取联系人列表 -miniCore.contact.getContacts(); - -// 添加监听事件 -miniCore.addEventHandler("handlerId", { - onTextMessage: (message) => {}, -}); +### 添加回调函数 -// 登录 -miniCore.open({ - username: "username", - password: "password", -}); ``` - -## SDK 初始化 - -使用 SDK 前需要进行初始化,示例代码如下: - -```javascript -const conn = new EC.connection({ - appKey: "your appKey", +conn.listen({ + onOpened: function () {}, //连接成功回调 + onClosed: function () {}, //连接关闭回调 + onTextMessage: function ( message ) {}, //收到文本消息 + onEmojiMessage: function ( message ) {}, //收到表情消息 + onPictureMessage: function ( message ) {}, //收到图片消息 + onCmdMessage: function ( message ) {}, //收到命令消息 + onAudioMessage: function ( message ) {}, //收到音频消息 + onLocationMessage: function ( message ) {},//收到位置消息 + onFileMessage: function ( message ) {}, //收到文件消息 + onCustomMessage: function ( message ) {}, //收到自定义消息 + onVideoMessage: function (message) { + var node = document.getElementById('privateVideo'); + var option = { + url: message.url, + headers: { + 'Accept': 'audio/mp4' + }, + onFileDownloadComplete: function (response) { + var objectURL = WebIM.utils.parseDownloadResponse.call(conn, response); + node.src = objectURL; + }, + onFileDownloadError: function () { + console.log('File down load error.') + } + }; + WebIM.utils.download.call(conn, option); + }, //收到视频消息 + onPresence: function ( message ) {}, //处理“广播”或“发布-订阅”消息,如联系人订阅请求、处理群组、聊天室被踢解散等消息 + onRoster: function ( message ) {}, //处理好友申请 + onInviteMessage: function ( message ) {}, //处理群组邀请 + onOnline: function () {}, //本机网络连接成功 + onOffline: function () {}, //本机网络掉线 + onError: function ( message ) {}, //失败回调 + onBlacklistUpdate: function (list) { //黑名单变动 + // 查询黑名单,将好友拉黑,将好友从黑名单移除都会回调这个函数,list则是黑名单现有的所有好友信息 + console.log(list); + }, + onRecallMessage: function(message){}, //收到撤回消息回调 + onReceivedMessage: function(message){}, //收到消息送达服务器回执 + onDeliveredMessage: function(message){}, //收到消息送达客户端回执 + onReadMessage: function(message){}, //收到消息已读回执 + onCreateGroup: function(message){}, //创建群组成功回执(需调用createGroupNew) + onMutedMessage: function(message){}, //如果用户在A群组被禁言,在A群发消息会走这个回调并且消息不会传递给群其它成员 + onChannelMessage: function(message){} //收到整个会话已读的回执,在对方发送channel ack时会在这个回调里收到消息 }); ``` -初始化 SDK 参数说明: - -| 参数 | 类型 | 是否必需 | 描述 | -| :-------------------- | :----- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | -| `appKey` | String | 是 | 环信即时通讯云控制台为你的应用生成的唯一标识,由应用名称(`Appname`)和组织名称(`Orgname`)组成。 | -| `isHttpDNS` | Bool | 否 | 是否开启 DNS,防止 DNS 劫持。
-(默认)`true`:开启 DNS;
- `false`:关闭 DNS。 | -| `delivery` | Bool | 否 | 是否开启送达回执:
- `true`:开启;
-(默认)`false`:关闭。 | -| `https` | Bool | 否 | 是否支持通过 HTTPS 访问即时通讯 IM:
- (默认)`true`:支持 HTTPS 和 HTTP;
-`false`:浏览器根据使用的域名自行判断。 | -| `heartBeatWait` | Int | 否 | 心跳间隔,单位为毫秒,默认为 30000。 | -| `deviceId` | String | 否 | 设备 ID,为默认随机值。 | -| `useOwnUploadFun` | Bool | 否 | 是否支持通过自己的路径将图片、文件上传到自己的服务器。
-`true`:支持,需要指定路径;
-(默认)`false`:关闭,通过消息服务器上传下载文件。 | -| `autoReconnectNumMax` | Int | 否 | 最大重连次数。 | - -## 注册用户 - -本节介绍三种用户注册方式。 - -### 控制台注册 - -登录[环信即时通讯云控制台](https://console.easemob.com/user/login),选择**即时通讯** > **运营服务** > **用户管理**,创建 IM 用户。 +## 注册 -### REST API 注册 +根据用户名/密码/昵称注册环信 Web IM : -请参考 [注册用户](/document/server-side/account_system.html#注册用户)。 - -### SDK 注册 - -若支持 SDK 注册,需登录[环信即时通讯云控制台](https://console.easemob.com/user/login),选择 **即时通讯** > **服务概览**,将 **设置**下的 **用户注册模式** 设置为 **开放注册**。 - -```javascript -conn - .registerUser({ - /** 用户 ID。 */ - username: string, - /** 密码。 */ - password: string, - /** 显示昵称。用于移动端推送的时候通知栏显示。 */ - nickname: string, - }) - .then((res) => { - console.log(res); - }); +``` +var options = { + username: 'username', + password: 'password', + nickname: 'nickname', + appKey: WebIM.config.appkey, + success: function () { }, + error: function (err) { + let errorData = JSON.parse(err.data); + if (errorData.error === 'duplicate_unique_property_exists') { + console.log('用户已存在!'); + } else if (errorData.error === 'illegal_argument') { + if (errorData.error_description === 'USERNAME_TOO_LONG') { + console.log('用户名超过64个字节!') + }else{ + console.log('用户名不合法!') + } + } else if (errorData.error === 'unauthorized') { + console.log('注册失败,无权限!') + } else if (errorData.error === 'resource_limited') { + console.log('您的App用户注册数量已达上限,请升级至企业版!') + } + }, + }; + conn.registerUser(options); ``` -## 用户登录 - -SDK 不支持自动登录,只支持通过以下方式手动登录: - -- 用户 ID + 密码 -- 用户 ID + token - -登录时传入的用户 ID 必须为 String 类型,支持的字符集详见[用户注册的 RESTful 接口](/document/server-side/account_system.html#注册用户)。 +## 登录 -调用登录接口后,收到 `onConnected` 回调表明 SDK 与环信服务器连接成功。 +#### 用户名/密码登录 -1. **用户 ID +密码** 登录是传统的登录方式。用户 ID 和密码都是你的终端用户自行决定,密码需要符合密码规则要求。 +使用用户名/密码登录环信 Web IM : -```javascript -conn - .open({ - user: "username", - pwd: "password", - }) - .then(() => { - console.log("login success"); - }) - .catch((reason) => { - console.log("login fail", reason); - }); +``` +var options = { + user: 'username', + pwd: 'password', + appKey: WebIM.config.appkey +}; +conn.open(options); ``` -2. **用户 ID + token** 是更加安全的登录方式。token 可以通过调用 REST API 获取,详见 [环信用户 token 的获取](/product/easemob_user_token.html)。 +#### 使用 Token 登录 -:::notice -使用 token 登录时需要处理 token 过期的问题,比如在每次登录时更新 token 等机制。 -::: +1. 使用用户名/密码登录,获取 Token。 -```javascript -conn - .open({ - user: "username", - accessToken: "token", - }) - .then(() => { - console.log("login success"); - }) - .catch((reason) => { - console.log("login fail", reason); - }); +``` +var options = { + user: 'username', + pwd: 'password', + appKey: WebIM.config.appkey, + success: function (res) { + var token = res.access_token + }, + error: function(){ + } +}; +conn.open(options); ``` -登录重试机制如下: - -- 登录时,若服务器返回明确的失败原因,例如,token 不正确,SDK 不会重试登录。 -- 若登录因超时失败,SDK 会重试登录。 - -## 退出登录 +2. 使用 Token 登录环信 Web IM。 -```typescript -conn.close(); ``` - -## 连接状态相关 - -你可以通过注册连接监听器确认连接状态。 - -```javascript -conn.addEventHandler("handlerId", { - onConnected: () => { - console.log("onConnected"); - }, - onDisconnected: () => { - console.log("onDisconnected"); - }, - onTokenWillExpire: () => { - console.log("onTokenWillExpire"); - }, - onTokenExpired: () => { - console.log("onTokenExpired"); - }, -}); +var options = { + user: 'username', + accessToken: 'token', + appKey: WebIM.config.appkey +}; +conn.open(options); ``` -### 断网自动重连 +## 退出 -如果由于网络信号弱、切换网络等引起的连接中断,系统会自动尝试重连。重连成功或者失败分别会收到 `onConnected` 和 `onDisconnected` 通知。 +``` +conn.close(); +``` -### 被动退出登录 +## 上传推送 token -对于 `onDisconnected` 通知,错误码(`errorCode`)可能为以下几种,建议 App 返回登录界面。 +如果把 SDK 用在原生客户端,集成第三方推送功能,可以调用此方法将 token 上传到环信服务器 -| 错误码 | 描述 | -| :------------------------------------------------- | :------------------------- | -| WEBIM_CONNCTION_USER_LOGIN_ANOTHER_DEVICE=206 | 用户已经在其他设备登录。 | -| WEBIM_CONNCTION_USER_REMOVED=207 | 用户账户已经被移除。 | -| WEBIM_CONNCTION_USER_KICKED_BY_CHANGE_PASSWORD=216 | 由于密码变更被踢下线。 | -| WEBIM_CONNCTION_USER_KICKED_BY_OTHER_DEVICE=217 | 由于其他设备登录被踢下线。 | +``` +/** + * @param {Object} options - + * @param {Object} options.deviceId - 设备 ID,可以自己定义,一般用来标识同一个设备 + * @param {Object} options.deviceToken - 推送 token + * @param {Object} options.notifierName - 推送服务的 appId,对于 FCM 是 senderId,对于 VIVO 是 “appId+#+AppKey ” + */ +conn.uploadToken(options); +``` -## 输出信息到日志文件 +## 修改推送昵称 -开启日志输出: +在注册时可以设置一个昵称,这个昵称用来在推送消息时显示,可以调用下面API修改昵称 -```javascript -logger.enableAll(); ``` - -关闭日志输出: - -```javascript -logger.disableAll(); +conn.updateCurrentUserNick('newNick') ``` -设置日志输出等级: - -```javascript -// 0 - 5 或者 'TRACE','DEBUG','INFO','WARN','ERROR','SILENT'; -logger.setLevel(0); -``` +## 常见问题 -设置缓存日志: +Q: 是否支持 token 登录,是否支持 HTTPS?
+A: 支持。 -```javascript -logger.setConfig({ - useCache: false, // 是否缓存 - maxCache: 3 * 1024 * 1024, // 最大缓存字节 -}); -// 缓存全部等级日志 -logger.setLevel(0); -``` +Q: 是否支持重连?
+A: 支持。1.未使用 DNS:当前连接不能建立时会尝试重新连接,连接次数可在 config 里配置;2.使用 DNS:当前连接不能建立时,会根据 DNSconfig 的地址逐一尝试连接。 -下载日志: +Q: ws 有上行没有下行?
+A: 可能是浏览器缓存了错误的 ws 返回结果,解决办法是加个时间戳参数,强制浏览器不走缓存。 -```javascript -logger.download(); -``` +Q: 收到提示 “您的连接不是私密连接”,怎么处理?
+
+A: chrome53 屏蔽了赛门铁克的某些日期颁发的证书,升级 chrome 就可以解决。详细信息可查看:http://www.jkeabc.com/376605.html 或者 https://sslmate.com/blog/post/ct_redaction_in_chrome_53。 \ No newline at end of file diff --git a/docs/document/v1/web/overview_v.md b/docs/document/v1/web/overview_v.md new file mode 100644 index 000000000..1301991b7 --- /dev/null +++ b/docs/document/v1/web/overview_v.md @@ -0,0 +1,252 @@ +# 概述 + + + +本页介绍 Web 集成相关内容。 + +## 前提条件 + +开始前,请注册有效的环信即时通讯 IM 开发者账号且获得 App key,见 [环信即时通讯云管理后台](/document/v1/privatization/uc_configure.html)。 + +## 集成环境 + +具体见 [开发环境要求](quickstart.html#前提条件)。 + +## 引入 SDK + +对于 JavaScript SDK,导入代码如下: + +```javascript +import EC from "easemob-websdk"; +``` + +对于 TypeScript SDK,导入代码如下, EasemobChat 是 SDK 类型的命名空间。 + +```javascript +import EC, { EasemobChat } from "easemob-websdk"; +``` + +如果对 SDK 大小有要求,可根据功能按需导入 SDK 文件。 + +| 功能 | 导入文件 | 使用方式 | +| :--------------- | :---------------------------------------------------------------------------- | :---------------------------------------------------- | +| 联系人和消息管理 | import \* as contactPlugin from "easemob-websdk/contact/contact"; | miniCore.usePlugin(contactPlugin, "contact"); | +| 群组 | import \* as groupPlugin from "easemob-websdk/group/group"; | miniCore.usePlugin(groupPlugin, "group"); | +| 聊天室 | import \* as chatroomPlugin from "easemob-websdk/chatroom/chatroom"; | miniCore.usePlugin(chatroomPlugin, "chatroom"); | +| 子区 | import \* as threadPlugin from "easemob-websdk/thread/thread"; | miniCore.usePlugin(threadPlugin, "thread"); | +| 翻译 | import \* as translationPlugin from "easemob-websdk/translation/translation"; | miniCore.usePlugin(translationPlugin, "translation"); | +| 在线状态订阅 | import \* as presencePlugin from "easemob-websdk/presence/presence"; | miniCore.usePlugin(presencePlugin, "presence"); | + +示例代码如下: + +```javascript +import MiniCore from "easemob-websdk/miniCore/miniCore"; +import * as contactPlugin from "easemob-websdk/contact/contact"; + +const miniCore = new MiniCore({ + appKey: "your appKey", +}); + +// "contact" 为固定值 +miniCore.usePlugin(contactPlugin, "contact"); + +// 获取联系人列表 +miniCore.contact.getContacts(); + +// 添加监听事件 +miniCore.addEventHandler("handlerId", { + onTextMessage: (message) => {}, +}); + +// 登录 +miniCore.open({ + username: "username", + password: "password", +}); +``` + +## SDK 初始化 + +使用 SDK 前需要进行初始化,示例代码如下: + +```javascript +const conn = new EC.connection({ + appKey: "your appKey", +}); +``` + +初始化 SDK 参数说明: + +| 参数 | 类型 | 是否必需 | 描述 | +| :-------------------- | :----- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | +| `appKey` | String | 是 | 环信即时通讯云控制台为你的应用生成的唯一标识,由应用名称(`Appname`)和组织名称(`Orgname`)组成。 | +| `isHttpDNS` | Bool | 否 | 是否开启 DNS,防止 DNS 劫持。
-(默认)`true`:开启 DNS;
- `false`:关闭 DNS。 | +| `delivery` | Bool | 否 | 是否开启送达回执:
- `true`:开启;
-(默认)`false`:关闭。 | +| `https` | Bool | 否 | 是否支持通过 HTTPS 访问即时通讯 IM:
- (默认)`true`:支持 HTTPS 和 HTTP;
-`false`:浏览器根据使用的域名自行判断。 | +| `heartBeatWait` | Int | 否 | 心跳间隔,单位为毫秒,默认为 30000。 | +| `deviceId` | String | 否 | 设备 ID,为默认随机值。 | +| `useOwnUploadFun` | Bool | 否 | 是否支持通过自己的路径将图片、文件上传到自己的服务器。
-`true`:支持,需要指定路径;
-(默认)`false`:关闭,通过消息服务器上传下载文件。 | +| `autoReconnectNumMax` | Int | 否 | 最大重连次数。 | + +## 注册用户 + +本节介绍三种用户注册方式。 + +### 控制台注册 + +登录[环信即时通讯云控制台](/document/v1/privatization/uc_configure.html),选择 **运营服务** > **用户管理**,创建 IM 用户。 + +### REST API 注册 + +请参考 [注册用户](/document/v1/server-side/account_system.html#注册用户)。 + +### SDK 注册 + +若支持 SDK 注册,需登录[环信即时通讯云控制台](/document/v1/privatization/uc_configure.html),选择 **应用概览** > **应用详情**,将 **设置**下的 **用户注册模式** 设置为 **开放注册**。 + +```javascript +conn + .registerUser({ + /** 用户 ID。 */ + username: string, + /** 密码。 */ + password: string, + /** 显示昵称。用于移动端推送的时候通知栏显示。 */ + nickname: string, + }) + .then((res) => { + console.log(res); + }); +``` + +## 用户登录 + +SDK 不支持自动登录,只支持通过以下方式手动登录: + +- 用户 ID + 密码 +- 用户 ID + token + +登录时传入的用户 ID 必须为 String 类型,支持的字符集详见[用户注册的 RESTful 接口](/document/v1/server-side/account_system.html#注册用户)。 + +调用登录接口后,收到 `onConnected` 回调表明 SDK 与环信服务器连接成功。 + +1. **用户 ID +密码** 登录是传统的登录方式。用户 ID 和密码都是你的终端用户自行决定,密码需要符合密码规则要求。 + +```javascript +conn + .open({ + user: "username", + pwd: "password", + }) + .then(() => { + console.log("login success"); + }) + .catch((reason) => { + console.log("login fail", reason); + }); +``` + +2. **用户 ID + token** 是更加安全的登录方式。token 可以通过调用 REST API 获取,详见 [环信用户 token 的获取](/document/v1/privatization/easemob_user_token.html)。 + +:::notice +使用 token 登录时需要处理 token 过期的问题,比如在每次登录时更新 token 等机制。 +::: + +```javascript +conn + .open({ + user: "username", + accessToken: "token", + }) + .then(() => { + console.log("login success"); + }) + .catch((reason) => { + console.log("login fail", reason); + }); +``` + +登录重试机制如下: + +- 登录时,若服务器返回明确的失败原因,例如,token 不正确,SDK 不会重试登录。 +- 若登录因超时失败,SDK 会重试登录。 + +## 退出登录 + +```typescript +conn.close(); +``` + +## 连接状态相关 + +你可以通过注册连接监听器确认连接状态。 + +```javascript +conn.addEventHandler("handlerId", { + onConnected: () => { + console.log("onConnected"); + }, + onDisconnected: () => { + console.log("onDisconnected"); + }, + onTokenWillExpire: () => { + console.log("onTokenWillExpire"); + }, + onTokenExpired: () => { + console.log("onTokenExpired"); + }, +}); +``` + +### 断网自动重连 + +如果由于网络信号弱、切换网络等引起的连接中断,系统会自动尝试重连。重连成功或者失败分别会收到 `onConnected` 和 `onDisconnected` 通知。 + +### 被动退出登录 + +对于 `onDisconnected` 通知,错误码(`errorCode`)可能为以下几种,建议 App 返回登录界面。 + +| 错误码 | 描述 | +| :------------------------------------------------- | :------------------------- | +| WEBIM_CONNCTION_USER_LOGIN_ANOTHER_DEVICE=206 | 用户已经在其他设备登录。 | +| WEBIM_CONNCTION_USER_REMOVED=207 | 用户账户已经被移除。 | +| WEBIM_CONNCTION_USER_KICKED_BY_CHANGE_PASSWORD=216 | 由于密码变更被踢下线。 | +| WEBIM_CONNCTION_USER_KICKED_BY_OTHER_DEVICE=217 | 由于其他设备登录被踢下线。 | + +## 输出信息到日志文件 + +开启日志输出: + +```javascript +logger.enableAll(); +``` + +关闭日志输出: + +```javascript +logger.disableAll(); +``` + +设置日志输出等级: + +```javascript +// 0 - 5 或者 'TRACE','DEBUG','INFO','WARN','ERROR','SILENT'; +logger.setLevel(0); +``` + +设置缓存日志: + +```javascript +logger.setConfig({ + useCache: false, // 是否缓存 + maxCache: 3 * 1024 * 1024, // 最大缓存字节 +}); +// 缓存全部等级日志 +logger.setLevel(0); +``` + +下载日志: + +```javascript +logger.download(); +``` diff --git a/docs/document/v1/web/presence.md b/docs/document/v1/web/presence.md index 195aa7a7f..397b30aec 100644 --- a/docs/document/v1/web/presence.md +++ b/docs/document/v1/web/presence.md @@ -35,8 +35,8 @@ 使用在线状态功能前,请确保满足以下条件: 1. 完成 `4.0.4 及以上版本` SDK 初始化,详见 [快速开始](quickstart.html)。 -2. 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -3. 已联系商务开通在线状态订阅功能。 +2. 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +3. 私有部署已开通在线状态订阅功能。 ## 实现方法 diff --git a/docs/document/v1/web/privatecloud.md b/docs/document/v1/web/privatecloud.md index e8fbdf50f..554dd1050 100644 --- a/docs/document/v1/web/privatecloud.md +++ b/docs/document/v1/web/privatecloud.md @@ -1,67 +1,34 @@ -# 私有云 SDK 集成配置 +# 私有云SDK集成配置 -## Web Vue 2 Demo -对于 Web Vue Demo,进行私有化配置需在 [Vue 2 Demo 源代码](https://download-sdk.oss-cn-beijing.aliyuncs.com/zq/private-vue2-20230104.zip)中进行修改。 +## 静态配置ip(域名)地址 -### 修改环境配置 +SDK 默认指向公有云地址,在部署私有云后,需要将地址重新指向到新的地址,以下是地址修改方法: -在 `src/utils/WebIMConfig.js` 文件中,进行如下修改: - -```javascript -appkey: 'easemob#easeim', // 私有化的 App Key -isHttpDNS: false, // 是否允许通过 DNS 获取。由于私有云需自己配置,这里必须为 `false`。 -socketServer: 'https://xxx.xxxxx.com', // 私有化的 WebSocket 地址 -restServer: 'https://xxx.xxxxx.com', // 私有化的 RESTful 服务器地址。对于 Uniapp 全平台,需要全局搜索,查找 `a1.easemob.com` 替换为 `restServer`。 ``` - -### 修改 SDK 初始化配置 - -在 `src/utils/WebIM.js` 文件中,进行如下修改: - -```javascript - appKey: WebIM.config.appkey, - url: WebIM.config.socketServer, - apiUrl: WebIM.config.restServer, - isHttpDNS:WebIM.config.isHttpDNS, // 对于私有云,该参数必须为 `false`。 - // 其他配置可酌情添加 +WebIM.conn = new websdk.connection({ + isHttpDNS: false, // 关闭DNS动态域名 + url: 'http://im-api-v2.easemob.com/ws', // 设置为私有云的websocket server url + apiUrl: 'http://a1.easemob.com' // 设置为私有云的rest server url +}) ``` -## Web Vue 3 Demo - -对于 Web Vue 3 Demo,进行私有化配置需在 [Vue 3 Demo 源代码](https://download-sdk.oss-cn-beijing.aliyuncs.com/zq/private-vue3-20230104.zip)中进行修改。 - -### 修改环境配置 - -在 `src/IM/initwebsdk.js` 文件中,进行如下修改: +注意:如果需要配置https只需将url、apiUrl指定为https协议: -```javascript -const DEFAULT_APPKEY = "easemob#easeim"; // 私有化的 App Key -const DEFAULT_URL = "https://xxx.xxxxx.com"; // 私有化的 WebSocket 地址 -const DEFAULT_APIURL = "https://xxx.xxxxx.com"; // 私有化的 RESTful 服务器地址 ``` - -## Web React Demo - -对于 Web React Demo,进行私有化配置需在 [React Demo 源代码](https://download-sdk.oss-cn-beijing.aliyuncs.com/zq/private-demo-20230104.zip)中进行修改。 - -修改配置如下: - -1. 在 `/demo/src/config/WebIMConfig.js` 中修改配置信息,如下所示: - -```javascript - appkey: appkey || 'easemob-demo#zim', - isHttpDNS: false, - restServer: rest.restServer || (window.location.protocol === 'https:' ? 'https:' : 'http:') + '//xxx.xxxxx.com', - restServer: rest.restServer || (window.location.protocol === 'https:' ? 'https:' : 'http:') + '//xxx.xxxxx.com', +WebIM.conn = new websdk.connection({ + isHttpDNS: false, // 关闭DNS动态域名 + url: 'https://im-api-v2.easemob.com/ws', + apiUrl: 'https://a1.easemob.com' +}) ``` -2. 在 `/demo/src/config/WebIM.js` 中修改初始化配置,如下所示: +## 动态配置地址 -```javascript - appKey: WebIM.config.appkey, - url: WebIM.config.socketServer, - apiUrl: WebIM.config.restServer, +``` +1.服务器端配置dns地址表 +2.设置isHttpDNS = true +3.设置服务器端配置的url地址:WebIM.conn.dnsArr = ['dns server url'], 例如:['https://rs.easemob.com'] ``` -然后,将 `if(WebIM.config.isSandbox)` 判断去掉,只使用 `options` 中配置的地址。 +注意:发送请求时的url是在dnsArr中的url上拼接上了固定路径:'/easemob/server.json' \ No newline at end of file diff --git a/docs/document/v1/web/push.md b/docs/document/v1/web/push.md index 87e41fc3d..536ab8024 100644 --- a/docs/document/v1/web/push.md +++ b/docs/document/v1/web/push.md @@ -15,7 +15,6 @@ 环信 IM Web SDK 本身不支持离线推送,只支持对移动端离线推送进行如下配置: - 设置推送通知,包含设置推送通知方式和免打扰模式。设置推送通知为推送的高级功能,使用前需要在环信控制台开启该功能。 -- 设置推送翻译。 ## 技术原理 @@ -33,7 +32,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 - 你已在环信即时通讯云管理后台中激活推送高级功能。推送高级功能包括设置推送通知模式和免打扰模式。 ![image](@static/images/web/push_web_enable_push.png) @@ -258,7 +257,7 @@ WebIM.conn.clearRemindTypeForConversation(params) ### 设置推送翻译 -如果用户启用[自动翻译](message_translation.html) 功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 +如果用户启用自动翻译功能并发送消息,SDK 会同时发送原始消息和翻译后的消息。 推送通知与翻译功能协同工作。作为接收方,你可以设置你在离线时希望接收的推送通知的首选语言。如果翻译消息的语言符合你的设置,则翻译消息显示在推送通知中;否则,将显示原始消息。 diff --git a/docs/document/v1/web/quickstart.md b/docs/document/v1/web/quickstart.md index 97337a0f2..e87cbd1e4 100644 --- a/docs/document/v1/web/quickstart.md +++ b/docs/document/v1/web/quickstart.md @@ -1,335 +1,97 @@ -# 环信即时通讯 IM Web 快速开始 +# Web SDK 快速集成 - +## 搭建本地测试环境 -本页面介绍如何快速集成环信即时通讯 IM Web SDK 实现单聊。 +1. 搭建环境之前需要对环信提供的参考文档有个初步的了解,主要为以下形式,请根据下面的关键字选择源码参考 -## 实现原理 +- 基于 react 开发的完整的实时 Demo ,关键字:**至少 IE9** ,**完整流程**,**webpack+react** +- 首先将源码下载到本地,[下载SDK及Demo](https://download-sdk.oss-cn-beijing.aliyuncs.com/mp/downloads/webdemo-3.4.2.7.zip) -下图展示在客户端发送和接收一对一文本消息的工作流程。 -![](@static/images/web/sendandreceivemsg.png) +2. 去官网安装[NodeJS](https://nodejs.org/zh-cn/),建议4+ -## 前提条件 +- 因为整套代码需要依赖于[npm](https://www.npmjs.com/) NodeJS 的包管理工具,安装 NodeJS 会默认安装 NPM 工具 +- 定位到 webim/demo 目录 在终端执行下面的命令,安装测试所需要的依赖模块 -- 有效的环信即时通讯 IM 开发者账号; -- [创建环信即时通讯 IM 项目并获取 App Key](/product/enable_and_configure_IM.html); -- [npm](https://www.npmjs.com/get-npm); -- SDK 支持 IE 9+、Firefox 10+、Chrome 54+ 和 Safari 6+。 +- 保证此过程没有 error 终止为成功,如果有错误中断,请保留错误日志并再次尝试,大多数情况是网络原因导致的无法连接而中断 -## 操作步骤 +``` +npm i +``` -### 1. 准备开发环境 +3. 上述步骤成功后 -本节介绍如何创建项目,将环信即时通讯 IM Web SDK 集成到你的项目中。 +``` +# 启动测试环境 +npm start (如果需要https 通过HTTPS=true npm start启动) +# 打包发布,发布后文件在 webim/demo/build 目录下 +npm run build +``` -#### 新建 Web 项目 +4. 浏览器访问即可看到测试页面: -新建 `Easemob_quickstart` 目录。在该目录下运行 `npm init` 命令创建 `package.json` 文件,然后创建以下文件: +- http:http://localhost:3000/ -- `index.html`:设置 Web 应用的用户界面; -- `index.js`:包含消息发送和接收逻辑的实现代码。 -此时你的目录中包含以下文件: +- https:https://localhost:3001/ -Easemob_quickstart
-├─ index.html
-├─ index.js
-└─ package.json +## 集成 -### 2. 集成 SDK +可以通过以下方式引用 Web SDK: -- 在 `package.json` 中的 `dependencies` 字段中加入 `easemob-websdk` 及对应版本: +- 将文件复制到本地,引用本地文件 -```json -{ - "name": "web", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "dependencies": { - "easemob-websdk": "latest" - }, - "author": "", - "license": "ISC" -} -``` -### 3. 实现用户界面 - -`index.html` 的内容如下。 - -`` 用于引用 webpack 打包之后的 `bundle.js` 文件。webpack 的配置在后续步骤中介绍。 - -```html - - - - - - Easemob Chat Examples - - - -

Easemob Chat Examples

-
-
-
-
-
- - -
-
- - -
-
-
- - - -
-
-
- - -
-
- - - -
-
-
-
-
-
-
- - - -``` +### 引用本地文件 -### 4. 实现消息发送与接收 - -`index.js` 的内容如下。本文使用 import 方法导入 SDK,并使用 webpack 对 JavaScript 文件进行打包,以避免浏览器兼容性问题。你需要分别将代码中的 `` 替换为你之前获取的 App Key。 - -```Javascript -import WebIM from 'easemob-websdk' -const appKey = "" - -let username, password - -// 初始化客户端。相关的参数配置,详见 API 参考中的 `Connection` 类。 -WebIM.conn = new WebIM.connection({ - //注意这里的 "K" 需大写。 - appKey: appKey, -}) - -// 添加回调函数。 -WebIM.conn.addEventHandler('connection&message', { - onConnected: () => { - document.getElementById("log").appendChild(document.createElement('div')).append("Connect success !") - }, - onDisconnected: () => { - document.getElementById("log").appendChild(document.createElement('div')).append("Logout success !") - }, - onTextMessage: (message) => { - console.log(message) - document.getElementById("log").appendChild(document.createElement('div')).append("Message from: " + message.from + " Message: " + message.msg) - }, - onError: (error) => { - console.log('on error', error) - } -}) - - -// 按钮行为定义。 -window.onload = function () { - // 注册。 - document.getElementById("register").onclick = function(){ - username = document.getElementById("userID").value.toString() - password = document.getElementById("password").value.toString() - WebIM.conn - .registerUser({ username, password }) - .then((res) => { - document - .getElementById("log") - .appendChild(document.createElement("div")) - .append(`register user ${username} success`); - }) - .catch((e) => { - document - .getElementById("log") - .appendChild(document.createElement("div")) - .append(`${username} already exists`); - }); - } - // 登录。 - document.getElementById("login").onclick = function () { - username = document.getElementById("userID").value.toString() - password = document.getElementById("password").value.toString() - WebIM.conn - .open({ user: username, pwd: password }) - .then((res) => { - document - .getElementById("log") - .appendChild(document.createElement("div")) - .append(`Login Success`); - }) - .catch((e) => { - document - .getElementById("log") - .appendChild(document.createElement("div")) - .append(`Login failed`); - }); - } - - // 登出。 - document.getElementById("logout").onclick = function () { - WebIM.conn.close(); - } - - // 发送一条单聊消息。 - document.getElementById("send_peer_message").onclick = function () { - let peerId = document.getElementById("peerId").value.toString() - let peerMessage = document.getElementById("peerMessage").value.toString() - let option = { - chatType: 'singleChat', // 会话类型,设置为单聊。 - type: 'txt', // 消息类型。 - to: peerId, // 消息接收方(用户 ID)。 - msg: peerMessage // 消息内容。 - } - let msg = WebIM.message.create(option); - WebIM.conn.send(msg).then((res) => { - console.log('send private text success'); - document.getElementById("log").appendChild(document.createElement('div')).append("Message send to: " + peerId + " Message: " + peerMessage) - }).catch(() => { - console.log('send private text fail'); - }) - } -} -``` -:::notice -对于 Typescript,通过以下代码引入类型声明: -```JavaScript -import WebIM, { EasemobChat } from 'easemob-websdk' -``` +1. 下载demo后,将sdk目录下的 webimSDK.js(现SDK包命名为websdk+版本号的形式,例如:websdk3.4.2.js)、EMedia_x1v1.js、EMedia_sdk-dev.js,按照实际项目需求选择对应的SDK拷贝到系统相应的目录下。 +:::tip +websdk:提供全功能即时通讯SDK接口,Emedia:提供音视频功能相关SDK接口。如需音视频功能,EMedia_x1v1.js与EMedia_sdk-dev.js只引用EMedia_x1v1.js即可。 ::: -### 5. 运行项目 - -本文使用 webpack 对项目进行打包,并使用 `webpack-dev-server` 运行项目。 - -1.在 `package.json` 的 `dependencies` 字段中添加 `webpack`、`webpack-cli` 和 `webpack-dev-server`,并且在 `scripts` 字段中添加 `build` 和 `start:dev` 命令。 - -```json -{ - "name": "web", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "build": "webpack --config webpack.config.js", - "start:dev": "webpack serve --open --config webpack.config.js" - }, - "dependencies": { - "easemob-websdk": "latest", - "webpack": "^5.50.0", - "webpack-dev-server": "^3.11.2", - "webpack-cli": "^4.8.0" - }, - "author": "", - "license": "ISC" -} -``` +2. 新版本中 WebIMConfig 文件只做参数定义方便实例化 SDK 时使用,仅与自己项目结构有关。详细使用可以查看 /demo/src/config/WebIM.js文件 -2.在项目根目录中添加 `webpack.config.js` 文件,用于配置 webpack。文件内容如下: - -```Javascript -const path = require('path'); - -module.exports = { - entry: './index.js', - mode: 'production', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, './dist'), - }, - devServer: { - compress: true, - port: 9000, - https: true - } -}; -``` +3. 新建 html 文件并引入相关 js 脚本。 -此时你的目录中包含以下文件: - -Easemob_quickstart
-├─ index.html
-├─ index.js
-├─ package.json
-└─webpack.config.js - -3.在项目根目录运行以下命令,安装依赖项。 - -```bash -$ npm install +``` + + ``` -4.运行以下命令使用 `webpack` 构建并运行项目。 +:::tip +Web SDK 向下兼容V1.1.2和V1.1.1。关于详细的引用文件和配置参数(WebIMConfig)的方法,请查看本页“兼容性”的内容。 +::: +初始化 WebIM.connection 和 构造消息 WebIM.message, 需要在中间加上 default,如:WebIM.default.message。 -```bash -# 使用 webpack 打包。 -$ npm run build +## 配置 + +3.0 SDK,在 WebIMConfig.js 文件内进行以下配置: -# 使用 webpack-dev-server 运行项目。 -$ npm run start:dev ``` +socketServer: 'https://xxx.xxxxx.com', // socket Server地址 -项目启动后,在页面输入用户名和密码进行注册,然后利用该用户名和密码登录。登录成功后,输入对方的用户名和要发送的消息,点击**发送**按钮发送消息,可同时打开另一页面相互收发消息。 +restServer: 'https://xxx.xxxxx.com', // rest Server地址 -### 6. 参考信息 +appkey: 'easemob-demo#chatdemoui', // App key -可通过以下两种方式集成 SDK: +https : false, // 是否使用https -#### 方法一:通过 npm 安装并导入 SDK +isHttpDNS: true, // 3.0 SDK支持,防止DNS劫持从服务端获取XMPPUrl、restUrl -1. 在 `package.json` 中的 `dependencies` 字段中加入 `easemob-websdk` 及对应版本: +isMultiLoginSessions: false, // 是否开启多页面同步收消息,注意,需要先联系商务开通此功能 -```json -{ - "name": "web", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "dependencies": { - "easemob-websdk": "latest" - }, - "author": "", - "license": "ISC" -} -``` +isDebug: false, // 打开调试,会自动打印log,在控制台的console中查看log -2. 在你的 `index.js` 文件中导入 `easemob-websdk` 模块: +autoReconnectNumMax: 2, // 断线重连最大次数 -```JavaScript -import WebIM from 'easemob-websdk' -``` +heartBeatWait: 30000, // 心跳间隔(只在小程序中使用) -#### 方法二:从官网获取并导入 SDK +delivery: false, // 是否发送已读回执 -1. 下载 [Easemob Chat SDK for Web](https://www.easemob.com/download/im)。将 `demo/src/config` 中的 Easemob-chat 文件保存到你的项目下。 +useOwnUploadFun: false, // 是否使用自己的上传方式(如将图片文件等上传到自己的服务器,构建消息时只传url) -2. 在 `index.html` 文件中,对 `index.js` 文件进行引用。 +deviceId: 'webim' // 设备ID,默认可不传,如果传一个固定值,在没开启多端登录的情况下同一个账号会互踢 -```JavaScript - +注意: +socketServer与restServer取值见 私有部署文档中的 2.2开通防火墙白名单 配置各服务“地址:端口”。 ``` + diff --git a/docs/document/v1/web/quickstart_v.md b/docs/document/v1/web/quickstart_v.md new file mode 100644 index 000000000..75ad3453f --- /dev/null +++ b/docs/document/v1/web/quickstart_v.md @@ -0,0 +1,335 @@ +# 环信即时通讯 IM Web 快速开始 + + + +本页面介绍如何快速集成环信即时通讯 IM Web SDK 实现单聊。 + +## 实现原理 + +下图展示在客户端发送和接收一对一文本消息的工作流程。 + +![](@static/images/web/sendandreceivemsg.png) + +## 前提条件 + +- 有效的环信即时通讯 IM 开发者账号; +- [创建环信即时通讯 IM 项目并获取 App Key](/document/v1/privatization/uc_configure.html); +- [npm](https://www.npmjs.com/get-npm); +- SDK 支持 IE 9+、Firefox 10+、Chrome 54+ 和 Safari 6+。 + +## 操作步骤 + +### 1. 准备开发环境 + +本节介绍如何创建项目,将环信即时通讯 IM Web SDK 集成到你的项目中。 + +#### 新建 Web 项目 + +新建 `Easemob_quickstart` 目录。在该目录下运行 `npm init` 命令创建 `package.json` 文件,然后创建以下文件: + +- `index.html`:设置 Web 应用的用户界面; +- `index.js`:包含消息发送和接收逻辑的实现代码。 +此时你的目录中包含以下文件: + +Easemob_quickstart
+├─ index.html
+├─ index.js
+└─ package.json + +### 2. 集成 SDK + +- 在 `package.json` 中的 `dependencies` 字段中加入 `easemob-websdk` 及对应版本: + +```json +{ + "name": "web", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "easemob-websdk": "latest" + }, + "author": "", + "license": "ISC" +} +``` + +### 3. 实现用户界面 + +`index.html` 的内容如下。 + +`` 用于引用 webpack 打包之后的 `bundle.js` 文件。webpack 的配置在后续步骤中介绍。 + +```html + + + + + + Easemob Chat Examples + + + +

Easemob Chat Examples

+
+
+
+
+
+ + +
+
+ + +
+
+
+ + + +
+
+
+ + +
+
+ + + +
+
+
+
+
+
+
+ + + +``` + +### 4. 实现消息发送与接收 + +`index.js` 的内容如下。本文使用 import 方法导入 SDK,并使用 webpack 对 JavaScript 文件进行打包,以避免浏览器兼容性问题。你需要分别将代码中的 `` 替换为你之前获取的 App Key。 + +```Javascript +import WebIM from 'easemob-websdk' +const appKey = "" + +let username, password + +// 初始化客户端。相关的参数配置,详见 API 参考中的 `Connection` 类。 +WebIM.conn = new WebIM.connection({ + //注意这里的 "K" 需大写。 + appKey: appKey, +}) + +// 添加回调函数。 +WebIM.conn.addEventHandler('connection&message', { + onConnected: () => { + document.getElementById("log").appendChild(document.createElement('div')).append("Connect success !") + }, + onDisconnected: () => { + document.getElementById("log").appendChild(document.createElement('div')).append("Logout success !") + }, + onTextMessage: (message) => { + console.log(message) + document.getElementById("log").appendChild(document.createElement('div')).append("Message from: " + message.from + " Message: " + message.msg) + }, + onError: (error) => { + console.log('on error', error) + } +}) + + +// 按钮行为定义。 +window.onload = function () { + // 注册。 + document.getElementById("register").onclick = function(){ + username = document.getElementById("userID").value.toString() + password = document.getElementById("password").value.toString() + WebIM.conn + .registerUser({ username, password }) + .then((res) => { + document + .getElementById("log") + .appendChild(document.createElement("div")) + .append(`register user ${username} success`); + }) + .catch((e) => { + document + .getElementById("log") + .appendChild(document.createElement("div")) + .append(`${username} already exists`); + }); + } + // 登录。 + document.getElementById("login").onclick = function () { + username = document.getElementById("userID").value.toString() + password = document.getElementById("password").value.toString() + WebIM.conn + .open({ user: username, pwd: password }) + .then((res) => { + document + .getElementById("log") + .appendChild(document.createElement("div")) + .append(`Login Success`); + }) + .catch((e) => { + document + .getElementById("log") + .appendChild(document.createElement("div")) + .append(`Login failed`); + }); + } + + // 登出。 + document.getElementById("logout").onclick = function () { + WebIM.conn.close(); + } + + // 发送一条单聊消息。 + document.getElementById("send_peer_message").onclick = function () { + let peerId = document.getElementById("peerId").value.toString() + let peerMessage = document.getElementById("peerMessage").value.toString() + let option = { + chatType: 'singleChat', // 会话类型,设置为单聊。 + type: 'txt', // 消息类型。 + to: peerId, // 消息接收方(用户 ID)。 + msg: peerMessage // 消息内容。 + } + let msg = WebIM.message.create(option); + WebIM.conn.send(msg).then((res) => { + console.log('send private text success'); + document.getElementById("log").appendChild(document.createElement('div')).append("Message send to: " + peerId + " Message: " + peerMessage) + }).catch(() => { + console.log('send private text fail'); + }) + } +} +``` +:::notice +对于 Typescript,通过以下代码引入类型声明: +```JavaScript +import WebIM, { EasemobChat } from 'easemob-websdk' +``` +::: + +### 5. 运行项目 + +本文使用 webpack 对项目进行打包,并使用 `webpack-dev-server` 运行项目。 + +1.在 `package.json` 的 `dependencies` 字段中添加 `webpack`、`webpack-cli` 和 `webpack-dev-server`,并且在 `scripts` 字段中添加 `build` 和 `start:dev` 命令。 + +```json +{ + "name": "web", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "webpack --config webpack.config.js", + "start:dev": "webpack serve --open --config webpack.config.js" + }, + "dependencies": { + "easemob-websdk": "latest", + "webpack": "^5.50.0", + "webpack-dev-server": "^3.11.2", + "webpack-cli": "^4.8.0" + }, + "author": "", + "license": "ISC" +} +``` + +2.在项目根目录中添加 `webpack.config.js` 文件,用于配置 webpack。文件内容如下: + +```Javascript +const path = require('path'); + +module.exports = { + entry: './index.js', + mode: 'production', + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, './dist'), + }, + devServer: { + compress: true, + port: 9000, + https: true + } +}; +``` + +此时你的目录中包含以下文件: + +Easemob_quickstart
+├─ index.html
+├─ index.js
+├─ package.json
+└─webpack.config.js + +3.在项目根目录运行以下命令,安装依赖项。 + +```bash +$ npm install +``` + +4.运行以下命令使用 `webpack` 构建并运行项目。 + +```bash +# 使用 webpack 打包。 +$ npm run build + +# 使用 webpack-dev-server 运行项目。 +$ npm run start:dev +``` + +项目启动后,在页面输入用户名和密码进行注册,然后利用该用户名和密码登录。登录成功后,输入对方的用户名和要发送的消息,点击**发送**按钮发送消息,可同时打开另一页面相互收发消息。 + +### 6. 参考信息 + +可通过以下两种方式集成 SDK: + +#### 方法一:通过 npm 安装并导入 SDK + +1. 在 `package.json` 中的 `dependencies` 字段中加入 `easemob-websdk` 及对应版本: + +```json +{ + "name": "web", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "easemob-websdk": "latest" + }, + "author": "", + "license": "ISC" +} +``` + +2. 在你的 `index.js` 文件中导入 `easemob-websdk` 模块: + +```JavaScript +import WebIM from 'easemob-websdk' +``` + +#### 方法二:下载Demo并导入 SDK + +1. 下载 [Easemob Chat SDK for Web](https://downloadsdk.easemob.com/mp/downloads/sdk/private-react-20230918.zip)。将 `demo/src/config` 中的 Easemob-chat 文件保存到你的项目下。 + +2. 在 `index.html` 文件中,对 `index.js` 文件进行引用。 + +```JavaScript + +``` diff --git a/docs/document/v1/web/reaction.md b/docs/document/v1/web/reaction.md index b37978ccb..2c1734464 100644 --- a/docs/document/v1/web/reaction.md +++ b/docs/document/v1/web/reaction.md @@ -6,7 +6,6 @@ :::notice 1. 目前 Reaction 仅适用于单聊和群组。聊天室暂不支持 Reaction 功能。 -2. 私有化版本不支持 Reaction 功能。 ::: ## 技术原理 @@ -32,8 +31,8 @@ 开始前,请确保满足以下条件: 1. 完成 `4.0.5 及以上版本` SDK 初始化,详见 [快速开始](quickstart.html)。 -2. 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -3. 已联系商务开通 Reaction 功能。 +2. 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +3. 私有部署已开通 Reaction 功能。 ## 实现方法 diff --git a/docs/document/v1/web/releasenote.md b/docs/document/v1/web/releasenote.md index e677d3db4..1d9b54fce 100644 --- a/docs/document/v1/web/releasenote.md +++ b/docs/document/v1/web/releasenote.md @@ -1,7 +1,7 @@ # Web IM SDK 更新日志 - + ## 版本:v3.4.2 2021-01-09 - [IM SDK] 增加获取会话列表功能; diff --git a/docs/document/v1/web/room_attributes.md b/docs/document/v1/web/room_attributes.md index 043e38b15..6db7c83cd 100644 --- a/docs/document/v1/web/room_attributes.md +++ b/docs/document/v1/web/room_attributes.md @@ -2,26 +2,27 @@ -聊天室是支持多人沟通的即时通讯系统。聊天室属性可分为聊天室名称、描述和公告等基本属性和自定义属性(key-value)。若聊天室基本属性不满足业务要求,用户可增加自定义属性并同步给所有成员。利用自定义属性可以存储直播聊天室的类型、狼人杀等游戏中的角色信息和游戏状态以及实现语聊房的麦位管理和同步等。聊天室自定义属性以键值对(key-value)形式存储,属性信息变更会实时同步给聊天室成员。 +聊天室是支持多人沟通的即时通讯系统。聊天室属性可分为聊天室名称、描述和公告等基本属性。 本文介绍如何管理聊天室属性信息。 ## 技术原理 -环信即时通讯 IM SDK 支持你通过调用 API 在项目中实现聊天室基本属性和自定义属性的管理功能: +环信即时通讯 IM SDK 支持你通过调用 API 在项目中实现聊天室基本属性管理功能: - 获取和更新聊天室基本属性; + ## 前提条件 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html); -- 了解聊天室的数量限制,详见 [套餐包详情](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html); + ## 实现方法 @@ -73,7 +74,7 @@ let option = { }; conn.updateChatRoomAnnouncement(option).then((res) => console.log(res)); ``` - + ### 监听聊天室事件 有关详细信息,请参阅 [聊天室事件](room_manage.html#监听聊天室事件)。 diff --git a/docs/document/v1/web/room_manage.md b/docs/document/v1/web/room_manage.md index d987e4db2..bbde12cd0 100644 --- a/docs/document/v1/web/room_manage.md +++ b/docs/document/v1/web/room_manage.md @@ -24,9 +24,8 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的 API 使用限制,详见 [使用限制](/product/limitation); -- 了解环信即时通讯 IM 聊天室不同版本的数量限制,详见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im); -- 仅 [超级管理员](/document/server-side/chatroom.html#管理超级管理员) 可以创建聊天室; +- 了解环信即时通讯 IM 的 API 使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html); +- 仅 [超级管理员](/document/v1/server-side/chatroom.html#管理超级管理员) 可以创建聊天室; - 聊天室创建者和管理员的数量之和不能超过 100 ,即管理员最多可添加 99 个。 ## 实现方法 @@ -35,9 +34,9 @@ ### 创建聊天室 -仅 [超级管理员](/document/server-side/chatroom.html#管理超级管理员) 可以调用 `createChatRoom` 方法创建聊天室,并设置聊天室的名称、描述、最大成员数等信息。成功创建聊天室后,该超级管理员为该聊天室的所有者。 +仅 [超级管理员](/document/v1/server-side/chatroom.html#管理超级管理员) 可以调用 `createChatRoom` 方法创建聊天室,并设置聊天室的名称、描述、最大成员数等信息。成功创建聊天室后,该超级管理员为该聊天室的所有者。 -你也可以直接调用 REST API [从服务端创建聊天室](/document/server-side/chatroom.html#创建聊天室)。 +你也可以直接调用 REST API [从服务端创建聊天室](/document/v1/server-side/chatroom.html#创建聊天室)。 示例代码如下: diff --git a/docs/document/v1/web/room_members.md b/docs/document/v1/web/room_members.md index 052410c33..d9119c9ab 100644 --- a/docs/document/v1/web/room_members.md +++ b/docs/document/v1/web/room_members.md @@ -20,8 +20,7 @@ 开始前,请确保满足以下条件: - 完成 SDK 初始化,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation); -- 了解环信即时通讯 IM 聊天室不同套餐相关限制,详见 [环信即时通讯 IM 价格](https://www.easemob.com/pricing/im)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html); ## 实现方法 diff --git a/docs/document/v1/web/room_overview.md b/docs/document/v1/web/room_overview.md index 89a425e04..5524db387 100644 --- a/docs/document/v1/web/room_overview.md +++ b/docs/document/v1/web/room_overview.md @@ -6,9 +6,9 @@ 聊天室是支持多人加入的类似 Twitch 的组织。聊天室中的成员没有固定关系,用户离线后,超过 2 分钟会自动退出聊天室。聊天室成员在离线后,不会收到推送消息。聊天室可以应用于直播、消息广播等。若需调整该时间,需联系环信商务经理。 -聊天室的使用限制视不同套餐版本而定,请参见 使用限制。 +聊天室的使用限制请参见 [使用限制](/document/v1/privatization/uc_limitation.html)。 -本文以及接下来几篇主要介绍聊天室管理功能,如需查看消息相关内容,参见 消息管理。 +本文以及接下来几篇主要介绍聊天室管理功能,如需查看消息相关内容,参见 。 ### 群组与聊天室的区别 @@ -32,7 +32,7 @@ | 功能 | 描述 | | :------------- | :----------------------------------------------------------- | -| 创建聊天室 | 只有被赋予 [超级管理员](/document/server-side/chatroom.html#管理超级管理员) 权限的用户有权限创建聊天室。聊天室成员数会受到版本指定聊天室最大成员数的限制。 | +| 创建聊天室 | 只有被赋予 [超级管理员](/document/v1/server-side/chatroom.html#管理超级管理员) 权限的用户有权限创建聊天室。聊天室成员数会受到版本指定聊天室最大成员数的限制。 | | 加入聊天室 | 没有被加入黑名单的所有 app 用户可自由加入聊天室。 | | 离开聊天室 | 所有聊天室成员都可以自由退出聊天室;也可能被动离开聊天室,原因分为:被管理员移出聊天室、聊天室解散和用户账号离线。 | | 销毁聊天室 | 需要聊天室所有者权限。 | diff --git a/docs/document/v1/web/sticker.md b/docs/document/v1/web/sticker.md new file mode 100644 index 000000000..a5d58fb4f --- /dev/null +++ b/docs/document/v1/web/sticker.md @@ -0,0 +1,32 @@ +## 导入第三方表情包 + +- 在项目下面新建一个文件夹,用于存放表情图片文件。 + +- 在引用了 SDK 之后执行如下代码: + +``` +WebIM.Emoji = { + path: 'demo/src/themes/faces/' /*表情包路径*/ + , map: { + '[):]': 'ee_1.png', + '[:D]': 'ee_2.png', + '[;)]': 'ee_3.png', + '[:-o]': 'ee_4.png', + '[:p]': 'ee_5.png' + } +}; +``` + +**注意:** + +- 全局变量 WebIM 添加一个 Emoji 属性 + +- path 表示表情图片存放的路径 + +- map 里面的 key 表示代表表情图片的字符 + +- value 表示表情图片的文件名。 + +发送和接收表情消息与文本消息类似,如果发送的文本消息中带有表情的 key 字符,SDK 会将此消息转换成表情图片的实际路径。 + +如:文本消息中包含 “[):]” 字符串,则解析为`WebIM.Emoji.path+WebIM.Emoji.map['[):]']= “demo/src/themes/faces/ee_1.png”`。 \ No newline at end of file diff --git a/docs/document/v1/web/thread.md b/docs/document/v1/web/thread.md index ad3e45ecb..39a61c0d6 100644 --- a/docs/document/v1/web/thread.md +++ b/docs/document/v1/web/thread.md @@ -4,9 +4,6 @@ 子区是群组成员的子集,是支持多人沟通的即时通讯系统,本文介绍如何使用环信即时通讯 IM SDK 在实时互动 app 中创建和管理子区,并实现子区相关功能。 -:::notice -私有化版本不支持子区功能。 -::: ## 技术原理 @@ -25,9 +22,8 @@ 开始前,请确保满足以下条件: - 完成 4.0.7 或以上版本 SDK 初始化,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -- 了解子区和子区成员数量限制,详见 [使用限制](/product/limitation.html)。 -- 联系商务开通子区功能。 +- 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 私有部署已开通子区功能。 ## 实现方法 diff --git a/docs/document/v1/web/thread_message.md b/docs/document/v1/web/thread_message.md index ecf271a27..a2afa075a 100644 --- a/docs/document/v1/web/thread_message.md +++ b/docs/document/v1/web/thread_message.md @@ -32,9 +32,8 @@ 开始前,请确保满足以下条件: - 完成 4.0.7 及以上版本 SDK 初始化,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM API 的 [使用限制](/product/limitation.html)。 -- 了解子区和子区成员数量限制,详见 [使用限制](/product/limitation.html)。 -- 联系商务开通子区功能。 +- 了解环信即时通讯 IM API 的 [使用限制](/document/v1/privatization/uc_limitation.html)。 +- 私有部署已开通子区功能。 ## 实现方法 diff --git a/docs/document/v1/web/toolrelated.md b/docs/document/v1/web/toolrelated.md new file mode 100644 index 000000000..5267f3292 --- /dev/null +++ b/docs/document/v1/web/toolrelated.md @@ -0,0 +1,80 @@ +# 工具类说明 + +## 文件上传下载判断 + +``` +//是否能上传file +WebIM.utils.isCanUploadFile; +//是否能下载file +WebIM.utils.isCanDownLoadFile ; +//是否设置header +WebIM.utils. isCanSetRequestHeader; +//是否设置mimetype +WebIM.utils.hasOverrideMimeType; +``` + +## 表情解析工具类 + +``` +WebIM.utils.parseEmoji(message); +``` + +## 格式化字符串类 + +目前只能解析字符串`%s` + +``` +WebIM.utils.sprintf(string[, args...]) +``` + +## 文件上传下载工具类 + +``` +var fileInfo = WebIM.utils.getFileUrl(fileInputId); + + +//上传 +var options = { + apiUrl:'//a1.easemob.com', + appName: 'chatdemoui', + orgName: 'easemob-demo', + appKey:'easemob-demo#chatdemoui', + file:fileInfo, + accessToken: 'YWMtjPPoovCqEeOQs7myPqqaOwAAAUaqNH0a8rRj4PwJLQju6-S47ZO6wYs3Lwo', + onFileUploadComplete: function ( data ) { //upload file success }, + onFileUploadError: function ( e ) { //upload file error } +}; + +WebIM.utils.uploadFile(options); + + + +//下载 +var options = { + responseType: 'blob',//default blob + mimeType: 'text/plain; charset=x-user-defined',//default + url:'http://s1.easemob.com/weiquan2/a2/chatfiles/0c0f5f3a-e66b-11e3-8863-f1c202c2b3ae', + secret: 'NSgGYPCxEeOou00jZasg9e-GqKUZGdph96EFxJ4WxW-qkxV4', + accessToken: 'YWMtjPPoovCqEeOQs7myPqqaOwAAAUaqNH0a8rRj4PwJLQju6-S47ZO6wYs3Lwo', + onFileDownloadComplete: function ( data ) { //download file success }, + onFileDownloadError: function ( e ) { //download file error } +}; + +WebIM.utils.download(options); +``` + +## 发送Ajax请求 + +``` +var options = { + dataType: 'text',//default + success: function () { //handle request success }, + error: function () { //handle request error }, + type: 'post',//default 'post' + url: 'http://s1.easemob.com/weiquan2/a2/chatfiles/0c0f5f3a-e66b-11e3-8863-f1c202c2b3ae', + headers: '',//default {} + data: '';//default null +}; + +WebIM.utils.ajax(options); +``` \ No newline at end of file diff --git a/docs/document/v1/web/user_relationship.md b/docs/document/v1/web/user_relationship.md index c9512245c..fbc4b4404 100644 --- a/docs/document/v1/web/user_relationship.md +++ b/docs/document/v1/web/user_relationship.md @@ -1,135 +1,150 @@ -# 管理用户关系 - - - -SDK 提供用户关系管理功能,包括好友列表管理和黑名单管理: -- 好友列表管理:查询好友列表、申请添加好友、同意好友申请、拒绝好友申请和删除好友等操作。 -- 黑名单管理:查询黑名单列表、添加用户至黑名单以及将用户移出黑名单等操作。 - -## 技术原理 - -环信即时通讯 IM Web SDK 提供以下好友管理功能: -- 请求添加好友; -- 接受和拒绝好友请求; -- 删除好友; -- 查询好友列表; -- 添加用户至黑名单; -- 将用户移出黑名单; -- 获取好友黑名单列表。 - -## 前提条件 - -开始前,请确保满足以下条件: -- 完成 SDK 初始化,并连接到服务器,详见 [快速开始](quickstart.html); -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 - -## 实现方法 - -### 管理联系人列表 - -#### 添加好友 - -本节主要介绍发送好友请求、接收好友请求、处理好友请求和好友请求处理结果回调等。 - -1. 调用 `conn.addEventHandler()` 注册监听好友状态,示例代码如下: - -```javascript -/** - * `msg` 为触发回调后的结果。 - * `contactEvent` 可自定义。 - * 下面的举例中,用户 A 为当前用户。 - */ -conn.addEventHandler("contactEvent", { - // 当前用户收到好友请求。用户 B 向用户 A 发送好友请求,用户 A 收到该事件。 - onContactInvited: function (msg) {}, - // 当前用户被其他用户从联系人列表上移除。用户 B 将用户 A 从联系人列表上删除,用户 A 收到该事件。 - onContactDeleted: function (msg) {}, - // 当前用户新增了联系人。用户 B 向用户 A 发送好友请求,用户 A 同意该请求,用户 A 收到该事件,而用户 B 收到 `onContactAgreed` 事件。 - onContactAdded: function (msg) {}, - // 当前用户发送的好友请求被拒绝。用户 A 向用户 B 发送好友请求,用户 B 收到好友请求后,拒绝加好友,则用户 A 收到该事件。 - onContactRefuse: function (msg) {}, - // 当前用户发送的好友请求经过了对方同意。用户 A 向用户 B 发送好友请求,用户 B 收到好友请求后,同意加好友,则用户 A 收到该事件。 - onContactAgreed: function (msg) {}, +# 好友管理 + +更新时间:2021-12-31 + +新版文档见:[用户关系管理](https://docs-im.easemob.com/ccim/web/relationship)。 + +好友管理能让您更好的体验 IM 功能,环信 Web IM SDK 支持好友体系管理,好友相关的操作如下: + +- 查询好友列表 + +- 监听好友状态事件 + +- 添加好友 + +- 处理好友请求 + +- 删除好友 + +- 黑名单 + +多种好友体系的管理操作,覆盖丰富的集成场景。 + +------ + +## 参数解释 + +| 名称 | 字段名 | 数据类型 | 描述 | +| :------ | :------- | :------- | :--------------------------------------------------- | +| 环信 ID | username | String | 环信 ID 是环信用户的唯一标识,在 AppKey 的范围内唯一 | + +## 查询好友列表 + +调用getRoster查询好友列表,示例代码如下: + +``` +conn.getRoster().then( (res) => { + console.log(res) // res.data > ['user1', 'user2'] }); ``` -2. 调用 `addContact` 请求添加好友,示例代码如下: +------ + +## 监听好友状态事件 + +通过在SDK conn.listen()中注册以下事件来监听好友状态, 示例代码如下: + +``` +conn.listen({ + onContactInvited: function(msg){}, // 收到好友邀请 + onContactDeleted: function(){}, // 被删除时回调此方法 + onContactAdded: function(){}, // 增加了联系人时回调此方法 + onContactRefuse: function(){}, // 好友请求被拒绝 + onContactAgreed: function(){} // 好友请求被同意 +}) +``` + +------ -```javascript -conn.addContact("userId", "加个好友呗!"); +## 添加好友 + +调用 addContact 添加好友,示例代码如下: + +``` +let message = '加个好友呗!'; +conn.addContact('username', message); ``` -3. 对端用户通过 `onContactInvited` 监听事件收到好友请求,确认是否成为好友。 - - 若接受好友请求,需调用 `acceptContactInvite` 方法。请求方收到 `onContactAgreed` 事件。 +------ + +## 处理好友请求 + +当收到**“添加好友”**的请求时,会有两种处理方式: + +- 同意添加对方为好友 - 示例代码如下: - - ```javascript - conn.acceptContactInvite("userId"); - ``` - - - 若拒绝好友请求,需调用 `declineContactInvite` 方法。请求方收到 `onContactRefuse` 事件。 - - 示例代码如下: - - ```javascript - conn.declineContactInvite("userId"); - ``` +- 拒绝添加对方为好友 -#### 删除好友 +具体代码实现示例如下: -删除联系人时会同时删除对方联系人列表中的该用户,建议执行双重确认,以免发生误删操作。删除操作不需要对方同意或者拒绝。 +### 同意添加对方为好友 -你可以调用 `deleteContact` 方法删除好友,示例代码如下: +调用 acceptInvitation 同意添加好友,示例代码如下: -```javascript -conn.deleteContact("userId"); +``` +conn.acceptInvitation('username') +``` + +### 拒绝添加对方为好友 + +调用 declineInvitation 拒绝添加好友,示例代码如下: + +``` +conn.declineInvitation('username') ``` -删除好友后,对方会收到 `onContactDeleted` 事件。 +------ -#### 获取好友列表 +## 删除好友 -你可以调用 `getContacts` 方法查询好友列表,示例代码如下: +调用 deleteContact 删除好友,代码示例如下: -```javascript -conn.getContacts().then((res) => { - console.log(res) // res.data > ['user1', 'user2'] -}) ``` +conn.deleteContact('username'); +``` + +------ + +## 黑名单 -### 管理黑名单 +集成黑名单操作中,有以下几种黑名单功能操作: -#### 添加用户至黑名单 +- 将好友加入黑名单 -你可以调用 `addUsersToBlocklist` 添加用户到黑名单。用户被加入黑名单后,无法向你发送消息,也无法发送好友申请。 +- 获取黑名单列表 -用户可以将任何其他用户添加到黑名单列表,无论该用户是否是好友。好友被加入黑名单后仍在好友列表上显示。 +- 将好友移除黑名单 -```javascript -conn.addUsersToBlocklist({ - //可以添加单个用户 ID 或批量添加多个用户 ID 组成的数组。 - name: ["user1", "user2"], +### 将好友加入黑名单 + +将好友加入黑名单后,对方好友列表依然可以看到己方,但无法向己方发送消息。 + +``` +// 用户ID,添加一个为单个用户ID;批量添加为用户ID数组,如["user1","user2",...] +conn.addToBlackList({ + name:['user1','user2'] }); ``` -#### 将用户移出黑名单 +------ -你可以调用 `removeUserFromBlocklist` 方法将用户移出黑名单,示例代码如下: +### 获取黑名单列表 -```javascript -conn.removeUserFromBlocklist({ - //可以添加单个用户 ID 或批量添加多个用户 ID 组成的数组。 - name: ["user1", "user2"], -}); +调用 getBlacklist 函数获取好友黑名单列表,示例代码如下: + +``` +conn.getBlacklist().then((res)=>{ + console.log('>>>>>>获取黑名单成功',res); // res.data > ['user1', 'user2'] + }) ``` -#### 获取黑名单列表 +------ -你可以调用 `getBlocklist` 方法获取用户黑名单列表,示例代码如下: +### 将好友移出黑名单 -```javascript -conn.getBlocklist().then((res) => { - console.log(res); -}); ``` +// 删除一个为单个用户ID;批量删除为用户ID数组,如["user1","user2"] +conn.removeFromBlackList({ + name: ['user1'] +}); +``` \ No newline at end of file diff --git a/docs/document/v1/web/user_relationship_v.md b/docs/document/v1/web/user_relationship_v.md new file mode 100644 index 000000000..dddaab540 --- /dev/null +++ b/docs/document/v1/web/user_relationship_v.md @@ -0,0 +1,135 @@ +# 管理用户关系 + + + +SDK 提供用户关系管理功能,包括好友列表管理和黑名单管理: +- 好友列表管理:查询好友列表、申请添加好友、同意好友申请、拒绝好友申请和删除好友等操作。 +- 黑名单管理:查询黑名单列表、添加用户至黑名单以及将用户移出黑名单等操作。 + +## 技术原理 + +环信即时通讯 IM Web SDK 提供以下好友管理功能: +- 请求添加好友; +- 接受和拒绝好友请求; +- 删除好友; +- 查询好友列表; +- 添加用户至黑名单; +- 将用户移出黑名单; +- 获取好友黑名单列表。 + +## 前提条件 + +开始前,请确保满足以下条件: +- 完成 SDK 初始化,详见 [快速开始](quickstart.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/document/v1/privatization/uc_limitation.html)。 + +## 实现方法 + +### 管理联系人列表 + +#### 添加好友 + +本节主要介绍发送好友请求、接收好友请求、处理好友请求和好友请求处理结果回调等。 + +1. 调用 `conn.addEventHandler()` 注册监听好友状态,示例代码如下: + +```javascript +/** + * `msg` 为触发回调后的结果。 + * `contactEvent` 可自定义。 + * 下面的举例中,用户 A 为当前用户。 + */ +conn.addEventHandler("contactEvent", { + // 当前用户收到好友请求。用户 B 向用户 A 发送好友请求,用户 A 收到该事件。 + onContactInvited: function (msg) {}, + // 当前用户被其他用户从联系人列表上移除。用户 B 将用户 A 从联系人列表上删除,用户 A 收到该事件。 + onContactDeleted: function (msg) {}, + // 当前用户新增了联系人。用户 B 向用户 A 发送好友请求,用户 A 同意该请求,用户 A 收到该事件,而用户 B 收到 `onContactAgreed` 事件。 + onContactAdded: function (msg) {}, + // 当前用户发送的好友请求被拒绝。用户 A 向用户 B 发送好友请求,用户 B 收到好友请求后,拒绝加好友,则用户 A 收到该事件。 + onContactRefuse: function (msg) {}, + // 当前用户发送的好友请求经过了对方同意。用户 A 向用户 B 发送好友请求,用户 B 收到好友请求后,同意加好友,则用户 A 收到该事件。 + onContactAgreed: function (msg) {}, +}); +``` + +2. 调用 `addContact` 请求添加好友,示例代码如下: + +```javascript +conn.addContact("userId", "加个好友呗!"); +``` + +3. 对端用户通过 `onContactInvited` 监听事件收到好友请求,确认是否成为好友。 + - 若接受好友请求,需调用 `acceptContactInvite` 方法。请求方收到 `onContactAgreed` 事件。 + + 示例代码如下: + + ```javascript + conn.acceptContactInvite("userId"); + ``` + + - 若拒绝好友请求,需调用 `declineContactInvite` 方法。请求方收到 `onContactRefuse` 事件。 + + 示例代码如下: + + ```javascript + conn.declineContactInvite("userId"); + ``` + +#### 删除好友 + +删除联系人时会同时删除对方联系人列表中的该用户,建议执行双重确认,以免发生误删操作。删除操作不需要对方同意或者拒绝。 + +你可以调用 `deleteContact` 方法删除好友,示例代码如下: + +```javascript +conn.deleteContact("userId"); +``` + +删除好友后,对方会收到 `onContactDeleted` 事件。 + +#### 获取好友列表 + +你可以调用 `getContacts` 方法查询好友列表,示例代码如下: + +```javascript +conn.getContacts().then((res) => { + console.log(res) // res.data > ['user1', 'user2'] +}) +``` + +### 管理黑名单 + +#### 添加用户至黑名单 + +你可以调用 `addUsersToBlocklist` 添加用户到黑名单。用户被加入黑名单后,无法向你发送消息,也无法发送好友申请。 + +用户可以将任何其他用户添加到黑名单列表,无论该用户是否是好友。好友被加入黑名单后仍在好友列表上显示。 + +```javascript +conn.addUsersToBlocklist({ + //可以添加单个用户 ID 或批量添加多个用户 ID 组成的数组。 + name: ["user1", "user2"], +}); +``` + +#### 将用户移出黑名单 + +你可以调用 `removeUserFromBlocklist` 方法将用户移出黑名单,示例代码如下: + +```javascript +conn.removeUserFromBlocklist({ + //可以添加单个用户 ID 或批量添加多个用户 ID 组成的数组。 + name: ["user1", "user2"], +}); +``` + +#### 获取黑名单列表 + +你可以调用 `getBlocklist` 方法获取用户黑名单列表,示例代码如下: + +```javascript +conn.getBlocklist().then((res) => { + console.log(res); +}); +``` diff --git a/docs/document/v1/web/userprofile.md b/docs/document/v1/web/userprofile.md index ae33c3add..981b403f8 100644 --- a/docs/document/v1/web/userprofile.md +++ b/docs/document/v1/web/userprofile.md @@ -8,6 +8,7 @@ 例如,在招聘场景下,利用用户属性功能可存储性别、邮箱、用户类型(面试者)、职位类型(Web 研发)等。查看用户信息时,可直接查询服务器存储的用户属性信息。 + \ No newline at end of file diff --git a/docs/document/v1/applet/multi_device .md b/docs/document/v2/applet/multi_device.md similarity index 100% rename from docs/document/v1/applet/multi_device .md rename to docs/document/v2/applet/multi_device.md diff --git a/docs/document/v2/privatization/uc_configure.md b/docs/document/v2/privatization/uc_configure.md index 7dfbf9102..584edbe6f 100644 --- a/docs/document/v2/privatization/uc_configure.md +++ b/docs/document/v2/privatization/uc_configure.md @@ -94,7 +94,7 @@ ![img](@static/images/privitization/deploy_push_callback.png) -3. 点击 **添加回调地址** 按钮,打开回调配置对话框,在回调配置对话框中,填写回调相关配置信息,点击 **保存** 按钮,完成回调配置,具体配置内容说明见 [回调配置](/document/server-side/callback.html#实现步骤)。 +3. 点击 **添加回调地址** 按钮,打开回调配置对话框,在回调配置对话框中,填写回调相关配置信息,点击 **保存** 按钮,完成回调配置,具体配置内容说明见 [回调配置](/document/v2/server-side/callback.html#实现步骤)。 ![img](@static/images/privitization/deploy_push_window.png) diff --git a/docs/document/v2/privatization/uc_deploy.md b/docs/document/v2/privatization/uc_deploy.md index bb3152936..b02fd5f19 100644 --- a/docs/document/v2/privatization/uc_deploy.md +++ b/docs/document/v2/privatization/uc_deploy.md @@ -16,9 +16,20 @@ 信息安全已成为国家重要安全战略,各行业客户对业务环境、功能及数据存储的安全性要求越来越高。需要将功能完备的即时通讯服务部署到内网物理服务器集群、公有云以及私有云等多种平台,请根据实际使用场景选择安装包及部署手册,下载后请按照部署手册要求准备环境并实施部署。 -| 安装包名称 | 适配环境要求 | 下载安装包 | 下载部署手册 | -| :------------------------------------- | :-------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 环信私有化即时通讯服务安装包(单机版) | 操作系统:Linux、ubuntu 20 及以上、centos 7 及以上 CPU 架构:X86(优先推荐)、ARM | [立即下载](https://zim-private.oss-cn-beijing.aliyuncs.com/zim/ZIM-23.1.5.x86_64-license/ZIM-23.1.5.x86_64.all.tar) | [立即下载](https://zim-private.oss-cn-beijing.aliyuncs.com/zim/ZIM-23.1.5.x86_64-license/%E7%8E%AF%E4%BF%A1%E7%A7%81%E6%9C%89%E5%8C%96IM%E9%83%A8%E7%BD%B2%E6%96%87%E6%A1%A320230516.pdf) | + + + + + + + + + + + + + +
安装包名称适配环境要求下载安装包下载部署手册
环信私有化即时通讯服务安装包(单机版)操作系统:Linux、ubuntu 20 及以上、centos 7 及以上
CPU 架构:X86、ARM
立即下载(X86)
立即下载(ARM)
立即下载
### 2.2 申请授权 diff --git a/static/images/privitization/3.3.5_certificate_add_success.png b/static/images/privitization/3.3.5_certificate_add_success.png new file mode 100644 index 000000000..6a3004c51 Binary files /dev/null and b/static/images/privitization/3.3.5_certificate_add_success.png differ diff --git a/static/images/privitization/3.3.5_cloud_messaging.png b/static/images/privitization/3.3.5_cloud_messaging.png new file mode 100644 index 000000000..bc2d37eee Binary files /dev/null and b/static/images/privitization/3.3.5_cloud_messaging.png differ diff --git a/static/images/privitization/3.3.5_config_download.png b/static/images/privitization/3.3.5_config_download.png new file mode 100644 index 000000000..bbe4b3f7d Binary files /dev/null and b/static/images/privitization/3.3.5_config_download.png differ diff --git a/static/images/privitization/3.3.5_config_location.png b/static/images/privitization/3.3.5_config_location.png new file mode 100644 index 000000000..bca2a1e67 Binary files /dev/null and b/static/images/privitization/3.3.5_config_location.png differ diff --git a/static/images/privitization/3_.png b/static/images/privitization/3_.png new file mode 100644 index 000000000..1746bcbd6 Binary files /dev/null and b/static/images/privitization/3_.png differ diff --git a/static/images/privitization/400webimintegration.jpeg b/static/images/privitization/400webimintegration.jpeg new file mode 100644 index 000000000..2e328293f Binary files /dev/null and b/static/images/privitization/400webimintegration.jpeg differ diff --git a/static/images/privitization/apns_create10.jpg b/static/images/privitization/apns_create10.jpg new file mode 100644 index 000000000..52371c0fe Binary files /dev/null and b/static/images/privitization/apns_create10.jpg differ diff --git a/static/images/privitization/apns_create11.jpg b/static/images/privitization/apns_create11.jpg new file mode 100644 index 000000000..c0aa084b2 Binary files /dev/null and b/static/images/privitization/apns_create11.jpg differ diff --git a/static/images/privitization/apns_create12.jpg b/static/images/privitization/apns_create12.jpg new file mode 100644 index 000000000..9839bbc95 Binary files /dev/null and b/static/images/privitization/apns_create12.jpg differ diff --git a/static/images/privitization/apns_create15.jpg b/static/images/privitization/apns_create15.jpg new file mode 100644 index 000000000..14892e15f Binary files /dev/null and b/static/images/privitization/apns_create15.jpg differ diff --git a/static/images/privitization/apns_create16.jpg b/static/images/privitization/apns_create16.jpg new file mode 100644 index 000000000..879672723 Binary files /dev/null and b/static/images/privitization/apns_create16.jpg differ diff --git a/static/images/privitization/apns_create17.jpg b/static/images/privitization/apns_create17.jpg new file mode 100644 index 000000000..9f8396341 Binary files /dev/null and b/static/images/privitization/apns_create17.jpg differ diff --git a/static/images/privitization/apns_create18.jpg b/static/images/privitization/apns_create18.jpg new file mode 100644 index 000000000..45c5a11b6 Binary files /dev/null and b/static/images/privitization/apns_create18.jpg differ diff --git a/static/images/privitization/apns_create19.jpg b/static/images/privitization/apns_create19.jpg new file mode 100644 index 000000000..96bafa2a4 Binary files /dev/null and b/static/images/privitization/apns_create19.jpg differ diff --git a/static/images/privitization/apns_create20.jpg b/static/images/privitization/apns_create20.jpg new file mode 100644 index 000000000..05efb8fb3 Binary files /dev/null and b/static/images/privitization/apns_create20.jpg differ diff --git a/static/images/privitization/apns_create21.jpg b/static/images/privitization/apns_create21.jpg new file mode 100644 index 000000000..2c963800d Binary files /dev/null and b/static/images/privitization/apns_create21.jpg differ diff --git a/static/images/privitization/apns_create9.jpg b/static/images/privitization/apns_create9.jpg new file mode 100644 index 000000000..92fdb9ce5 Binary files /dev/null and b/static/images/privitization/apns_create9.jpg differ diff --git a/static/images/privitization/apns_image006.png b/static/images/privitization/apns_image006.png new file mode 100644 index 000000000..5967513fd Binary files /dev/null and b/static/images/privitization/apns_image006.png differ diff --git a/static/images/privitization/apns_image007.png b/static/images/privitization/apns_image007.png new file mode 100644 index 000000000..36a55079b Binary files /dev/null and b/static/images/privitization/apns_image007.png differ diff --git a/static/images/privitization/apns_setting_1.jpg b/static/images/privitization/apns_setting_1.jpg new file mode 100644 index 000000000..0206568c2 Binary files /dev/null and b/static/images/privitization/apns_setting_1.jpg differ diff --git a/static/images/privitization/apns_setting_10.jpg b/static/images/privitization/apns_setting_10.jpg new file mode 100644 index 000000000..0215a9b5b Binary files /dev/null and b/static/images/privitization/apns_setting_10.jpg differ diff --git a/static/images/privitization/apns_setting_11.jpg b/static/images/privitization/apns_setting_11.jpg new file mode 100644 index 000000000..365601a14 Binary files /dev/null and b/static/images/privitization/apns_setting_11.jpg differ diff --git a/static/images/privitization/apns_setting_12.jpg b/static/images/privitization/apns_setting_12.jpg new file mode 100644 index 000000000..8bbdfaa94 Binary files /dev/null and b/static/images/privitization/apns_setting_12.jpg differ diff --git a/static/images/privitization/apns_setting_2.jpg b/static/images/privitization/apns_setting_2.jpg new file mode 100644 index 000000000..1d092ce64 Binary files /dev/null and b/static/images/privitization/apns_setting_2.jpg differ diff --git a/static/images/privitization/apns_setting_3.jpg b/static/images/privitization/apns_setting_3.jpg new file mode 100644 index 000000000..7b4846f8f Binary files /dev/null and b/static/images/privitization/apns_setting_3.jpg differ diff --git a/static/images/privitization/apns_setting_4.jpg b/static/images/privitization/apns_setting_4.jpg new file mode 100644 index 000000000..2418c8bfe Binary files /dev/null and b/static/images/privitization/apns_setting_4.jpg differ diff --git a/static/images/privitization/apns_setting_5.jpg b/static/images/privitization/apns_setting_5.jpg new file mode 100644 index 000000000..2ad468e4d Binary files /dev/null and b/static/images/privitization/apns_setting_5.jpg differ diff --git a/static/images/privitization/apns_setting_6.jpg b/static/images/privitization/apns_setting_6.jpg new file mode 100644 index 000000000..f3ae1221c Binary files /dev/null and b/static/images/privitization/apns_setting_6.jpg differ diff --git a/static/images/privitization/apns_setting_7.jpg b/static/images/privitization/apns_setting_7.jpg new file mode 100644 index 000000000..2746baaa5 Binary files /dev/null and b/static/images/privitization/apns_setting_7.jpg differ diff --git a/static/images/privitization/apns_setting_8.jpg b/static/images/privitization/apns_setting_8.jpg new file mode 100644 index 000000000..32d252705 Binary files /dev/null and b/static/images/privitization/apns_setting_8.jpg differ diff --git a/static/images/privitization/apns_setting_9.jpg b/static/images/privitization/apns_setting_9.jpg new file mode 100644 index 000000000..f0be17d33 Binary files /dev/null and b/static/images/privitization/apns_setting_9.jpg differ diff --git a/static/images/privitization/choice.png b/static/images/privitization/choice.png new file mode 100644 index 000000000..27e52a6d1 Binary files /dev/null and b/static/images/privitization/choice.png differ diff --git a/static/images/privitization/development-framework.png b/static/images/privitization/development-framework.png new file mode 100644 index 000000000..86c787982 Binary files /dev/null and b/static/images/privitization/development-framework.png differ diff --git a/static/images/privitization/image005.png b/static/images/privitization/image005.png new file mode 100644 index 000000000..2b6401019 Binary files /dev/null and b/static/images/privitization/image005.png differ diff --git a/static/images/privitization/image006.png b/static/images/privitization/image006.png new file mode 100644 index 000000000..ff0b0fcde Binary files /dev/null and b/static/images/privitization/image006.png differ diff --git a/static/images/privitization/image010.png b/static/images/privitization/image010.png new file mode 100644 index 000000000..6d58854a8 Binary files /dev/null and b/static/images/privitization/image010.png differ diff --git a/static/images/privitization/prepare1.png b/static/images/privitization/prepare1.png new file mode 100644 index 000000000..6ddbc8a72 Binary files /dev/null and b/static/images/privitization/prepare1.png differ diff --git a/static/images/privitization/prepare2.png b/static/images/privitization/prepare2.png new file mode 100644 index 000000000..5fb9b08ab Binary files /dev/null and b/static/images/privitization/prepare2.png differ diff --git a/static/images/privitization/push_cert.png b/static/images/privitization/push_cert.png new file mode 100644 index 000000000..018b231c8 Binary files /dev/null and b/static/images/privitization/push_cert.png differ diff --git a/static/images/privitization/push_setcert.png b/static/images/privitization/push_setcert.png new file mode 100644 index 000000000..3d4427728 Binary files /dev/null and b/static/images/privitization/push_setcert.png differ diff --git a/static/images/privitization/upload.png b/static/images/privitization/upload.png new file mode 100644 index 000000000..d79c1095f Binary files /dev/null and b/static/images/privitization/upload.png differ diff --git "a/static/images/privitization/\346\267\273\345\212\240\350\260\267\346\255\214\350\257\201\344\271\246.png" "b/static/images/privitization/\346\267\273\345\212\240\350\260\267\346\255\214\350\257\201\344\271\246.png" new file mode 100644 index 000000000..91563e80a Binary files /dev/null and "b/static/images/privitization/\346\267\273\345\212\240\350\260\267\346\255\214\350\257\201\344\271\246.png" differ