From 1cb2a38b9d63d9cd75fe5a0fcaca35cace180a13 Mon Sep 17 00:00:00 2001 From: haoxiuwen Date: Wed, 18 Jun 2025 18:57:43 +0800 Subject: [PATCH 1/3] Modify Message --- docs/.vuepress/sidebar/document.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/.vuepress/sidebar/document.ts b/docs/.vuepress/sidebar/document.ts index de63b03c8..463f480d5 100644 --- a/docs/.vuepress/sidebar/document.ts +++ b/docs/.vuepress/sidebar/document.ts @@ -55,7 +55,8 @@ const documentSidebar = [ collapsible: true, children: [ { text: '消息概述', link: 'message_overview.html' }, - { text: '发送和接收消息', link: 'message_send_receive.html' }, + { text: '发送消息', link: 'message_send.html' }, + { text: '接收消息', link: 'message_receive.html' }, { text: '获取历史消息', link: 'message_retrieve.html' }, { text: '撤回消息', link: 'message_recall.html' }, { text: '搜索消息', link: 'message_search.html', except: ['web']}, @@ -66,6 +67,8 @@ const documentSidebar = [ { text: '导入和插入消息', link: 'message_import_insert.html', except: ['web']}, { text: '更新消息', link: 'message_update.html', except: ['web']}, { text: '删除消息', link: 'message_delete.html' }, + { text: '定向消息', link: 'message_target.html' }, + { text: '消息扩展', link: 'message_extension.html' }, { text: '置顶消息', link: 'message_pin.html'}, { text: '翻译消息', link: 'message_translation.html', except: ['harmonyos']}, { text: '只投在线用户', link: 'message_deliver_only_online.html'}, @@ -225,13 +228,16 @@ const documentSidebar = [ collapsible: true, children: [ { text: '消息概述', link: 'message_overview.html' }, - { text: '发送和接收消息', link: 'message_send_receive.html' }, + { text: '发送消息', link: 'message_send.html' }, + { text: '接收消息', link: 'message_receive.html' }, { text: '获取历史消息', link: 'message_retrieve.html' }, { text: '撤回消息', link: 'message_recall.html' }, { text: '消息回执', link: 'message_receipt.html' }, { text: '消息表情回复', link: 'reaction.html' }, { text: '修改消息', link: 'message_modify.html' }, { text: '删除消息', link: 'message_delete.html' }, + { text: '定向消息', link: 'message_target.html' }, + { text: '消息扩展', link: 'message_extension.html' }, { text: '置顶消息', link: 'message_pin.html' }, { text: '翻译消息', link: 'message_translation.html' }, { text: '只投在线用户', link: 'message_deliver_only_online.html'}, From 0e7134769a7906c7b16130ecc6ebce871e027469 Mon Sep 17 00:00:00 2001 From: haoxiuwen Date: Wed, 18 Jun 2025 22:39:42 +0800 Subject: [PATCH 2/3] Split SDK Message Sending and Receiving Docs --- docs/document/android/message_extension.md | 15 + docs/document/android/message_receive.md | 271 ++++++++ docs/document/android/message_send.md | 325 +++++++++ docs/document/android/message_send_receive.md | 615 ----------------- docs/document/android/message_target.md | 34 + docs/document/applet/message_extension.md | 31 + docs/document/applet/message_receive.md | 175 +++++ ...essage_send_receive.md => message_send.md} | 292 +-------- docs/document/applet/message_target.md | 44 ++ docs/document/flutter/message_extension.md | 17 + docs/document/flutter/message_receive.md | 272 ++++++++ docs/document/flutter/message_send.md | 283 ++++++++ docs/document/flutter/message_send_receive.md | 616 ------------------ docs/document/flutter/message_target.md | 34 + docs/document/harmonyos/message_extension.md | 32 + docs/document/harmonyos/message_receive.md | 262 ++++++++ docs/document/harmonyos/message_send.md | 317 +++++++++ .../harmonyos/message_send_receive.md | 601 ----------------- docs/document/harmonyos/message_target.md | 32 + docs/document/ios/message_extension.md | 22 + docs/document/ios/message_receive.md | 223 +++++++ ...essage_send_receive.md => message_send.md} | 337 ++-------- docs/document/ios/message_target.md | 36 + .../react-native/message_extension.md | 14 + docs/document/react-native/message_receive.md | 171 +++++ ...essage_send_receive.md => message_send.md} | 243 +------ docs/document/react-native/message_target.md | 32 + docs/document/unity/message_extension.md | 34 + docs/document/unity/message_receive.md | 270 ++++++++ ...essage_send_receive.md => message_send.md} | 339 ++-------- docs/document/unity/message_target.md | 45 ++ docs/document/web/message_extension.md | 31 + docs/document/web/message_receive.md | 176 +++++ ...essage_send_receive.md => message_send.md} | 289 +------- docs/document/web/message_target.md | 44 ++ docs/document/windows/message_extension.md | 34 + docs/document/windows/message_receive.md | 270 ++++++++ ...essage_send_receive.md => message_send.md} | 339 ++-------- docs/document/windows/message_target.md | 45 ++ 39 files changed, 3818 insertions(+), 3444 deletions(-) create mode 100644 docs/document/android/message_extension.md create mode 100644 docs/document/android/message_receive.md create mode 100644 docs/document/android/message_send.md delete mode 100644 docs/document/android/message_send_receive.md create mode 100644 docs/document/android/message_target.md create mode 100644 docs/document/applet/message_extension.md create mode 100644 docs/document/applet/message_receive.md rename docs/document/applet/{message_send_receive.md => message_send.md} (66%) create mode 100644 docs/document/applet/message_target.md create mode 100644 docs/document/flutter/message_extension.md create mode 100644 docs/document/flutter/message_receive.md create mode 100644 docs/document/flutter/message_send.md delete mode 100644 docs/document/flutter/message_send_receive.md create mode 100644 docs/document/flutter/message_target.md create mode 100644 docs/document/harmonyos/message_extension.md create mode 100644 docs/document/harmonyos/message_receive.md create mode 100644 docs/document/harmonyos/message_send.md delete mode 100644 docs/document/harmonyos/message_send_receive.md create mode 100644 docs/document/harmonyos/message_target.md create mode 100644 docs/document/ios/message_extension.md create mode 100644 docs/document/ios/message_receive.md rename docs/document/ios/{message_send_receive.md => message_send.md} (52%) create mode 100644 docs/document/ios/message_target.md create mode 100644 docs/document/react-native/message_extension.md create mode 100644 docs/document/react-native/message_receive.md rename docs/document/react-native/{message_send_receive.md => message_send.md} (56%) create mode 100644 docs/document/react-native/message_target.md create mode 100644 docs/document/unity/message_extension.md create mode 100644 docs/document/unity/message_receive.md rename docs/document/unity/{message_send_receive.md => message_send.md} (54%) create mode 100644 docs/document/unity/message_target.md create mode 100644 docs/document/web/message_extension.md create mode 100644 docs/document/web/message_receive.md rename docs/document/web/{message_send_receive.md => message_send.md} (65%) create mode 100644 docs/document/web/message_target.md create mode 100644 docs/document/windows/message_extension.md create mode 100644 docs/document/windows/message_receive.md rename docs/document/windows/{message_send_receive.md => message_send.md} (54%) create mode 100644 docs/document/windows/message_target.md diff --git a/docs/document/android/message_extension.md b/docs/document/android/message_extension.md new file mode 100644 index 000000000..f9ad35937 --- /dev/null +++ b/docs/document/android/message_extension.md @@ -0,0 +1,15 @@ +# 消息扩展 + +当 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/android/message_receive.md b/docs/document/android/message_receive.md new file mode 100644 index 000000000..325c5534b --- /dev/null +++ b/docs/document/android/message_receive.md @@ -0,0 +1,271 @@ +# 接收消息 + +环信即时通讯 IM Android SDK 通过 [EMMessageListener](https://sdkdocs.easemob.com/apidoc/android/chat3.0/interfacecom_1_1hyphenate_1_1_e_m_message_listener.html) 类实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +- 你可以用注册监听 [EMMessageListener](https://sdkdocs.easemob.com/apidoc/android/chat3.0/interfacecom_1_1hyphenate_1_1_e_m_message_listener.html) 接收消息。该 [EMMessageListener](https://sdkdocs.easemob.com/apidoc/android/chat3.0/interfacecom_1_1hyphenate_1_1_e_m_message_listener.html) 可以多次添加,请记得在不需要的时候移除 `listener`,如在 `activity` 的 `onDestroy()` 时。 +- 在新消息到来时,你会收到 `onMessageReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `EMOptions#setIncludeSendMessageInMessageListener` 开关,则该回调中会返回发送成功的消息。 +- 对于聊天室消息,你可以通过消息的 `EMMessage#isBroadcast` 属性判断该消息是否为 [通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```java +EMMessageListener msgListener = new EMMessageListener() { + + // 收到消息,遍历消息队列,解析和显示。 + @Override + public void onMessageReceived(List messages) { + + } +}; +// 注册消息监听 +EMClient.getInstance().chatManager().addMessageListener(msgListener); +// 解注册消息监听 +EMClient.getInstance().chatManager().removeMessageListener(msgListener); +``` + +## 接收附件消息 + +除文本消息外,SDK 还支持接收附件类型消息,包括语音、图片、视频和文件消息。 + +附件消息的接收过程如下: + +1. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 +2. 获取附件的服务器地址和本地路径。 + +自 4.14.0 版本开始,即时通讯 IM 支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户必须调用 SDK 的 `downloadAttachment` 方法下载消息附件。 + +### 接收语音消息 + +1. 接收方收到语音消息时,自动下载语音文件。 +2. 接收方收到 [onMessageReceived 回调](#接收文本消息),调用 `getRemoteUrl` 或 `getLocalUri` 方法获取语音文件的服务器地址或本地路径,从而获取语音文件。 + +```java +EMVoiceMessageBody voiceBody = (EMVoiceMessageBody) msg.getBody(); +// 获取语音文件在服务器的地址。 +String voiceRemoteUrl = voiceBody.getRemoteUrl(); +// 本地语音文件的资源路径。 +Uri voiceLocalUri = voiceBody.getLocalUri(); +``` + +### 接收图片消息 + +1. 接收方收到图片消息,自动下载图片缩略图。 + +- 默认情况下,SDK 自动下载缩略图,即 `EMClient.getInstance().getOptions().setAutoDownloadThumbnail(true)`。 +- 若设置为手动下载缩略图,即 `EMClient.getInstance().getOptions().setAutoDownloadThumbnail(false)`,需调用 `EMClient.getInstance().chatManager().downloadThumbnail(message)` 下载。 + +2. 接收方收到 [onMessageReceived 回调](#接收文本消息),调用 `downloadAttachment` 下载原图。 + +```java +@Override +public void onMessageReceived(List messages) { + for(EMMessage message : messages) { + if (message.getType() == Type.IMAGE) { + message.setMessageStatusCallback(new EMCallBack() { + @Override + public void onSuccess() { + // 附件下载成功 + } + @Override + public void onError(int code, String error) { + // 附件下载失败 + } + + @Override + public void onProgress(int progress, String status) { + // 附件下载进度 + } + + }); + // 下载附件 + EMClient.getInstance().chatManager().downloadAttachment(message); + } + } +} +``` + +3. 获取图片消息的缩略图和附件。 + +```java +EMImageMessageBody imgBody = (EMImageMessageBody) message.getBody(); +// 从服务器端获取图片文件。 +String imgRemoteUrl = imgBody.getRemoteUrl(); +// 从服务器端获取图片缩略图。 +String thumbnailUrl = imgBody.getThumbnailUrl(); +// 从本地获取图片文件。 +Uri imgLocalUri = imgBody.getLocalUri(); +// 从本地获取图片缩略图。 +Uri thumbnailLocalUri = imgBody.thumbnailLocalUri(); +``` + +### 接收 GIF 图片消息 + +自 Android SDK 4.14.0 开始,支持接收 GIF 图片消息。 + +图片缩略图的下载与普通图片消息相同,详见 [接收图片消息](#接收图片消息)。 + +与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onMessageReceived` 回调方法。接收方判断为图片消息后,读取消息体的 `isGif` 属性,若值是 `YES`, 则为 GIF 图片消息。 + +```java +public void onMessageReceived(List messages) { + for(EMMessage message : messages) { + if (message.getType() == Type.IMAGE && ) { + EMImageMessageBody body = (EMImageMessageBody) msg.getBody(); + if(body.isGif()) { + // 根据业务情况处理gif message, 例如下载展示该消息 + } + } + } + +} +``` + +### 接收视频消息 + +1. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见 [设置图片缩略图自动下载](#接收图片消息)。 +2. 接收方收到 [onMessageReceived 回调](#接收文本消息),可以调用 `EMClient.getInstance().chatManager().downloadAttachment(message)` 方法下载视频原文件。 + +```java +/** + * 下载视频文件。 + */ +private void downloadVideo(final EMMessage message) { + message.setMessageStatusCallback(new EMCallBack() { + @Override + public void onSuccess() { + } + + @Override + public void onProgress(final int progress,String status) { + } + + @Override + public void onError(final int error, String msg) { + } + }); + // 下载附件 + EMClient.getInstance().chatManager().downloadAttachment(message); +} +``` + +3. 获取视频缩略图和视频原文件。 + +```java +// 从服务器端获取视频文件。 +String imgRemoteUrl = ((EMVideoMessageBody) body).getRemoteUrl(); +// 从服务器获取视频缩略图文件。 +String thumbnailUrl = ((EMVideoMessageBody) body).getThumbnailUrl(); +// 从本地获取视频文件文件。 +Uri localUri = ((EMVideoMessageBody) body).getLocalUri(); +// 从本地获取视频缩略图文件。 +Uri localThumbUri = ((EMVideoMessageBody) body).thumbnailLocalUri(); +``` + +### 接收文件消息 + +1. 接收方收到 [onMessageReceived 回调](#接收文本消息),调用 `downloadAttachment` 方法下载文件。 + +```java +/** + * 下载文件。 + */ +private void downloadFile(final EMMessage message) { + message.setMessageStatusCallback(new CallBack() { + @Override + public void onSuccess() { + } + + @Override + public void onProgress(final int progress,String status) { + } + + @Override + public void onError(final int error, String msg) { + } + }); + // 下载附件 + EMClient.getInstance().chatManager().downloadAttachment(message); +} +``` + +2. 调用以下方法从服务器或本地获取文件附件: + +```java +EMNormalFileMessageBody fileMessageBody = (EMNormalFileMessageBody) message.getBody(); +// 从服务器获取文件。 +String fileRemoteUrl = fileMessageBody.getRemoteUrl(); +// 从本地获取文件。 +Uri fileLocalUri = fileMessageBody.getLocalUri(); +``` + +## 接收位置消息 + +接收位置消息与文本消息一致,详见[接收文本消息](#接收文本消息)。 + +接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +## 接收透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +接收方通过 `onMessageReceived` 和 `onCmdMessageReceived` 回调接收透传消息,方便用户进行不同的处理。 + +```java +EMMessageListener msgListener = new EMMessageListener(){ + // 收到消息。 + @Override + public void onMessageReceived(List messages) { + } + // 收到透传消息。 + @Override + public void onCmdMessageReceived(List messages) { + } +} +``` + +## 接收自定义类型消息 + +你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +接收自定义消息与其他类型消息一致,详见[接收文本消息](#接收文本消息)。 + +## 接收合并消息 + +为了方便消息互动,即时通讯 IM 自 4.1.0 版本开始支持将多个消息合并在一起进行转发。 + +接收合并消息与接收普通消息的操作相同,详见[接收文本消息](#接收文本消息)。 + +- 对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 +- 合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 +- 对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: + - 若附件已存在,该方法会直接解析附件并返回原始消息列表。 + - 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 + +```java +EMClient.getInstance().chatManager().downloadAndParseCombineMessage(combineMessage, new EMValueCallBack>() { + @Override + public void onSuccess(List value) { + // 处理并展示消息列表 + } + + @Override + public void onError(int error, String errorMsg) { + // 处理出错信息 + } +}); +``` + diff --git a/docs/document/android/message_send.md b/docs/document/android/message_send.md new file mode 100644 index 000000000..0c83c3c70 --- /dev/null +++ b/docs/document/android/message_send.md @@ -0,0 +1,325 @@ +# 发送消息 + +环信即时通讯 IM Android SDK 通过 [EMChatManager](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_chat_manager.html)、[EMMessage](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_message.html) 和 [EMOptions](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_options.html) 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 + +- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要 [开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 +- 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 +- 关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 发送文本消息 + +1. 发送方调用 [EMMessage#createTextSendMessage](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_message.html) 方法构造一条消息。 + +默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 + +```java +// 创建一条文本消息,`content` 为消息文字内容。 +// `conversationId` 为消息接收方,单聊时为对端用户 ID、群聊时为群组 ID,聊天室时为聊天室 ID。 +EMMessage message = EMMessage.createTextSendMessage(content, conversationId); +// 会话类型:单聊为 EMMessage.ChatType.Chat,群聊为 EMMessage.ChatType.GroupChat, 聊天室为EMMessage.ChatType.ChatRoom,默认为单聊。 +message.setChatType(EMMessage.ChatType.Chat); +// 发送消息。 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +2. 发送方调用 [EMChatManager#sendMessage](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_chat_manager.html) 发送消息。 + + 发送消息时可以设置 [EMCallBack](https://sdkdocs.easemob.com/apidoc/android/chat3.0/interfacecom_1_1hyphenate_1_1_e_m_call_back.html) 的实例,获取消息发送状态。 + +```java +// 发送消息时可以设置 `EMCallBack` 的实例,获得消息发送的状态。可以在该回调中更新消息的显示状态。例如消息发送失败后的提示等等。 +message.setMessageStatusCallback(new EMCallBack() { + @Override + public void onSuccess() { + // 发送消息成功 + } + @Override + public void onError(int code, String error) { + // 发送消息失败 + } + @Override + public void onProgress(int progress, String status) { + + } + + }); + // 发送消息。 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +## 发送附件消息 + +除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 + +发送附件消息分为以下两步: + +1. 创建和发送附件类型消息。 +2. SDK 将附件上传到环信服务器。 + +### 发送语音消息 + +1. 发送语音消息前,在应用层录制语音文件。 +2. 发送方调用 `EMMessage#createVoiceSendMessage` 方法传入语音文件的 URI、语音时长和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建语音消息。 +3. 发送方调用 `EMChatManager#sendMessage` 方法发送消息。SDK 会将语音文件上传至环信服务器。 + +```java +// `voiceUri` 为语音文件的本地资源标志符,`duration` 为语音时长(单位为秒)。 +EMMessage message = EMMessage.createVoiceSendMessage(voiceUri, duration, toChatUsername); +// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +// message.setChatType(ChatType.GroupChat); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 发送图片消息 + +1. 发送方调用 `EMMessage#createImageSendMessage` 方法传入图片的本地资源标志符 URI、设置是否发送原图以及接收方的用户 ID (群聊或聊天室分别为群组 ID 或聊天室 ID)创建图片消息。 +2. 发送方调用 `EMChatManager#sendMessage` 方法发送该消息。 + +```java +// `imageUri` 为图片本地资源标志符,`false` 为不发送原图(默认超过 100 KB 的图片会压缩后发给对方),若需要发送原图传 `true`,即设置 `original` 参数为 `true`。 +EMMessage message = EMMessage.createImageSendMessage(imageUri, false, toChatUsername); +// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +// message.setChatType(ChatType.GroupChat); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 发送 GIF 图片消息 + +- 自 Android SDK 4.14.0 开始,支持发送 GIF 图片消息。 +- GIF 图片消息是一种特殊的图片消息,与普通图片消息不同,**GIF 图片发送时不能压缩**。 + +发送 GIF 图片消息的过程如下: + +1. 发送方调用 `EMMessage#createGifImageMessage` 方法构造 GIF 图片消息体。 +2. 发送方调用 `EMChatManager#sendMessage` 发送 GIF 图片消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 + +```java +// `imageUri` 为图片本地资源标志符 +EMMessage message = EMMessage.createGifImageMessage(imageUri, toChatUsername); +// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +// message.setChatType(ChatType.GroupChat); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 发送视频消息 + +1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 +2. 发送方调用 `EMMessage#createVideoSendMessage` 方法传入视频文件的本地资源标志符、缩略图的本地存储路径、视频时长以及接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID) 创建视频消息。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `thumbPath` 方法。 +3. 发送方调用 `EMChatManager#sendMessage` 方法发送视频消息。SDK 会将视频文件上传至消息服务器。 + +```java +// 在应用层获取视频首帧,你需要自己实现 getThumbPath 方法。 +String thumbPath = getThumbPath(videoUri); +EMMessage message = EMMessage.createVideoSendMessage(videoUri, thumbPath, videoLength, toChatUsername); +// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +// message.setChatType(ChatType.GroupChat); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 发送文件消息 + +1. 发送方调用 `EMMessage#createFileSendMessage` 方法传入文件的本地资源标志符和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建文件消息。 +2. 发送方调用 `EMChatManager#sendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 + +```java +// `fileLocalUri` 为本地资源标志符。 +EMMessage message = EMMessage.createFileSendMessage(fileLocalUri, toChatUsername); +// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +// message.setChatType(ChatType.GroupChat); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +## 发送位置消息 + +1. 发送方调用 `EMMessage#createLocationSendMessage` 方法创建位置消息。 +2. 发送方调用 `EMChatManager#sendMessage` 方法发送位置消息。 + +发送位置时,需要集成第三方地图服务,获取到位置点的经纬度信息。 + +```java +// `latitude` 为纬度,`longitude` 为经度,`locationAddress` 为具体位置内容。 +EMMessage message = EMMessage.createLocationSendMessage(latitude, longitude, locationAddress, toChatUsername); +// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +// message.setChatType(ChatType.GroupChat); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(message); +``` + +## 发送透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +发送透传消息的过程如下: + +1. 发送方调用 `EMMessage#createSendMessage` 方法创建透传消息。 +2. 发送方调用 `EMChatManager#sendMessage` 方法发送透传消息。 + +```java +EMMessage cmdMsg = EMMessage.createSendMessage(EMMessage.Type.CMD); +// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +// 若为群聊,添加下行代码。 +// cmdMsg.setChatType(EMMessage.ChatType.GroupChat); +// 若为聊天室,添加下行代码。 +// cmdMsg.setChatType(EMMessage.ChatType.ChatRoom); + +String action="action1"; +// `action` 可以自定义。 +EMCmdMessageBody cmdBody = new EMCmdMessageBody(action); +String toUsername = "test1"; +// 对于单聊,传入接收方的用户 ID,群聊传入群组 ID,聊天室传入聊天室 ID。 +cmdMsg.setTo(toUsername); +cmdMsg.addBody(cmdBody); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(cmdMsg); +``` + +## 发送自定义类型消息 + +你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +1. 发送方调用 `EMMessage#createSendMessage` 方法创建自定义消息。 +2. 发送方调用 `EMChatManager#sendMessage` 方法发送自定义消息。 + +```java +EMMessage customMessage = EMMessage.createSendMessage(EMMessage.Type.CUSTOM); +// `event` 为需要传递的自定义消息事件,比如礼物消息,可以设置: +String event = "gift"; +EMCustomMessageBody customBody = new EMCustomMessageBody(event); +// `params` 类型为 `Map`。 +customBody.setParams(params); +customMessage.addBody(customBody); +// `to` 指定接收方,单聊、群聊和聊天室分别为对端用户 ID、群组 ID 和聊天室 ID。 +customMessage.setTo(to); +// 对于单聊、群群聊或聊天室,`chatType` 分别为 `Chat`、`GroupChat` 和 `ChatRoom`,默认是单聊。 +customMessage.setChatType(chatType); +// 发送消息 +EMClient.getInstance().chatManager().sendMessage(customMessage); +``` + +## 发送合并消息 + +为了方便消息互动,即时通讯 IM 自 4.1.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: + +1. 利用原始消息列表创建一条合并消息。 +2. 发送合并消息。 + +你可以调用 `createCombinedSendMessage` 方法创建一条合并消息,然后调用 `sendMessage` 方法发送该条消息。 + +创建合并消息时,需要设置以下参数: + +| 属性 | 类型 | 描述 | +| :-------------- | :-------------------- | :-------------------- | +| `title` | String | 合并消息的标题。 | +| `summary` | String | 合并消息的概要。 | +| `compatibleText` | String | 合并消息的兼容文本。
兼容文本起向下兼容不支持消息合并转发的版本的作用。当支持合并消息的 SDK 向不支持合并消息的低版本 SDK 发送消息时,低版本的 SDK 会将该属性解析为文本消息的消息内容。 | +| `messageIdList` | List | 合并消息的原始消息 ID 列表。该列表最多包含 300 个消息 ID。 | +| `userId` | String | 消息接收方。该字段的设置取决于会话类型:
- 单聊:对方用户 ID;
- 群聊:群组 ID;
- 子区会话:子区 ID;
- 聊天室聊天:聊天室 ID。| + +:::tip +1. 合并转发支持嵌套,最多支持 10 层嵌套,每层最多 300 条消息。 +2. 不论 `EMOptions#setAutoTransferMessageAttachments` 设置为 `false` 或 `true`,SDK 都会将合并消息附件上传到环信服务器。 +3. 合并消息不支持搜索。 +4. 对于转发合并消息,例如,用户 A 向用户 B 发送了合并消息,用户 B 将该合并消息转发给用户 C,需要调用转发单条合并消息的 API。详见 [转发单条消息](message_forward.html#转发单条消息)。 +::: + +示例代码如下: + +```java +String title = "A和B的聊天记录"; +String summary = "A:这是A的消息内容\nB:这是B的消息内容"; +String compatibleText = "您当前的版本不支持该消息,请升级到最新版本"; +// 添加原消息 ID。 +ArrayList msgIdList = new ArrayList<>(); +msgIdList.add("1390191369179366180"); +msgIdList.add("1390191426268037924"); +msgIdList.add("1390186040483906340"); +EMMessage message = EMMessage.createCombinedSendMessage(title, summary, compatibleText, msgIdList, receiverId); +message.setMessageStatusCallback(new EMCallBack() { + @Override + public void onSuccess() { + // 消息发送成功的处理逻辑 + } + + @Override + public void onError(int code, String error) { + // 消息发送失败的处理逻辑 + } +}); +EMClient.getInstance().chatManager().sendMessage(message); +``` + +## 更多 + +### 聊天室消息优先级与消息丢弃逻辑 + +- **消息优先级**:对于聊天室消息,环信即时通讯提供消息分级功能,支持高、普通和低三种优先级,高优先级的消息会优先送达。你可以在创建消息时对指定消息类型或指定成员的消息设置为高优先级,确保这些消息优先送达。这种方式可以确保在聊天室内消息并发量较大或消息发送频率过高的情况下,服务器首先丢弃低优先级消息,将资源留给高优先级消息,确保重要消息(如打赏、公告等)优先送达,以此提升重要消息的可靠性。请注意,该功能并不保证高优先级消息必达。在聊天室内消息并发量过大的情况下,为保证用户实时互动的流畅性,即使是高优先级消息仍然会被丢弃。 + +- **消息丢弃逻辑**:对于单个聊天室,每秒发送的消息数量默认超过 20 条,则会触发消息丢弃逻辑,即首先丢弃低优先级的消息,优先保留高优先级的消息。若带有优先级的消息超过了 20 条/秒,则按照消息发送时间顺序处理,丢弃后发送的消息。 + +```java + EMMessage message = EMMessage.createTextSendMessage(content, conversationId); + message.setChatType(ChatType.ChatRoom); + // 聊天室消息的优先级。如果不设置,默认值为 `PriorityNormal`,即“普通”优先级。 + message.setPriority(EMChatRoomMessagePriority.PriorityHigh); + sendMessage(message); +``` + +### 获取发送附件消息的进度 + +发送附件类型消息时,可以在 `onProgress` 回调中获取附件上传的进度,以百分比表示,示例代码如下: + +```java +// 发送消息时可以设置 `EMCallBack` 的实例,获得消息发送的状态。可以在该回调中更新消息的显示状态。例如,消息发送失败后的提示等等。 + message.setMessageStatusCallback(new EMCallBack() { + @Override + public void onSuccess() { + // 发送消息成功 + dialog.dismiss(); + } + @Override + public void onError(int code, String error) { + // 发送消息失败 + } + + // 消息发送的状态,这里只用于附件类型的消息。 + @Override + public void onProgress(int progress, String status) { + + } + + }); + // 发送消息 + EMClient.getInstance().chatManager().sendMessage(message); +``` + +### 发送消息前的内容审核 + +- 内容审核关注消息 body + +[内容审核服务会关注消息 body 中指定字段的内容,不同类型的消息审核不同的字段](/product/moderation/moderation_mechanism.html),若创建消息时在这些字段中传入了很多业务信息,可能会影响审核效果。因此,创建消息时需要注意内容审核的字段不涉及业务信息,建议业务信息放在扩展字段中。 + +- 设置发送方收到内容审核替换后的内容 + +若初始化时打开了 `EMOptions#setUseReplacedMessageContents` 开关,发送文本消息时如果被内容审核(Moderation)进行了内容替换,发送方会收到替换后的内容。若该开关为关闭状态,则发送方不会收到替换后的内容。 + + + diff --git a/docs/document/android/message_send_receive.md b/docs/document/android/message_send_receive.md deleted file mode 100644 index f21a894f5..000000000 --- a/docs/document/android/message_send_receive.md +++ /dev/null @@ -1,615 +0,0 @@ -# 发送和接收消息 - -环信即时通讯 IM Android SDK 通过 [EMChatManager](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_chat_manager.html)、[EMMessage](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_message.html) 、[EMOptions](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_options.html) 和 [EMMessageListener](https://sdkdocs.easemob.com/apidoc/android/chat3.0/interfacecom_1_1hyphenate_1_1_e_m_message_listener.html) 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 - -- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - -- 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 - -关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 - -## 前提条件 - -开始前,请确保满足以下条件: - -- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 - -## 发送和接收文本消息 - -1. 首先,利用 [EMMessage](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_message.html) 类构造一条消息。 - -默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 - -示例代码: - -```java -// 创建一条文本消息,`content` 为消息文字内容。 -// `conversationId` 为消息接收方,单聊时为对端用户 ID、群聊时为群组 ID,聊天室时为聊天室 ID。 -EMMessage message = EMMessage.createTextSendMessage(content, conversationId); -// 会话类型:单聊为 EMMessage.ChatType.Chat,群聊为 EMMessage.ChatType.GroupChat, 聊天室为EMMessage.ChatType.ChatRoom,默认为单聊。 -message.setChatType(EMMessage.ChatType.Chat); -// 发送消息。 -EMClient.getInstance().chatManager().sendMessage(message); -``` - -2. 通过 [EMChatManager](https://sdkdocs.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_chat_manager.html) 将该消息发出。发送消息时可以设置 [EMCallBack](https://sdkdocs.easemob.com/apidoc/android/chat3.0/interfacecom_1_1hyphenate_1_1_e_m_call_back.html) 的实例,获取消息发送状态。 - -```java -// 发送消息时可以设置 `EMCallBack` 的实例,获得消息发送的状态。可以在该回调中更新消息的显示状态。例如消息发送失败后的提示等等。 -message.setMessageStatusCallback(new EMCallBack() { - @Override - public void onSuccess() { - // 发送消息成功 - } - @Override - public void onError(int code, String error) { - // 发送消息失败 - } - @Override - public void onProgress(int progress, String status) { - - } - - }); - // 发送消息。 -EMClient.getInstance().chatManager().sendMessage(message); -``` - -3. 你可以用注册监听 [EMMessageListener](https://sdkdocs.easemob.com/apidoc/android/chat3.0/interfacecom_1_1hyphenate_1_1_e_m_message_listener.html) 接收消息。该 [EMMessageListener](https://sdkdocs.easemob.com/apidoc/android/chat3.0/interfacecom_1_1hyphenate_1_1_e_m_message_listener.html) 可以多次添加,请记得在不需要的时候移除 `listener`,如在 `activity` 的 `onDestroy()` 时。 - -在新消息到来时,你会收到 `onMessageReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `EMOptions#setIncludeSendMessageInMessageListener` 开关,则该回调中会返回发送成功的消息。 - -对于聊天室消息,你可以通过消息的 `EMMessage#isBroadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```java -EMMessageListener msgListener = new EMMessageListener() { - - // 收到消息,遍历消息队列,解析和显示。 - @Override - public void onMessageReceived(List messages) { - - } -}; -// 注册消息监听 -EMClient.getInstance().chatManager().addMessageListener(msgListener); -// 解注册消息监听 -EMClient.getInstance().chatManager().removeMessageListener(msgListener); -``` - -## 发送和接收附件消息 - -除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 - -附件消息的发送和接收过程如下: - -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器。 -2. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 -3. 获取附件的服务器地址和本地路径。 - -自 4.14.0 版本开始,即时通讯 IM 支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户必须调用 SDK 的 `downloadAttachment` 方法下载消息附件。 - -### 发送和接收语音消息 - -发送和接收语音消息的过程如下: - -1. 发送语音消息前,在应用层录制语音文件。 -2. 发送方调用 `createVoiceSendMessage` 方法传入语音文件的 URI、语音时长和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建语音消息,然后调用 `sendMessage` 方法发送消息。SDK 会将语音文件上传至环信服务器。 - -```java -// `voiceUri` 为语音文件的本地资源标志符,`duration` 为语音时长(单位为秒)。 -EMMessage message = EMMessage.createVoiceSendMessage(voiceUri, duration, toChatUsername); -// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -// message.setChatType(ChatType.GroupChat); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(message); -``` - -3. 接收方收到语音消息时,自动下载语音文件。 - -4. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),调用 `getRemoteUrl` 或 `getLocalUri` 方法获取语音文件的服务器地址或本地路径,从而获取语音文件。 - -```java -EMVoiceMessageBody voiceBody = (EMVoiceMessageBody) msg.getBody(); -// 获取语音文件在服务器的地址。 -String voiceRemoteUrl = voiceBody.getRemoteUrl(); -// 本地语音文件的资源路径。 -Uri voiceLocalUri = voiceBody.getLocalUri(); -``` - -### 发送和接收图片消息 - -发送和接收图片消息的流程如下: - -1. 发送方调用 `createImageSendMessage` 方法传入图片的本地资源标志符 URI、设置是否发送原图以及接收方的用户 ID (群聊或聊天室分别为群组 ID 或聊天室 ID)创建图片消息,然后调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 - -```java -// `imageUri` 为图片本地资源标志符,`false` 为不发送原图(默认超过 100 KB 的图片会压缩后发给对方),若需要发送原图传 `true`,即设置 `original` 参数为 `true`。 -EMMessage message = EMMessage.createImageSendMessage(imageUri, false, toChatUsername); -// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -// message.setChatType(ChatType.GroupChat); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(message); -``` - -2. 接收方收到图片消息,自动下载图片缩略图。 - -- 默认情况下,SDK 自动下载缩略图,即 `EMClient.getInstance().getOptions().setAutoDownloadThumbnail(true)`。 -- 若设置为手动下载缩略图,即 `EMClient.getInstance().getOptions().setAutoDownloadThumbnail(false)`,需调用 `EMClient.getInstance().chatManager().downloadThumbnail(message)` 下载。 - -3. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),调用 `downloadAttachment` 下载原图。 - -```java -@Override -public void onMessageReceived(List messages) { - for(EMMessage message : messages) { - if (message.getType() == Type.IMAGE) { - message.setMessageStatusCallback(new EMCallBack() { - @Override - public void onSuccess() { - // 附件下载成功 - } - @Override - public void onError(int code, String error) { - // 附件下载失败 - } - - @Override - public void onProgress(int progress, String status) { - // 附件下载进度 - } - - }); - // 下载附件 - EMClient.getInstance().chatManager().downloadAttachment(message); - } - } -} -``` - -4. 获取图片消息的缩略图和附件。 - -```java -EMImageMessageBody imgBody = (EMImageMessageBody) message.getBody(); -// 从服务器端获取图片文件。 -String imgRemoteUrl = imgBody.getRemoteUrl(); -// 从服务器端获取图片缩略图。 -String thumbnailUrl = imgBody.getThumbnailUrl(); -// 从本地获取图片文件。 -Uri imgLocalUri = imgBody.getLocalUri(); -// 从本地获取图片缩略图。 -Uri thumbnailLocalUri = imgBody.thumbnailLocalUri(); -``` - -### 发送和接收 GIF 图片消息 - -自 Android SDK 4.14.0 开始,支持发送和接收 GIF 图片消息。 - -GIF 图片消息是一种特殊的图片消息,与普通图片消息不同,**GIF 图片发送时不能压缩**。 - -图片缩略图的生成和下载与普通图片消息相同,详见 [发送和接收图片消息](#发送和接收图片消息)。 - -#### 发送 GIF 图片消息 - -你可以通过以下方式构造 GIF 图片消息: - -- 使用 `EMMessage#createGifImageMessage` 方法构造Gif图片消息体。 - -```java -// `imageUri` 为图片本地资源标志符 -EMMessage message = EMMessage.createGifImageMessage(imageUri, toChatUsername); -// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -// message.setChatType(ChatType.GroupChat); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(message); -``` - -#### 接收 GIF 图片消息 - -与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onMessageReceived` 回调方法。接收方判断为图片消息后,读取消息体的 `isGif` 属性,若值是 `YES`, 则为 GIF 图片消息。 - -```java -public void onMessageReceived(List messages) { - for(EMMessage message : messages) { - if (message.getType() == Type.IMAGE && ) { - EMImageMessageBody body = (EMImageMessageBody) msg.getBody(); - if(body.isGif()) { - // 根据业务情况处理gif message, 例如下载展示该消息 - } - } - } - -} -``` - -### 发送和接收视频消息 - -发送和接收视频消息的流程如下: - -1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 - -2. 发送方调用 `createVideoSendMessage` 方法传入视频文件的本地资源标志符、缩略图的本地存储路径、视频时长以及接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID),然后调用 `sendMessage` 方法发送消息。SDK 会将视频文件上传至消息服务器。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `createVideoSendMessage` 方法。 - -```java -// 在应用层获取视频首帧,你需要自己实现 getThumbPath 方法。 -String thumbPath = getThumbPath(videoUri); -EMMessage message = EMMessage.createVideoSendMessage(videoUri, thumbPath, videoLength, toChatUsername); -// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -// message.setChatType(ChatType.GroupChat); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(message); -``` - -3. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#发送和接收图片消息)。 - -4. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),可以调用 `EMClient.getInstance().chatManager().downloadAttachment(message)` 方法下载视频原文件。 - -```java -/** - * 下载视频文件。 - */ -private void downloadVideo(final EMMessage message) { - message.setMessageStatusCallback(new EMCallBack() { - @Override - public void onSuccess() { - } - - @Override - public void onProgress(final int progress,String status) { - } - - @Override - public void onError(final int error, String msg) { - } - }); - // 下载附件 - EMClient.getInstance().chatManager().downloadAttachment(message); -} -``` - -5. 获取视频缩略图和视频原文件。 - -```java -// 从服务器端获取视频文件。 -String imgRemoteUrl = ((EMVideoMessageBody) body).getRemoteUrl(); -// 从服务器获取视频缩略图文件。 -String thumbnailUrl = ((EMVideoMessageBody) body).getThumbnailUrl(); -// 从本地获取视频文件文件。 -Uri localUri = ((EMVideoMessageBody) body).getLocalUri(); -// 从本地获取视频缩略图文件。 -Uri localThumbUri = ((EMVideoMessageBody) body).thumbnailLocalUri(); -``` - -### 发送和接收文件消息 - -发送和接收文件消息的流程如下: - -1. 发送方调用 `createFileSendMessage` 方法传入文件的本地资源标志符和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建文件消息,然后调用 `sendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 - -```java -// `fileLocalUri` 为本地资源标志符。 -EMMessage message = EMMessage.createFileSendMessage(fileLocalUri, toChatUsername); -// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -// message.setChatType(ChatType.GroupChat); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(message); -``` - -2. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),调用 `downloadAttachment` 方法下载文件。 - -```java -/** - * 下载文件。 - */ -private void downloadFile(final EMMessage message) { - message.setMessageStatusCallback(new CallBack() { - @Override - public void onSuccess() { - } - - @Override - public void onProgress(final int progress,String status) { - } - - @Override - public void onError(final int error, String msg) { - } - }); - // 下载附件 - EMClient.getInstance().chatManager().downloadAttachment(message); -} -``` - -3. 调用以下方法从服务器或本地获取文件附件: - -```java -EMNormalFileMessageBody fileMessageBody = (EMNormalFileMessageBody) message.getBody(); -// 从服务器获取文件。 -String fileRemoteUrl = fileMessageBody.getRemoteUrl(); -// 从本地获取文件。 -Uri fileLocalUri = fileMessageBody.getLocalUri(); -``` - -## 发送和接收位置消息 - -1. 创建和发送位置消息。 - -发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 - -```java -// `latitude` 为纬度,`longitude` 为经度,`locationAddress` 为具体位置内容。 -EMMessage message = EMMessage.createLocationSendMessage(latitude, longitude, locationAddress, toChatUsername); -// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -// message.setChatType(ChatType.GroupChat); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(message); -``` - -2. 接收位置消息与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - - 接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 - -## 发送和接收透传消息 - -透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 - -具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 - -:::tip -- 透传消息发送后,不支持撤回。 -- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 -::: - -1. 创建和发送透传消息。 - -```java -EMMessage cmdMsg = EMMessage.createSendMessage(EMMessage.Type.CMD); -// 设置会话类型,即`EMMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -// 若为群聊,添加下行代码。 -// cmdMsg.setChatType(EMMessage.ChatType.GroupChat); -// 若为聊天室,添加下行代码。 -// cmdMsg.setChatType(EMMessage.ChatType.ChatRoom); - -String action="action1"; -// `action` 可以自定义。 -EMCmdMessageBody cmdBody = new EMCmdMessageBody(action); -String toUsername = "test1"; -// 对于单聊,传入接收方的用户 ID,群聊传入群组 ID,聊天室传入聊天室 ID。 -cmdMsg.setTo(toUsername); -cmdMsg.addBody(cmdBody); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(cmdMsg); -``` - -2. 接收方通过 `onMessageReceived` 和 `onCmdMessageReceived` 回调接收透传消息,方便用户进行不同的处理。 - -```java -EMMessageListener msgListener = new EMMessageListener(){ - // 收到消息。 - @Override - public void onMessageReceived(List messages) { - } - // 收到透传消息。 - @Override - public void onCmdMessageReceived(List messages) { - } -} -``` - -## 发送和接收自定义类型消息 - -除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 - -1. 创建和发送自定义类型消息。 - -```java -EMMessage customMessage = EMMessage.createSendMessage(EMMessage.Type.CUSTOM); -// `event` 为需要传递的自定义消息事件,比如礼物消息,可以设置: -String event = "gift"; -EMCustomMessageBody customBody = new EMCustomMessageBody(event); -// `params` 类型为 `Map`。 -customBody.setParams(params); -customMessage.addBody(customBody); -// `to` 指定接收方,单聊、群聊和聊天室分别为对端用户 ID、群组 ID 和聊天室 ID。 -customMessage.setTo(to); -// 对于单聊、群群聊或聊天室,`chatType` 分别为 `Chat`、`GroupChat` 和 `ChatRoom`,默认是单聊。 -customMessage.setChatType(chatType); -// 发送消息 -EMClient.getInstance().chatManager().sendMessage(customMessage); -``` - -2. 接收自定义消息与其他类型消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -## 发送和接收合并消息 - -为了方便消息互动,即时通讯 IM 自 4.1.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: - -1. 利用原始消息列表创建一条合并消息。 -2. 发送合并消息。 -3. 对端收到合并消息后进行解析,获取原始消息列表。合并消息转发后在接收端显示该消息的标题和预览图。 - -:::tip -对于转发合并消息,例如,用户 A 向 用户 B 发送了合并消息,用户 B 将该合并消息转发给用户 C,需要调用转发单条合并消息的 API。详见[转发单条消息](message_forward.html#转发单条消息)。 -::: - -#### 创建和发送合并消息 - -你可以调用 `createCombinedSendMessage` 方法创建一条合并消息,然后调用 `sendMessage` 方法发送该条消息。 - -创建合并消息时,需要设置以下参数: - -| 属性 | 类型 | 描述 | -| :-------------- | :-------------------- | :-------------------- | -| `title` | String | 合并消息的标题。 | -| `summary` | String | 合并消息的概要。 | -| `compatibleText` | String | 合并消息的兼容文本。
兼容文本起向下兼容不支持消息合并转发的版本的作用。当支持合并消息的 SDK 向不支持合并消息的低版本 SDK 发送消息时,低版本的 SDK 会将该属性解析为文本消息的消息内容。 | -| `messageIdList` | List | 合并消息的原始消息 ID 列表。该列表最多包含 300 个消息 ID。 | -| `userId` | String | 消息接收方。该字段的设置取决于会话类型:
- 单聊:对方用户 ID;
- 群聊:群组 ID;
- 子区会话:子区 ID;
- 聊天室聊天:聊天室 ID。| - -:::tip -1. 合并转发支持嵌套,最多支持 10 层嵌套,每层最多 300 条消息。 -2. 不论 `EMOptions#setAutoTransferMessageAttachments` 设置为 `false` 或 `true`,SDK 都会将合并消息附件上传到环信服务器。 -3. 合并消息不支持搜索。 -::: - -示例代码如下: - -```java -String title = "A和B的聊天记录"; -String summary = "A:这是A的消息内容\nB:这是B的消息内容"; -String compatibleText = "您当前的版本不支持该消息,请升级到最新版本"; -// 添加原消息 ID。 -ArrayList msgIdList = new ArrayList<>(); -msgIdList.add("1390191369179366180"); -msgIdList.add("1390191426268037924"); -msgIdList.add("1390186040483906340"); -EMMessage message = EMMessage.createCombinedSendMessage(title, summary, compatibleText, msgIdList, receiverId); -message.setMessageStatusCallback(new EMCallBack() { - @Override - public void onSuccess() { - // 消息发送成功的处理逻辑 - } - - @Override - public void onError(int code, String error) { - // 消息发送失败的处理逻辑 - } -}); -EMClient.getInstance().chatManager().sendMessage(message); -``` - -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 - -对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: - -- 若附件已存在,该方法会直接解析附件并返回原始消息列表。 -- 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 - -```java -EMClient.getInstance().chatManager().downloadAndParseCombineMessage(combineMessage, new EMValueCallBack>() { - @Override - public void onSuccess(List value) { - // 处理并展示消息列表 - } - - @Override - public void onError(int error, String errorMsg) { - // 处理出错信息 - } -}); -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 仅 SDK 4.0.3 及以上版本支持。 -2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: - -1. 创建一条群组或聊天室消息。 -2. 设置消息的接收方。 -3. 发送定向消息。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```java -// 创建一条文本消息。 -EMMessage message = EMMessage.createTextSendMessage(content, groupId); - // 会话类型:群组和聊天室聊天,分别为 `GroupChat` 和 `ChatRoom`。 - message.setChatType(EMMessage.ChatType.GroupChat); - List receives=new ArrayList<>(); - receives.add("张三"); - receives.add("李四"); - // 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`,则消息发送给群组或聊天室的所有成员。 - message.setReceiverList(receives); -EMClient.getInstance().chatManager().sendMessage(message); -``` - -接收群定向消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 - -## 使用消息扩展字段 - -当 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) -``` - -## 更多 - -### 聊天室消息优先级与消息丢弃逻辑 - -- **消息优先级**:对于聊天室消息,环信即时通讯提供消息分级功能,支持高、普通和低三种优先级,高优先级的消息会优先送达。你可以在创建消息时对指定消息类型或指定成员的消息设置为高优先级,确保这些消息优先送达。这种方式可以确保在聊天室内消息并发量较大或消息发送频率过高的情况下,服务器首先丢弃低优先级消息,将资源留给高优先级消息,确保重要消息(如打赏、公告等)优先送达,以此提升重要消息的可靠性。请注意,该功能并不保证高优先级消息必达。在聊天室内消息并发量过大的情况下,为保证用户实时互动的流畅性,即使是高优先级消息仍然会被丢弃。 - -- **消息丢弃逻辑**:对于单个聊天室,每秒发送的消息数量默认超过 20 条,则会触发消息丢弃逻辑,即首先丢弃低优先级的消息,优先保留高优先级的消息。若带有优先级的消息超过了 20 条/秒,则按照消息发送时间顺序处理,丢弃后发送的消息。 - -```java - EMMessage message = EMMessage.createTextSendMessage(content, conversationId); - message.setChatType(ChatType.ChatRoom); - // 聊天室消息的优先级。如果不设置,默认值为 `PriorityNormal`,即“普通”优先级。 - message.setPriority(EMChatRoomMessagePriority.PriorityHigh); - sendMessage(message); -``` - -### 获取发送附件消息的进度 - -发送附件类型消息时,可以在 `onProgress` 回调中获取附件上传的进度,以百分比表示,示例代码如下: - -```java -// 发送消息时可以设置 `EMCallBack` 的实例,获得消息发送的状态。可以在该回调中更新消息的显示状态。例如,消息发送失败后的提示等等。 - message.setMessageStatusCallback(new EMCallBack() { - @Override - public void onSuccess() { - // 发送消息成功 - dialog.dismiss(); - } - @Override - public void onError(int code, String error) { - // 发送消息失败 - } - - // 消息发送的状态,这里只用于附件类型的消息。 - @Override - public void onProgress(int progress, String status) { - - } - - }); - // 发送消息 - EMClient.getInstance().chatManager().sendMessage(message); -``` - -### 发送消息前的内容审核 - -- 内容审核关注消息 body - -[内容审核服务会关注消息 body 中指定字段的内容,不同类型的消息审核不同的字段](/product/moderation/moderation_mechanism.html),若创建消息时在这些字段中传入了很多业务信息,可能会影响审核效果。因此,创建消息时需要注意内容审核的字段不涉及业务信息,建议业务信息放在扩展字段中。 - -- 设置发送方收到内容审核替换后的内容 - -若初始化时打开了 `EMOptions#setUseReplacedMessageContents` 开关,发送文本消息时如果被内容审核(Moderation)进行了内容替换,发送方会收到替换后的内容。若该开关为关闭状态,则发送方不会收到替换后的内容。 - - - diff --git a/docs/document/android/message_target.md b/docs/document/android/message_target.md new file mode 100644 index 000000000..aa2ccd5c9 --- /dev/null +++ b/docs/document/android/message_target.md @@ -0,0 +1,34 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 仅 SDK 4.0.3 及以上版本支持。 +2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: + +1. 创建一条群组或聊天室消息。 +2. 设置消息的接收方。 +3. 发送定向消息。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```java +// 创建一条文本消息。 +EMMessage message = EMMessage.createTextSendMessage(content, groupId); + // 会话类型:群组和聊天室聊天,分别为 `GroupChat` 和 `ChatRoom`。 + message.setChatType(EMMessage.ChatType.GroupChat); + List receives=new ArrayList<>(); + receives.add("张三"); + receives.add("李四"); + // 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`,则消息发送给群组或聊天室的所有成员。 + message.setReceiverList(receives); +EMClient.getInstance().chatManager().sendMessage(message); +``` + +接收群定向消息与接收普通消息的操作相同,详见 [接收文本消息](#发送和接收文本消息)。 \ No newline at end of file diff --git a/docs/document/applet/message_extension.md b/docs/document/applet/message_extension.md new file mode 100644 index 000000000..572777fd9 --- /dev/null +++ b/docs/document/applet/message_extension.md @@ -0,0 +1,31 @@ +# 消息扩展 + +如果上述类型的消息无法满足要求,你可以使用消息扩展为消息添加属性。这种情况可用于更复杂的消息传递场景,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```javascript +function sendTextMessage() { + let option = { + type: "txt", + msg: "message content", + to: "username", + chatType: "singleChat", + // 设置消息扩展信息。扩展字段为可选,若带有该字段,值不能为空,即 "ext:null" 会出错。 + ext: { + key1: "Self-defined value1", + key2: { + key3: "Self-defined value3", + }, + }, + }; + let msg = WebIM.message.create(option); + // 调用 `send` 方法发送该扩展消息。 + conn + .send(msg) + .then((res) => { + console.log("send private text Success"); + }) + .catch((e) => { + console.log("Send private text error"); + }); +} +``` \ No newline at end of file diff --git a/docs/document/applet/message_receive.md b/docs/document/applet/message_receive.md new file mode 100644 index 000000000..047e719c2 --- /dev/null +++ b/docs/document/applet/message_receive.md @@ -0,0 +1,175 @@ +# 接收消息 + + + +环信即时通讯 IM 的小程序 SDK 可以实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +- 你可以通过 `addEventHandler` 注册监听器监听消息事件。你可以添加多个事件。当不再监听事件时,请确保删除监听器。 +- 当消息到达时,接收方会收到 `onTextMessage` 回调。每个回调包含一条或多条消息。你可以遍历消息列表,并可以解析和展示回调中的消息。 +- 对于聊天室消息,你可以通过消息的 `broadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + onTextMessage: function (message) {}, + +}); +``` + +## 接收附件消息 + +- 语音、图片、视频和文件消息本质上是附件消息。 +- 接收方可以自行下载语音、图片、图片缩略图、视频和文件。 +- 环信即时通讯 IM 支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户须调用 SDK 的 API `EC.utils.download` 下载消息附件。 + +### 接收语音消息 + +接收方收到 `onAudioMessage` 回调,根据消息 `url` 字段获取语音文件的服务器地址,从而获取语音文件。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + // 当前用户收到语音消息。 + onAudioMessage: function (message) { + // 语音文件在服务器的地址。 + console.log(message.url); + }, +}); + +``` + +### 接收图片消息 + +接收方收到 `onImageMessage` 回调,根据消息 `url` 字段获取图片文件的服务器地址,从而获取图片文件。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + onImageMessage: function (message) {}, +}); +``` + +### 接收 GIF 图片消息 + +自小程序 SDK 4.14.0 开始,支持接收 GIF 图片消息。 + +与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onImageMessage` 回调方法。接收方收到消息后,读取消息体的 `isGif` 属性,若值是 `true`, 则为 GIF 图片消息。 + +```javascript +onImageMessage: (message) => { + if(message.isGif){ + // 图片为GIF + } +} +``` + +### 接收视频消息 + +接收方收到 `onVideoMessage` 回调,根据消息 `url` 字段获取视频文件的服务器地址,从而获取视频文件。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + // 当前用户收到视频消息。 + onVideoMessage: function (message) { + // 视频文件在服务器的地址。 + console.log(message.url); + // 视频首帧缩略图文件在服务器的地址。 + console.log(message.thumb); + }, +}); +``` + +### 接收文件消息 + +接收方收到 `onFileMessage` 回调,根据消息 `url` 字段获取文件的服务器地址,从而获取文件。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + // 当前用户收到文件消息。 + onFileMessage: function (message) { + // 文件在服务器的地址。 + console.log(message.url); + }, +}); + +``` + +## 接收位置消息 + +接收方收到 `onLocationMessage` 回调,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + onLocationMessage: function (message) {}, +}); +``` + +## 接收透传消息 + +透传消息是通知指定用户采取特定操作的命令消息。接收方自己处理透传消息。 + +:::tip +透传消息发送后,不支持撤回。 +::: + +接收方通过 `onCmdMessage` 回调接收透传消息。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + onCmdMessage: function (message) {}, +}); +``` + + +## 接收自定义消息 + +自定义消息为用户自定义的键值对,包括消息类型和消息内容。 + +接收方通过 `onCustomMessage` 回调接收自定义消息。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + onCustomMessage: function (message) {}, +}); +``` + +## 接收合并消息 + +为了方便消息互动,即时通讯 IM 自 4.2.0 版本开始支持将多个消息合并在一起进行转发。 + +:::tip + +该功能在 uniapp 中暂不支持运行到原生手机端。 + +::: + +接收合并消息与接收普通消息的操作相同,唯一不同是对于合并消息来说,消息接收事件为 `onCombineMessage`。 + +对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 + +合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 + +```javascript +connection + .downloadAndParseCombineMessage({ + url: msg.url, + secret: msg.secret, + }) + .then((res) => { + console.log("合并消息解析后的消息列表", res); + }); +``` \ No newline at end of file diff --git a/docs/document/applet/message_send_receive.md b/docs/document/applet/message_send.md similarity index 66% rename from docs/document/applet/message_send_receive.md rename to docs/document/applet/message_send.md index cdb2a8716..1b3b3235a 100644 --- a/docs/document/applet/message_send_receive.md +++ b/docs/document/applet/message_send.md @@ -1,14 +1,12 @@ -# 发送和接收消息 +# 发送消息 环信即时通讯 IM 的小程序 SDK 可以实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 -- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - +- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要 [开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 - -关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 +- 关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 ## 前提条件 @@ -17,9 +15,9 @@ - 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 - 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -## 发送和接收文本消息 +## 发送文本消息 -1. 使用 `Message` 类创建并发送文本消息。 +使用 `Message` 类创建并发送文本消息。 默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 @@ -47,33 +45,11 @@ function sendTextMessage() { } ``` -2. 你可以通过 `addEventHandler` 注册监听器监听消息事件。你可以添加多个事件。当不再监听事件时,请确保删除监听器。 - -当消息到达时,接收方会收到 `onTextMessage` 回调。每个回调包含一条或多条消息。你可以遍历消息列表,并可以解析和展示回调中的消息。 - -对于聊天室消息,你可以通过消息的 `broadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - onTextMessage: function (message) {}, - -}); -``` - -## 发送和接收附件消息 +## 发送附件消息 -语音、图片、视频和文件消息本质上是附件消息。发送和接收附件消息的流程如下: - -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器,获取消息的基本信息以及服务器上附件文件的路径。 - - 对于图片消息来说,环信服务器会自动生成图片缩略图;而对于视频消息来说,视频的首帧为缩略图。 - -2. 接收附件消息。 - - 接收方可以自行下载语音、图片、图片缩略图、视频和文件。 - -环信即时通讯 IM 支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户须调用 SDK 的 API `EC.utils.download` 下载消息附件。 +- 语音、图片、视频和文件消息本质上是附件消息。 +- 创建和发送附件类型消息。SDK 将附件上传到环信服务器,获取消息的基本信息以及服务器上附件文件的路径。 +- 对于图片消息,环信服务器会自动生成图片缩略图;对于视频消息,视频的首帧为缩略图。 对于消息附件,你也可以将附件上传到自己的服务器,而不是环信服务器,然后发送消息。这种情况下,需要在 SDK 初始化时将 [`Connection` 类中的 `useOwnUploadFun` 参数](https://doc.easemob.com/jsdoc/classes/Connection.Connection-1.html)设置为 `true`。例如,对于图片消息,上传附件后,调用 `sendPrivateUrlImg` 方法传入图片的 URL 发送图片消息。 @@ -95,11 +71,11 @@ function sendPrivateUrlImg() { } ``` -### 发送和接收语音消息 +### 发送语音消息 -在发送语音消息前,你应该在 app 级别实现录音,提供录制的语音文件的 URI 和时长(单位为秒)。 +1. 发送语音消息前,在 app 级别实现录音,提供录制的语音文件的 URI 和时长(单位为秒)。 -1. 创建和发送语音消息。 +2. 创建和发送语音消息。 ```javascript /** @@ -153,25 +129,9 @@ function sendPrivateAudio(tempFilePath, duration) { } ``` -2. 接收方收到 `onAudioMessage` 回调,根据消息 `url` 字段获取语音文件的服务器地址,从而获取语音文件。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - // 当前用户收到语音消息。 - onAudioMessage: function (message) { - // 语音文件在服务器的地址。 - console.log(message.url); - }, -}); - -``` - -### 发送和接收图片消息 +### 发送图片消息 -发送和接收图片消息的流程如下: - -1. 创建和发送图片消息。 +创建和发送图片消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 ```javascript function sendImage() { @@ -255,25 +215,13 @@ function sendPrivateImg(res) { } ``` -2. 接收方收到 `onImageMessage` 回调,根据消息 `url` 字段获取图片文件的服务器地址,从而获取图片文件。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - onImageMessage: function (message) {}, -}); -``` +### 发送 GIF 图片消息 -### 发送和接收 GIF 图片消息 +- 自小程序 SDK 4.14.0 开始,支持发送 GIF 图片消息。 +- GIF 图片消息是一种特殊的图片消息,在发送图片消息时可以指定是否是 GIF 图片。 +- GIF 图片缩略图的生成与普通图片消息相同,详见 [发送图片消息](#发送图片消息)。 -自小程序 SDK 4.14.0 开始,支持发送和接收 GIF 图片消息。 - -GIF 图片消息是一种特殊的图片消息,在发送图片消息时可以指定是否是 GIF 图片。 - -#### 发送 GIF 图片消息 - -1. 构造消息,设置 `isGif` 为 `true`。 -2. 调用 `send` 方法发送消息。 +构造消息时,设置 `isGif` 为 `true`。 ```javascript sendGIFMsg(){ @@ -283,30 +231,18 @@ sendGIFMsg(){ type: "img", to: "userId", file: file, - isGif: file.data.type === "image/gif", // 设置是否是为 GIF 图片 + isGif: file.data.type === "image/gif", // 设置是否为 GIF 图片 }; let msg = EC.message.create(option); conn.send(msg); } ``` -#### 接收 GIF 图片消息 +### 发送视频消息 -与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onImageMessage` 回调方法。接收方收到消息后,读取消息体的 `isGif` 属性,若值是 `true`, 则为 GIF 图片消息。 +1. 发送视频消息之前,在 app 级别实现视频捕获以及捕获文件的上传。 -```javascript -onImageMessage: (message) => { - if(message.isGif){ - // 图片为GIF - } -} -``` - -### 发送和接收视频消息 - -在发送视频消息之前,应在 app 级别实现视频捕获以及捕获文件的上传。 - -1. 创建和发送视频消息。服务器自动生成视频消息的缩略图,即视频的首帧。 +2. 创建和发送视频消息。SDK 会将视频文件上传至消息服务器。服务端自动生成视频消息的缩略图。 ```javascript function sendPrivateVideo(){ @@ -364,27 +300,11 @@ function sendPrivateVideo(){ }, ``` +### 发送文件消息 -2. 接收方收到 `onVideoMessage` 回调,根据消息 `url` 字段获取视频文件的服务器地址,从而获取视频文件。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - // 当前用户收到视频消息。 - onVideoMessage: function (message) { - // 视频文件在服务器的地址。 - console.log(message.url); - // 视频首帧缩略图文件在服务器的地址。 - console.log(message.thumb); - }, -}); -``` - -### 发送和接收文件消息 +1. 发送文件消息前,先选择文件。微信小程序仅支持从客户端会话选择文件。 -发送文件消息前,应先选择文件。微信小程序仅支持从客户端会话选择文件。 - -1. 创建和发送文件消息。 +2. 创建和发送文件消息。 ```javascript // 发送文件消息。 @@ -454,27 +374,12 @@ function sendFileMessage() { } ``` -2. 接收方收到 `onFileMessage` 回调,根据消息 `url` 字段获取文件的服务器地址,从而获取文件。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - // 当前用户收到文件消息。 - onFileMessage: function (message) { - // 文件在服务器的地址。 - console.log(message.url); - }, -}); - -``` - -## 发送和接收位置消息 +## 发送位置消息 -发送和接收位置消息的流程如下: - -1. 创建和发送位置消息。 +创建和发送位置消息。 发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 + ```javascript const sendLocMsg = () => { let option = { @@ -495,24 +400,17 @@ const sendLocMsg = () => { }; ``` -2. 接收方收到 `onLocationMessage` 回调,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - onLocationMessage: function (message) {}, -}); -``` - -## 发送和接收透传消息 +## 发送透传消息 透传消息是通知指定用户采取特定操作的命令消息。接收方自己处理透传消息。 +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + :::tip 透传消息发送后,不支持撤回。 ::: -1. 创建和发送透传消息。 +创建和发送透传消息,示例代码如下: ```javascript function sendCMDMessage() { @@ -544,22 +442,11 @@ function sendCMDMessage() { } ``` -2. 接收方通过 `onCmdMessage` 回调接收透传消息。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - onCmdMessage: function (message) {}, -}); -``` - - -## 发送和接收自定义消息 +## 发送自定义消息 自定义消息为用户自定义的键值对,包括消息类型和消息内容。 -发送和接收自定义消息的流程如下: -1. 创建和发送自定义消息。 +创建和发送自定义消息,示例代码如下: ```javascript function sendCustomMsg() { @@ -596,29 +483,18 @@ function sendCustomMsg() { } ``` -2. 接收方通过 `onCustomMessage` 回调接收自定义消息。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - onCustomMessage: function (message) {}, -}); -``` - -## 发送和接收合并消息 +## 发送合并消息 为了方便消息互动,即时通讯 IM 自 4.2.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: 1. 利用原始消息列表创建一条合并消息。 2. 发送合并消息。 -3. 对端收到合并消息后进行解析,获取原始消息列表。 :::tip 该功能在 uniapp 中暂不支持运行到原生手机端。 ::: -#### 创建和发送合并消息 你可以调用 `message.create` 方法创建一条合并消息,然后调用 `connection.send` 方法发送该条消息。 @@ -673,102 +549,6 @@ conn.send }); ``` -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,唯一不同是对于合并消息来说,消息接收事件为 `onCombineMessage`。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 - -```javascript -connection - .downloadAndParseCombineMessage({ - url: msg.url, - secret: msg.secret, - }) - .then((res) => { - console.log("合并消息解析后的消息列表", res); - }); -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 仅 SDK 4.2.0 及以上版本支持。 -2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置定向消息的接收方。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```javascript -// 发送定向文本消息。 -function sendTextMessage() { - let option = { - // 消息类型。 - type: "txt", - // 消息内容。 - msg: "message content", - // 消息接收方所在群组或聊天室的 ID。 - to: "groupId", - // 会话类型:群聊和聊天室分别为 `groupChat` 和 `chatRoom`。 - chatType: "groupChat", - // 消息的接收方列表。最多可传 20 个接收方的用户 ID。若不设置该字段或传入数组类型之外的值,如字符串,则消息发送给群组或聊天室的所有成员。 - receiverList: ['uId1','uId2'], - }; - // 创建文本消息。 - let msg = WebIM.message.create(option); - // 调用 `send` 方法发送该文本消息。 - conn.send(msg).then((res)=>{ - console.log("Send message success",res); - }).catch((e)=>{ - console.log("Send message fail",e); - }); -} -``` - -接收定向消息与接收普通消息的操作相同,详见各类消息的接收描述。 - -## 使用消息扩展 - -如果上述类型的消息无法满足要求,你可以使用消息扩展为消息添加属性。这种情况可用于更复杂的消息传递场景,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 - -```javascript -function sendTextMessage() { - let option = { - type: "txt", - msg: "message content", - to: "username", - chatType: "singleChat", - // 设置消息扩展信息。扩展字段为可选,若带有该字段,值不能为空,即 "ext:null" 会出错。 - ext: { - key1: "Self-defined value1", - key2: { - key3: "Self-defined value3", - }, - }, - }; - let msg = WebIM.message.create(option); - // 调用 `send` 方法发送该扩展消息。 - conn - .send(msg) - .then((res) => { - console.log("send private text Success"); - }) - .catch((e) => { - console.log("Send private text error"); - }); -} -``` - ## 更多 ### 聊天室消息优先级与消息丢弃逻辑 diff --git a/docs/document/applet/message_target.md b/docs/document/applet/message_target.md new file mode 100644 index 000000000..a062708ba --- /dev/null +++ b/docs/document/applet/message_target.md @@ -0,0 +1,44 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 + +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 仅 SDK 4.2.0 及以上版本支持。 +2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置定向消息的接收方。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```javascript +// 发送定向文本消息。 +function sendTextMessage() { + let option = { + // 消息类型。 + type: "txt", + // 消息内容。 + msg: "message content", + // 消息接收方所在群组或聊天室的 ID。 + to: "groupId", + // 会话类型:群聊和聊天室分别为 `groupChat` 和 `chatRoom`。 + chatType: "groupChat", + // 消息的接收方列表。最多可传 20 个接收方的用户 ID。若不设置该字段或传入数组类型之外的值,如字符串,则消息发送给群组或聊天室的所有成员。 + receiverList: ['uId1','uId2'], + }; + // 创建文本消息。 + let msg = WebIM.message.create(option); + // 调用 `send` 方法发送该文本消息。 + conn.send(msg).then((res)=>{ + console.log("Send message success",res); + }).catch((e)=>{ + console.log("Send message fail",e); + }); +} +``` + +接收定向消息与接收普通消息的操作相同,详见各类消息的接收描述。 \ No newline at end of file diff --git a/docs/document/flutter/message_extension.md b/docs/document/flutter/message_extension.md new file mode 100644 index 000000000..006de3237 --- /dev/null +++ b/docs/document/flutter/message_extension.md @@ -0,0 +1,17 @@ +# 消息扩展 + +当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型。 + +当目前消息类型不满足用户需求时,可以在扩展部分保存更多信息,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```dart +try { + final msg = EMMessage.createTxtSendMessage( + targetId: targetId, + content: 'content', + ); + + msg.attributes = {'k': 'v'}; + EMClient.getInstance.chatManager.sendMessage(msg); +} on EMError catch (e) {} +``` \ No newline at end of file diff --git a/docs/document/flutter/message_receive.md b/docs/document/flutter/message_receive.md new file mode 100644 index 000000000..707bdfa90 --- /dev/null +++ b/docs/document/flutter/message_receive.md @@ -0,0 +1,272 @@ +# 接收消息 + +环信即时通讯 IM Flutter SDK 通过 `EMChatEventHandler` 类实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +- 你可以添加 `EMChatEventHandler` 监听器接收消息。`EMChatEventHandler` 可以多次添加。请记得在不需要的时候移除该监听器,如在 `dispose` 时。 +- 在新消息到来时,你会收到 `onMessagesReceived` 事件,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。 +- 若在初始化时打开了 `ChatOptions#messagesReceiveCallbackIncludeSend` 开关,则该回调中会返回发送成功的消息。 +- 对于聊天室消息,你可以通过消息的 `EMMessage#isBroadcast` 属性判断该消息是否为 [通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```dart +// 继承并实现 EMChatEventHandler +class _ChatMessagesPageState extends State { + @override + void initState() { + super.initState(); + // 添加监听器 + EMClient.getInstance.chatManager.addEventHandler( + "UNIQUE_HANDLER_ID", + EMChatEventHandler( + onMessagesReceived: (list) => {}, + ), + ); + } + + @override + Widget build(BuildContext context) { + return Container(); + } + + @override + void dispose() { + // 移除监听器 + EMClient.getInstance.chatManager.removeEventHandler("UNIQUE_HANDLER_ID"); + super.dispose(); + } +} +``` + +## 接收附件消息 + +除文本消息外,SDK 还支持接收附件类型消息,包括语音、图片、视频和文件消息。 + +附件消息的接收过程如下: + +1. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 +2. 获取附件的服务器地址和本地路径。 + +### 接收语音消息 + +1. 接收方收到语音消息时,自动下载语音文件。 +2. 接收方收到 [EMChatEventHandler#onMessagesReceived 回调](#接收文本消息),调用 `remotePath` 或 `localPath` 方法获取语音文件的服务器地址或本地路径,从而获取语音文件。 + +```dart +if(msg.body.type == MessageType.VOICE) { + EMVoiceMessageBody body = msg.body as EMVoiceMessageBody; + body.duration; // 语音时长 + body.localPath; // 本地语音文件路径 + body.remotePath; // 远程语音文件路径 +} + +``` + +### 接收图片消息 + +1. 接收方收到图片消息,自动下载图片缩略图。 + +- 默认情况下,SDK 自动下载缩略图,即 `EMOptions#isAutoDownloadThumbnail` 设置为 `true`。 +- 若设置为手动下载缩略图,即 `EMOptions#isAutoDownloadThumbnail` 设置为 `false`,需调用 `EMChatManager#downloadThumbnail` 下载。 + +2. 接收方收到 [EMChatEventHandler#onMessagesReceived 回调](#接收文本消息),调用 `downloadAttachment` 下载原图。 + +```dart +EMClient.getInstance.chatManager.addMessageEvent( + 'UNIQUE_HANDLER_ID', + ChatMessageEvent( + onSuccess: (msgId, msg) { + // 下载成功 + }, + onProgress: (msgId, progress) { + // 下载进度 + }, + onError: (msgId, msg, error) { + // 下载失败 + }, + ), +); + +// 下载附件 +EMClient.getInstance.chatManager.downloadAttachment(msg); +``` + +3. 下载成功后获取图片消息的缩略图和附件。 + +```dart +EMImageMessageBody body = msg.body as EMImageMessageBody; +// 本地大图路径 +body.localPath; +// 本地缩略图路径 +body.thumbnailLocalPath; +// 服务器大图路径。 +body.remotePath; +// 服务器缩略图路径。 +body.thumbnailRemotePath; +``` + +### 接收 GIF 图片消息 + +自 Flutter SDK 4.15.0 开始,支持接收 GIF 图片消息。 + +与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onMessageReceived` 回调方法。接收方判断为图片消息后,读取消息体的 `isGif` 属性,若值是 `YES`, 则为 GIF 图片消息。 + +```java +public void onMessageReceived(List messages) { + for(EMMessage message : messages) { + if (message.getType() == Type.IMAGE && ) { + EMImageMessageBody body = (EMImageMessageBody) msg.getBody(); + if(body.isGif()) { + // 根据业务情况处理 gif message, 例如下载展示该消息 + } + } + } + +} +``` + +### 接收视频消息 + +1. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见 [设置图片缩略图自动下载](#接收图片消息)。 +2. 接收方收到 [EMChatEventHandler#onMessagesReceived 回调](#接收文本消息),调用 `downloadAttachment` 下载视频文件。 + +```dart + +EMClient.getInstance.chatManager.addMessageEvent( + 'UNIQUE_HANDLER_ID', + ChatMessageEvent( + onSuccess: (msgId, msg) { + // 下载成功 + }, + onProgress: (msgId, progress) { + // 下载进度 + }, + onError: (msgId, msg, error) { + // 下载失败 + }, + ), +); + +// 下载附件 +EMClient.getInstance.chatManager.downloadAttachment(msg); + +``` + +3. 获取视频缩略图和视频原文件。 + +```dart +EMVideoMessageBody body = msg.body as EMVideoMessageBody; +// 本地视频路径 +body.localPath; +// 本地缩略图 +body.thumbnailLocalPath; +// 服务器视频文件路径。 +body.remotePath; +// 服务器缩略图路径。 +body.thumbnailRemotePath; +``` + +### 接收文件消息 + +1. 接收方收到 [EMChatEventHandler#onMessagesReceived 回调](#接收文本消息),调用 `downloadAttachment` 下载文件。 + +```dart +EMClient.getInstance.chatManager.addMessageEvent( + 'UNIQUE_HANDLER_ID', + ChatMessageEvent( + onSuccess: (msgId, msg) { + // 下载成功 + }, + onProgress: (msgId, progress) { + // 下载进度 + }, + onError: (msgId, msg, error) { + // 下载失败 + }, + ), +); + +// 下载附件 +EMClient.getInstance.chatManager.downloadAttachment(msg); +``` + +2. 调用以下方法从服务器或本地获取文件附件: + +```dart +EMFileMessageBody body = msg.body as EMFileMessageBody; +// 文件的本地路径 +body.localPath; +// 文件的服务器路径 +body.remotePath; +``` + +## 接收位置消息 + +接收位置消息与文本消息一致,详见 [接收文本消息](#接收文本消息)。 + +接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +## 接收透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +接收方通过 `onCmdMessagesReceived` 回调接收透传消息,方便用户进行不同的处理。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +```dart +final handler = EMChatEventHandler( + onCmdMessagesReceived: (messages) {}, +); + +// 添加监听 +EMClient.getInstance.chatManager.addEventHandler( + "UNIQUE_HANDLER_ID", + handler, +); + +// ... + +// 移除监听 +EMClient.getInstance.chatManager.removeEventHandler( + "UNIQUE_HANDLER_ID", +); +``` + +## 接收自定义类型消息 + +接收自定义消息与其他类型消息一致,详见 [接收文本消息](#接收文本消息)。 + +## 接收合并消息 + +为了方便消息互动,即时通讯 IM 自 4.1.0 版本开始支持将多个消息合并在一起进行转发。 + +接收合并消息与接收普通消息的操作相同,详见 [接收文本消息](#接收文本消息)。 +- 对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 +- 合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `EMChatManager#fetchCombineMessageDetail` 方法下载合并消息附件并解析出原始消息列表。 +- 对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: + - 若附件已存在,该方法会直接解析附件并返回原始消息列表。 + - 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 + +```dart + +try { + List msgList = + await EMClient.getInstance.chatManager.fetchCombineMessageDetail( + message: combineMsg, + ); +} on EMError catch (e) {} + +``` \ No newline at end of file diff --git a/docs/document/flutter/message_send.md b/docs/document/flutter/message_send.md new file mode 100644 index 000000000..145f5d0ae --- /dev/null +++ b/docs/document/flutter/message_send.md @@ -0,0 +1,283 @@ +# 发送消息 + +环信即时通讯 IM Flutter SDK 通过 `EMChatManager` 和 `EMMessage` 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 + +- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要 [开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 +- 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 +- 关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 发送文本消息 + +1. 调用 `EMMessage#createTxtSendMessage` 方法构造一条消息。 +2. 调用 `EMChatManager#sendMessage` 方法发送这条消息。 + +默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 + +```dart +// 创建一条文本消息。 +final msg = EMMessage.createTxtSendMessage( + // `targetId` 为接收方,单聊为对端用户 ID、群聊为群组 ID,聊天室为聊天室 ID。 + targetId: conversationId, + // `content` 为消息文字内容。 + content: 'hello', + // 会话类型:单聊为 `Chat`,群聊为 `GroupChat`, 聊天室为 `ChatRoom`,默认为单聊。 + chatType: ChatType.Chat, +); + +// 发送消息。 +EMClient.getInstance.chatManager.sendMessage(msg); +``` + +## 发送附件消息 + +除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 + +发送附件消息分为以下两步: + +1. 创建和发送附件类型消息。 +2. SDK 将附件上传到环信服务器。 + +### 发送语音消息 + +1. 发送语音消息前,在应用层录制语音文件。 +2. 发送方调用 `EMMessage#createVoiceSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID),语音文件的 `filePath` 和语音时长创建语音消息。 +3. 发送方调用 `sendMessage` 方法发送消息。SDK 会将语音文件上传至环信服务器。 + +```dart +final voiceMsg = EMMessage.createVoiceSendMessage( + targetId: targetId, + filePath: filePath, + duration: 30, +); + +EMClient.getInstance.chatManager.sendMessage(msg); +``` + +### 发送图片消息 + +1. 发送方调用 `EMMessage#createImageSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)和图片文件的 `filePath`,创建图片消息。 +2. 发送方调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 + +```dart +final imgMsg = EMMessage.createImageSendMessage( + targetId: targetId, + filePath: filePath, +); + +EMClient.getInstance.chatManager.sendMessage(imgMsg); +``` + +### 发送 GIF 图片消息 + +自 Flutter SDK 4.15.0 开始,支持发送 GIF 图片消息。 + +GIF 图片消息是一种特殊的图片消息,与普通图片消息不同,**GIF 图片发送时不能压缩**。 + +图片缩略图的生成和下载与普通图片消息相同,详见 [发送图片消息](#发送图片消息)。 + +使用 `EMMessage#createImageSendMessage` 方法构造 GIF 图片消息体。 + +```dart + final msg = EMMessage.createImageSendMessage( + targetId: 'targetId', + filePath: 'filePath', + isGif: true, + ); + + EMClient.getInstance.chatManager.sendMessage(msg); +``` + +### 发送视频消息 + +1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 +你可以设置发送消息结果回调,用于接收消息发送进度或者发送结果,如发送成功或失败。为此,需实现 `EMChatManager#addMessageEvent` 接口。 +2. 发送方调用 `EMMessage#createVideoSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)、图片文件的 `filePath`、创建视频消息。 +3. 发送方调用 `sendMessage` 方法发送消息。SDK 会将视频文件上传至消息服务器。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `createVideoSendMessage` 方法。 + +```dart +final videoMsg = EMMessage.createVideoSendMessage( + targetId: targetId, + filePath: filePath, + thumbnailLocalPath: thumbnailLocalPath, + duration: 30, +); + +EMClient.getInstance.chatManager.sendMessage(videoMsg); + +``` + +### 发送文件消息 + +1. 发送方调用 `EMMessage#createImageSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)和文件的 `filePath`,创建文件消息。 +2. 发送方调用 `sendMessage` 方法发送该消息。SDK 将文件上传至环信服务器。 + +```dart +final fileMsg = EMMessage.createFileSendMessage( + targetId: targetId, + filePath: filePath, +); + +EMClient.getInstance.chatManager.sendMessage(fileMsg); +``` + +## 发送位置消息 + +1. 发送方调用 `EMMessage#createLocationSendMessage` 方法创建位置消息。 +2. 发送方调用 `EMChatManager#sendMessage` 方法发送位置消息。 + +发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 + +```dart +final localMsg = EMMessage.createLocationSendMessage( + targetId: targetId, + latitude: 0, + longitude: 0, + address: 'address', +); + +EMClient.getInstance.chatManager.sendMessage(localMsg); +``` + +## 发送和接收透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +发送透传消息的过程如下: + +1. 发送方调用 `EMMessage#createCmdSendMessage` 方法创建和发送透传消息。 +2. 发送方调用 `sendMessage` 方法发送消息。 + +```dart +final cmdMsg = EMMessage.createCmdSendMessage( + targetId: targetId, + // `action` 可以自定义。 + action: action, +); + +EMClient.getInstance.chatManager.sendMessage(cmdMsg); +``` + +## 发送自定义类型消息 + +除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +```dart +final customMsg = EMMessage.createCustomSendMessage( + targetId: targetId, + // `event` 为需要传递的自定义消息事件,比如礼物消息,可以设置: + event: 'gift', + // `params` 类型为 `Map`。 + params: {'k': 'v'}, +); + +EMClient.getInstance.chatManager.sendMessage(customMsg); +``` + +## 发送合并消息 + +为了方便消息互动,即时通讯 IM 自 4.1.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: + +1. 利用原始消息列表创建一条合并消息。 +2. 发送合并消息。 + +你可以调用 `createCombineSendMessage` 方法创建一条合并消息,然后调用 `sendMessage` 方法发送该条消息。 + +创建合并消息时,需要设置以下参数: + +| 属性 | 类型 | 描述 | +| :-------------- | :-------------------- | :-------------------- | +| `title` | String | 合并消息的标题。 | +| `summary` | String | 合并消息的概要。 | +| `compatibleText` | String | 合并消息的兼容文本。
兼容文本起向下兼容不支持消息合并转发的版本的作用。当支持合并消息的 SDK 向不支持合并消息的低版本 SDK 发送消息时,低版本的 SDK 会将该属性解析为文本消息的消息内容。 | +| `msgIds` | List | 合并消息的原始消息 ID 列表。该列表最多包含 300 个消息 ID。 | +| `targetId` | String | 消息接收方。该字段的设置取决于会话类型:
- 单聊:对方用户 ID;
- 群聊:群组 ID;
- 子区会话:子区 ID;
- 聊天室聊天:聊天室 ID。| + +:::tip +1. 合并转发支持嵌套,最多支持 10 层嵌套,每层最多 300 条消息。 +2. 不论 `EMOptions#serverTransfer` 设置为 `false` 或 `true`,SDK 都会将合并消息附件上传到环信服务器。 +3. 合并消息不支持搜索。 +4. 对于转发合并消息,例如,用户 A 向用户 B 发送了合并消息,用户 B 将该合并消息转发给用户 C,需要调用转发单条合并消息的 API。详见 [转发单条消息](message_forward.html#转发单条消息)。 +::: + +示例代码如下: + +```dart +final combineMsg = EMMessage.createCombineSendMessage( + targetId: targetId, + title: 'A和B的聊天记录', + summary: 'A:这是A的消息内容\nB:这是B的消息内容', + compatibleText: compatibleText, + msgIds: msgIds, +); + +EMClient.getInstance.chatManager.sendMessage(combineMsg); +``` + +## 更多 + +### 聊天室消息优先级与消息丢弃逻辑 + +- **消息优先级**:对于聊天室消息,环信即时通讯提供消息分级功能,支持高、普通和低三种优先级,高优先级的消息会优先送达。你可以在创建消息时对指定消息类型或指定成员的消息设置为高优先级,确保这些消息优先送达。这种方式可以确保在聊天室内消息并发量较大或消息发送频率过高的情况下,服务器首先丢弃低优先级消息,将资源留给高优先级消息,确保重要消息(如打赏、公告等)优先送达,以此提升重要消息的可靠性。请注意,该功能并不保证高优先级消息必达。在聊天室内消息并发量过大的情况下,为保证用户实时互动的流畅性,即使是高优先级消息仍然会被丢弃。 + +- **消息丢弃逻辑**:对于单个聊天室,每秒发送的消息数量默认超过 20 条,则会触发消息丢弃逻辑,即首先丢弃低优先级的消息,优先保留高优先级的消息。若带有优先级的消息超过了 20 条/秒,则按照消息发送时间顺序处理,丢弃后发送的消息。 + +```dart +final msg = EMMessage.createTxtSendMessage( + targetId: conversationId, + content: 'hello', + chatType: ChatType.ChatRoom, +); + +// 聊天室消息的优先级。如果不设置,默认值为 `Normal`,即“普通”优先级。 +msg.chatroomMessagePriority = ChatRoomMessagePriority.High; +EMClient.getInstance.chatManager.sendMessage(msg); + +``` + +### 获取发送附件消息的进度 + +发送附件类型消息时,可以在 `ChatMessageEvent#onProgress` 回调中获取附件上传的进度(百分比),以 int 表示,范围为 [0, 100],示例代码如下: + +```dart +final handler = ChatMessageEvent( + // 消息发送成功回调,msgId 为消息原始 ID,msg 为发送完成后的消息。 + onSuccess: (msgId, msg) {}, + // 附件上传进度回调,msgId 为消息原始 ID,progress 为消息发送进度(百分比), 范围[0, 100]。 + onProgress: (msgId, progress) {}, + // 消息发送失败回调,msgId 为消息原始 ID,msg 为发送完成后的消息,error 为错误原因。 + onError: (msgId, msg, error) {}, +); + +/// 添加监听 +EMClient.getInstance.chatManager.addMessageEvent( + 'UNIQUE_HANDLER_ID', + handler, +); + +/// 移除监听 +EMClient.getInstance.chatManager.removeMessageEvent('UNIQUE_HANDLER_ID'); +``` + +### 发送消息前的内容审核 + +- 内容审核关注消息 body + +[内容审核服务会关注消息 body 中指定字段的内容,不同类型的消息审核不同的字段](/product/moderation/moderation_mechanism.html),若创建消息时在这些字段中传入了很多业务信息,可能会影响审核效果。因此,创建消息时需要注意内容审核的字段不涉及业务信息,建议业务信息放在扩展字段中。 + +- 设置发送方收到内容审核替换后的内容 + +若初始化时打开了 `ChatOptions#useReplacedMessageContents` 开关,发送文本消息时如果被内容审核(Moderation)进行了内容替换,发送方会收到替换后的内容。若该开关为关闭状态,则发送方不会收到替换后的内容。 \ No newline at end of file diff --git a/docs/document/flutter/message_send_receive.md b/docs/document/flutter/message_send_receive.md deleted file mode 100644 index 50f9a0b00..000000000 --- a/docs/document/flutter/message_send_receive.md +++ /dev/null @@ -1,616 +0,0 @@ -# 发送和接收消息 - -环信即时通讯 IM Flutter SDK 通过 `EMChatManager` 和 `EMMessage` 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 - -- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - -- 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 - -关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 - -## 前提条件 - -开始前,请确保满足以下条件: - -- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 - -## 发送和接收文本消息 - -1. 首先,利用 `EMMessage` 类构造一条消息。 - -默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 - -示例代码: - -```dart -// 创建一条文本消息。 -final msg = EMMessage.createTxtSendMessage( - // `targetId` 为接收方,单聊为对端用户 ID、群聊为群组 ID,聊天室为聊天室 ID。 - targetId: conversationId, - // `content` 为消息文字内容。 - content: 'hello', - // 会话类型:单聊为 `Chat`,群聊为 `GroupChat`, 聊天室为 `ChatRoom`,默认为单聊。 - chatType: ChatType.Chat, -); - -// 发送消息。 -EMClient.getInstance.chatManager.sendMessage(msg); -``` - -2. 通过 `EMChatManager` 将消息发出。发送时可以设置 `ChatMessageEvent` ,获取消息发送状态。 - -```dart -// 添加消息状态监听器 -EMClient.getInstance.chatManager.addMessageEvent( - "UNIQUE_HANDLER_ID", - ChatMessageEvent( - // 收到成功回调之后,可以对发送的消息进行更新处理,或者其他操作。 - onSuccess: (msgId, msg) { - // msgId 发送时消息 ID; - // msg 发送成功的消息; - }, - // 收到回调之后,可以将发送的消息状态进行更新,或者进行其他操作。 - onError: (msgId, msg, error) { - // msgId 发送时的消息 ID; - // msg 发送失败的消息; - // error 失败原因; - }, - // 对于附件类型的消息,如图片,语音,文件,视频类型,上传或下载文件时会收到相应的进度值,表示附件的上传或者下载进度。 - onProgress: (msgId, progress) { - // msgId 发送时的消息ID; - // progress 进度; - }, - ), -); - -void dispose() { - // 移除消息状态监听器 - EMClient.getInstance.chatManager.removeMessageEvent("UNIQUE_HANDLER_ID"); - super.dispose(); -} - -// 消息发送结果会通过 ChatMessageEvent 回调对象返回,该返回结果仅表示该方法的调用结果,与实际消息发送状态无关。 -EMClient.getInstance.chatManager.sendMessage(message).then((value) { - // 消息发送动作完成。 -}); -``` - -3. 你可以添加 `EMChatEventHandler` 监听器接收消息。`EMChatEventHandler` 可以多次添加。请记得在不需要的时候移除该监听器,如在 `dispose` 时。 - -在新消息到来时,你会收到 `onMessagesReceived` 事件,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。 - -若在初始化时打开了 `ChatOptions#messagesReceiveCallbackIncludeSend` 开关,则该回调中会返回发送成功的消息。 - -对于聊天室消息,你可以通过消息的 `EMMessage#isBroadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```dart -// 继承并实现 EMChatEventHandler -class _ChatMessagesPageState extends State { - @override - void initState() { - super.initState(); - // 添加监听器 - EMClient.getInstance.chatManager.addEventHandler( - "UNIQUE_HANDLER_ID", - EMChatEventHandler( - onMessagesReceived: (list) => {}, - ), - ); - } - - @override - Widget build(BuildContext context) { - return Container(); - } - - @override - void dispose() { - // 移除监听器 - EMClient.getInstance.chatManager.removeEventHandler("UNIQUE_HANDLER_ID"); - super.dispose(); - } -} -``` - -## 发送和接收附件消息 - -附件消息的发送和接收过程如下: - -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器。 -2. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 -3. 获取附件的服务器地址和本地路径。 - -自 4.15.0 版本开始,即时通讯 IM 支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户必须调用 SDK 的 `downloadAttachment` 方法下载消息附件。 - -### 发送和接收语音消息 - -发送和接收语音消息的过程如下: - -1. 发送语音消息前,在应用层录制语音文件。 -2. 发送方调用 `EMMessage#createVoiceSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID),语音文件的 filePath 和语音时长创建语音消息,然后调用 `sendMessage` 方法发送消息。SDK 会将语音文件上传至环信服务器。 - -```dart -final voiceMsg = EMMessage.createVoiceSendMessage( - targetId: targetId, - filePath: filePath, - duration: 30, -); - -EMClient.getInstance.chatManager.sendMessage(msg); -``` -3. 接收方收到语音消息时,自动下载语音文件。 - -4. 接收方收到 [EMChatEventHandler#onMessagesReceived](#发送和接收文本消息) 回调,调用 `remotePath` 或 `localPath` 方法获取语音文件的服务器地址或本地路径,从而获取语音文件。 - -```dart -if(msg.body.type == MessageType.VOICE) { - EMVoiceMessageBody body = msg.body as EMVoiceMessageBody; - body.duration; // 语音时长 - body.localPath; // 本地语音文件路径 - body.remotePath; // 远程语音文件路径 -} - -``` - -### 发送和接收图片消息 - -发送和接收图片消息的流程如下: - -1. 发送方调用 `EMMessage#createImageSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)和图片文件的 `filePath`,创建图片消息,然后调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 - -```dart -final imgMsg = EMMessage.createImageSendMessage( - targetId: targetId, - filePath: filePath, -); - -EMClient.getInstance.chatManager.sendMessage(imgMsg); -``` - -2. 接收方收到图片消息,自动下载图片缩略图。 - -- 默认情况下,SDK 自动下载缩略图,即 `EMOptions#isAutoDownloadThumbnail` 设置为 `true`。 -- 若设置为手动下载缩略图,即 `EMOptions#isAutoDownloadThumbnail` 设置为 `false`,需调用 `EMChatManage#downloadThumbnail` 下载。 - -3. 接收方收到 [EMChatEventHandler#onMessagesReceived 回调](#发送和接收文本消息),调用 `downloadAttachment` 下载大图。 - -```dart -EMClient.getInstance.chatManager.addMessageEvent( - 'UNIQUE_HANDLER_ID', - ChatMessageEvent( - onSuccess: (msgId, msg) { - // 下载成功 - }, - onProgress: (msgId, progress) { - // 下载进度 - }, - onError: (msgId, msg, error) { - // 下载失败 - }, - ), -); - -// 下载附件 -EMClient.getInstance.chatManager.downloadAttachment(msg); -``` - -4. 下载成功后获取图片消息的缩略图和附件。 - -```dart -EMImageMessageBody body = msg.body as EMImageMessageBody; -// 本地大图路径 -body.localPath; -// 本地缩略图路径 -body.thumbnailLocalPath; -// 服务器大图路径。 -body.remotePath; -// 服务器缩略图路径。 -body.thumbnailRemotePath; -``` - -### 发送和接收 GIF 图片消息 - -自 Flutter SDK 4.15.0 开始,支持发送和接收 GIF 图片消息。 - -GIF 图片消息是一种特殊的图片消息,与普通图片消息不同,**GIF 图片发送时不能压缩**。 - -图片缩略图的生成和下载与普通图片消息相同,详见 [发送和接收图片消息](#发送和接收图片消息)。 - -#### 发送 GIF 图片消息 - -使用 `EMMessage#createImageSendMessage` 方法构造 GIF 图片消息体。 - -```dart - final msg = EMMessage.createImageSendMessage( - targetId: 'targetId', - filePath: 'filePath', - isGif: true, - ); - - EMClient.getInstance.chatManager.sendMessage(msg); -``` - -#### 接收 GIF 图片消息 - -与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onMessageReceived` 回调方法。接收方判断为图片消息后,读取消息体的 `isGif` 属性,若值是 `YES`, 则为 GIF 图片消息。 - -```java -public void onMessageReceived(List messages) { - for(EMMessage message : messages) { - if (message.getType() == Type.IMAGE && ) { - EMImageMessageBody body = (EMImageMessageBody) msg.getBody(); - if(body.isGif()) { - // 根据业务情况处理 gif message, 例如下载展示该消息 - } - } - } - -} -``` - -### 发送和接收视频消息 - -发送和接收视频消息的流程如下: - -1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 - -你可以设置发送消息结果回调,用于接收消息发送进度或者发送结果,如发送成功或失败。为此,需实现 `EMChatManager#addMessageEvent` 接口。 - -2. 发送方调用 `EMMessage#createVideoSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID),图片文件的 `filePath`、创建视频消息,然后调用 `sendMessage` 方法发送消息。SDK 会将视频文件上传至消息服务器。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `createVideoSendMessage` 方法。 - -```dart - -final videoMsg = EMMessage.createVideoSendMessage( - targetId: targetId, - filePath: filePath, - thumbnailLocalPath: thumbnailLocalPath, - duration: 30, -); - -EMClient.getInstance.chatManager.sendMessage(videoMsg); - -``` - -3. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#发送和接收图片消息)。 - -4. 接收方收到 [EMChatEventHandler#onMessagesReceived 回调](#发送和接收文本消息),调用 `downloadAttachment` 下载视频文件。 - -```dart - -EMClient.getInstance.chatManager.addMessageEvent( - 'UNIQUE_HANDLER_ID', - ChatMessageEvent( - onSuccess: (msgId, msg) { - // 下载成功 - }, - onProgress: (msgId, progress) { - // 下载进度 - }, - onError: (msgId, msg, error) { - // 下载失败 - }, - ), -); - -// 下载附件 -EMClient.getInstance.chatManager.downloadAttachment(msg); - -``` - -5. 获取视频缩略图和视频原文件。 - -```dart -EMVideoMessageBody body = msg.body as EMVideoMessageBody; -// 本地视频路径 -body.localPath; -// 本地缩略图 -body.thumbnailLocalPath; -// 服务器视频文件路径。 -body.remotePath; -// 服务器缩略图路径。 -body.thumbnailRemotePath; -``` - -### 发送和接收文件消息 - -发送和接收文件消息的流程如下: - -1. 发送方调用 `EMMessage#createImageSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID),文件的 filePath、创建文件消息,然后调用 `sendMessage` 方法发送该消息。SDK 将文件上传至环信服务器。 - -```dart -final fileMsg = EMMessage.createFileSendMessage( - targetId: targetId, - filePath: filePath, -); - -EMClient.getInstance.chatManager.sendMessage(fileMsg); -``` - -2. 接收方收到 [EMChatEventHandler#onMessagesReceived 回调](#发送和接收文本消息),调用 `downloadAttachment` 下载文件。 - -```dart -EMClient.getInstance.chatManager.addMessageEvent( - 'UNIQUE_HANDLER_ID', - ChatMessageEvent( - onSuccess: (msgId, msg) { - // 下载成功 - }, - onProgress: (msgId, progress) { - // 下载进度 - }, - onError: (msgId, msg, error) { - // 下载失败 - }, - ), -); - -// 下载附件 -EMClient.getInstance.chatManager.downloadAttachment(msg); -``` - -3. 调用以下方法从服务器或本地获取文件附件: - -```dart -EMFileMessageBody body = msg.body as EMFileMessageBody; -// 文件的本地路径 -body.localPath; -// 文件的服务器路径 -body.remotePath; -``` - -## 发送和接收位置消息 - -1. 创建和发送位置消息。 - -发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 - -```dart -final localMsg = EMMessage.createLocationSendMessage( - targetId: targetId, - latitude: 0, - longitude: 0, - address: 'address', -); - -EMClient.getInstance.chatManager.sendMessage(localMsg); -``` - -2. 接收位置消息与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - - 接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 - -## 发送和接收透传消息 - -透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 - -具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 - -:::tip -- 透传消息发送后,不支持撤回。 -- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 -::: - -1. 创建和发送透传消息。 - -```dart -final cmdMsg = EMMessage.createCmdSendMessage( - targetId: targetId, - // `action` 可以自定义。 - action: action, -); - -EMClient.getInstance.chatManager.sendMessage(cmdMsg); -``` - -2. 接收方通过 `onCmdMessagesReceived` 回调接收透传消息,方便用户进行不同的处理。 - -```dart -final handler = EMChatEventHandler( - onCmdMessagesReceived: (messages) {}, -); - -// 添加监听 -EMClient.getInstance.chatManager.addEventHandler( - "UNIQUE_HANDLER_ID", - handler, -); - -// ... - -// 移除监听 -EMClient.getInstance.chatManager.removeEventHandler( - "UNIQUE_HANDLER_ID", -); -``` - -## 发送自定义类型消息 - -除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 - -接收自定义消息与其他类型消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -```dart -final customMsg = EMMessage.createCustomSendMessage( - targetId: targetId, - // `event` 为需要传递的自定义消息事件,比如礼物消息,可以设置: - event: 'gift', - // `params` 类型为 `Map`。 - params: {'k': 'v'}, -); - -EMClient.getInstance.chatManager.sendMessage(customMsg); -``` - -## 发送和接收合并消息 - -为了方便消息互动,即时通讯 IM 自 4.1.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: - -1. 利用原始消息列表创建一条合并消息。 -2. 发送合并消息。 -3. 对端收到合并消息后进行解析,获取原始消息列表。 - -#### 创建和发送合并消息 - -你可以调用 `createCombineSendMessage` 方法创建一条合并消息,然后调用 `sendMessage` 方法发送该条消息。 - -创建合并消息时,需要设置以下参数: - -| 属性 | 类型 | 描述 | -| :-------------- | :-------------------- | :-------------------- | -| `title` | String | 合并消息的标题。 | -| `summary` | String | 合并消息的概要。 | -| `compatibleText` | String | 合并消息的兼容文本。
兼容文本起向下兼容不支持消息合并转发的版本的作用。当支持合并消息的 SDK 向不支持合并消息的低版本 SDK 发送消息时,低版本的 SDK 会将该属性解析为文本消息的消息内容。 | -| `msgIds` | List | 合并消息的原始消息 ID 列表。该列表最多包含 300 个消息 ID。 | -| `targetId` | String | 消息接收方。该字段的设置取决于会话类型:
- 单聊:对方用户 ID;
- 群聊:群组 ID;
- 子区会话:子区 ID;
- 聊天室聊天:聊天室 ID。| - -:::tip -1. 合并转发支持嵌套,最多支持 10 层嵌套,每层最多 300 条消息。 -2. 不论 `EMOptions#serverTransfer` 设置为 `false` 或 `true`,SDK 都会将合并消息附件上传到环信服务器。 -::: - -示例代码如下: - -```dart -final combineMsg = EMMessage.createCombineSendMessage( - targetId: targetId, - title: 'A和B的聊天记录', - summary: 'A:这是A的消息内容\nB:这是B的消息内容', - compatibleText: compatibleText, - msgIds: msgIds, -); - -EMClient.getInstance.chatManager.sendMessage(combineMsg); -``` - -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `EMChatManager#fetchCombineMessageDetail` 方法下载合并消息附件并解析出原始消息列表。 - -对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: - -- 若附件已存在,该方法会直接解析附件并返回原始消息列表。 -- 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 - -```dart - -try { - List msgList = - await EMClient.getInstance.chatManager.fetchCombineMessageDetail( - message: combineMsg, - ); -} on EMError catch (e) {} - -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 仅 SDK 4.1.0 及以上版本支持。 -2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: - -1. 创建一条群组或聊天室消息。 -2. 设置消息的接收方。 -3. 发送定向消息。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```dart - -final msg = EMMessage.createTxtSendMessage( - targetId: targetId, - content: 'content', - chatType: ChatType.GroupChat, -); -// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`,则消息发送给群组或聊天室的所有成员。 -msg.receiverList = ['userId1', 'userId2']; -EMClient.getInstance.chatManager.sendMessage(msg); - -``` -接收群定向消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 - -## 使用消息扩展字段 - -当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型。 - -当目前消息类型不满足用户需求时,可以在扩展部分保存更多信息,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 - -```dart -try { - final msg = EMMessage.createTxtSendMessage( - targetId: targetId, - content: 'content', - ); - - msg.attributes = {'k': 'v'}; - EMClient.getInstance.chatManager.sendMessage(msg); -} on EMError catch (e) {} -``` - -## 更多 - -### 聊天室消息优先级与消息丢弃逻辑 - -- **消息优先级**:对于聊天室消息,环信即时通讯提供消息分级功能,支持高、普通和低三种优先级,高优先级的消息会优先送达。你可以在创建消息时对指定消息类型或指定成员的消息设置为高优先级,确保这些消息优先送达。这种方式可以确保在聊天室内消息并发量较大或消息发送频率过高的情况下,服务器首先丢弃低优先级消息,将资源留给高优先级消息,确保重要消息(如打赏、公告等)优先送达,以此提升重要消息的可靠性。请注意,该功能并不保证高优先级消息必达。在聊天室内消息并发量过大的情况下,为保证用户实时互动的流畅性,即使是高优先级消息仍然会被丢弃。 - -- **消息丢弃逻辑**:对于单个聊天室,每秒发送的消息数量默认超过 20 条,则会触发消息丢弃逻辑,即首先丢弃低优先级的消息,优先保留高优先级的消息。若带有优先级的消息超过了 20 条/秒,则按照消息发送时间顺序处理,丢弃后发送的消息。 - -```dart -final msg = EMMessage.createTxtSendMessage( - targetId: conversationId, - content: 'hello', - chatType: ChatType.ChatRoom, -); - -// 聊天室消息的优先级。如果不设置,默认值为 `Normal`,即“普通”优先级。 -msg.chatroomMessagePriority = ChatRoomMessagePriority.High; -EMClient.getInstance.chatManager.sendMessage(msg); - -``` - -### 获取发送附件消息的进度 - -发送附件类型消息时,可以在 `ChatMessageEvent#onProgress` 回调中获取附件上传的进度(百分比),以 int 表示,范围为 [0, 100],示例代码如下: - -```dart -final handler = ChatMessageEvent( - // 消息发送成功回调,msgId 为消息原始 ID,msg 为发送完成后的消息。 - onSuccess: (msgId, msg) {}, - // 附件上传进度回调,msgId 为消息原始 ID,progress 为消息发送进度(百分比), 范围[0, 100]。 - onProgress: (msgId, progress) {}, - // 消息发送失败回调,msgId 为消息原始 ID,msg 为发送完成后的消息,error 为错误原因。 - onError: (msgId, msg, error) {}, -); - -/// 添加监听 -EMClient.getInstance.chatManager.addMessageEvent( - 'UNIQUE_HANDLER_ID', - handler, -); - -/// 移除监听 -EMClient.getInstance.chatManager.removeMessageEvent('UNIQUE_HANDLER_ID'); -``` - -### 发送消息前的内容审核 - -- 内容审核关注消息 body - -[内容审核服务会关注消息 body 中指定字段的内容,不同类型的消息审核不同的字段](/product/moderation/moderation_mechanism.html),若创建消息时在这些字段中传入了很多业务信息,可能会影响审核效果。因此,创建消息时需要注意内容审核的字段不涉及业务信息,建议业务信息放在扩展字段中。 - -- 设置发送方收到内容审核替换后的内容 - -若初始化时打开了 `ChatOptions#useReplacedMessageContents` 开关,发送文本消息时如果被内容审核(Moderation)进行了内容替换,发送方会收到替换后的内容。若该开关为关闭状态,则发送方不会收到替换后的内容。 \ No newline at end of file diff --git a/docs/document/flutter/message_target.md b/docs/document/flutter/message_target.md new file mode 100644 index 000000000..d10626a7c --- /dev/null +++ b/docs/document/flutter/message_target.md @@ -0,0 +1,34 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 + +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 仅 SDK 4.1.0 及以上版本支持。 +2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: + +1. 创建一条群组或聊天室消息。 +2. 设置消息的接收方。 +3. 发送定向消息。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```dart + +final msg = EMMessage.createTxtSendMessage( + targetId: targetId, + content: 'content', + chatType: ChatType.GroupChat, +); +// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`,则消息发送给群组或聊天室的所有成员。 +msg.receiverList = ['userId1', 'userId2']; +EMClient.getInstance.chatManager.sendMessage(msg); + +``` +接收群定向消息与接收普通消息的操作相同,详见 [接收文本消息](message_receive.html#接收文本消息)。 \ No newline at end of file diff --git a/docs/document/harmonyos/message_extension.md b/docs/document/harmonyos/message_extension.md new file mode 100644 index 000000000..ce4a351a3 --- /dev/null +++ b/docs/document/harmonyos/message_extension.md @@ -0,0 +1,32 @@ +# 使用消息扩展字段 + +当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```typescript +let message = ChatMessage.createTxtSendMessage(toChatUsername, content); +if (!message) { + return; +} +// 增加自定义属性。 +let attributes = new Map(); +attributes.set("attribute1", "value"); +attributes.set("attribute2", true); +attributes.set("attribute3", 123); +attributes.set("attribute4", { + nickname: 'Nickname', + avatarUrl: 'https://www.easemob.com/example.png', + gender: Gender.MALE +} as UserInfo); +message.setExt(attributes); +ChatClient.getInstance().chatManager()?.sendMessage(message); +// 获取自定义属性 +let exts = message.ext(); +let attr1 = exts.get("attribute1") as string; +let attr2 = exts.get("attribute2") as boolean; +let attr3 = exts.get("attribute3") as boolean; +let attr4 = exts.get("attribute4") as UserInfo; +``` + +:::tip +1.6.0 版本 `ChatMessage.setExt` 方法支持 object 数据类型,用于设置 JSON 结构的扩展信息。 +::: \ No newline at end of file diff --git a/docs/document/harmonyos/message_receive.md b/docs/document/harmonyos/message_receive.md new file mode 100644 index 000000000..13ab253fd --- /dev/null +++ b/docs/document/harmonyos/message_receive.md @@ -0,0 +1,262 @@ +# 接收消息 + +环信即时通讯 IM HarmonyOS SDK 通过 [ChatMessageListener](https://sdkdocs.easemob.com/apidoc/harmony/chat3.0/modules/ChatMessageListener.html) 类实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +你可以用注册监听 `ChatMessageListener` 接收消息。该 `ChatMessageListener` 可以多次添加,请记得在不需要的时候移除 `listener`。 + +在新消息到来时,你会收到 `onMessageReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。 + +对于聊天室消息,你可以通过消息的 `ChatMessage#isBroadcast` 属性判断该消息是否为 [通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```typescript +let msgListener: ChatMessageListener = { + onMessageReceived: (messages: ChatMessage[]): void => { + // 收到消息,遍历消息队列,解析和显示。 + } +} +// 注册消息监听 +ChatClient.getInstance().chatManager()?.addMessageListener(msgListener); +// 解注册消息监听 +ChatClient.getInstance().chatManager()?.removeMessageListener(msgListener); +``` + +## 接收附件消息 + +除文本消息外,SDK 还支持接收附件类型消息,包括语音、图片、视频和文件消息。 + +附件消息的接收过程如下: + +1. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 +2. 获取附件的服务器地址和本地路径。 + +自 1.7.0 版本开始,即时通讯 IM 支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户必须调用 SDK 的 `downloadAttachment` 方法下载消息附件。 + +### 接收语音消息 + +1. 接收方收到语音消息时,自动下载语音文件。 + +2. 接收方收到 [onMessageReceived](#接收文本消息) 回调,调用 `getRemoteUrl` 或 `getLocalPath` 方法获取语音文件的服务器地址或本地路径,从而获取语音文件。 + +```typescript +let voiceBody = message.getBody() as VoiceMessageBody; +// 获取语音文件在服务器的地址。 +let voiceRemoteUrl = voiceBody.getRemoteUrl(); +// 本地语音文件的本地路径。 +let voiceLocalPath = voiceBody.getLocalPath(); +``` + +### 接收图片消息 + +1. 接收方收到图片消息,自动下载图片缩略图。 + +- 默认情况下,SDK 自动下载缩略图,即 `ChatOptions.setAutoDownloadThumbnail` 设置为 `true`。 +- 若设置为手动下载缩略图,即 `ChatOptions.setAutoDownloadThumbnail` 设置为 `false` ,需调用 `ChatClient.getInstance().chatManager()?.downloadThumbnail(message)` 下载。 + +2. 接收方收到 [onMessageReceived](#接收文本消息) 回调,调用 `downloadAttachment` 下载原图。 + +```typescript +let msgListener: ChatMessageListener = { + onMessageReceived: (messages: ChatMessage[]): void => { + messages.forEach( message => { + if (message.getType() === ContentType.IMAGE) { + let callback: ChatCallback = { + onSuccess: (): void => { + // 附件下载成功 + }, + onError: (code: number, error: string): void => { + // 附件下载失败 + }, + onProgress: (progress: number): void => { + // 附件下载进度 + } + } + message.setMessageStatusCallback(callback); + // 下载附件 + ChatClient.getInstance().chatManager()?.downloadAttachment(message); + } + }) + } +} +``` + +3. 获取图片消息的缩略图和附件。 + +```typescript +let imgBody = message.getBody() as ImageMessageBody; +// 从服务器端获取图片文件。 +let imgRemoteUrl = imgBody.getRemoteUrl(); +// 从服务器端获取图片缩略图。 +let thumbnailUrl = imgBody.getThumbnailRemoteUrl(); +// 从本地获取图片文件。 +let imgLocalPath = imgBody.getLocalPath(); +// 从本地获取图片缩略图。 +let thumbnailLocalPath = imgBody.getThumbnailLocalPath(); +``` + +### 接收 GIF 图片消息 + +自 HarmonyOS SDK 1.7.0 开始,支持接收 GIF 图片消息。 + +GIF 图片缩略图的下载与普通图片消息相同,详见 [接收图片消息](#接收图片消息)。 + +与普通消息相同,接收 GIF 图片消息时,接收方会收到 [onMessageReceived](#接收文本消息) 回调方法。接收方判断为图片消息后,读取消息体的 `isGif` 属性,若值是 `YES`, 则为 GIF 图片消息。 + +```typescript +ChatClient.getInstance().chatManager()?.addMessageListener({ + onMessageReceived: (messages) => { + messages.forEach(message => { + if (message.getType() === ContentType.IMAGE) { + let body = message.getBody() as ImageMessageBody; + if (body.isGif()) { + // 根据业务情况处理gif message, 例如下载展示该消息 + } + } + }) + } +}); +``` + +### 接收视频消息 + +1. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#接收图片消息)。 + +2. 接收方收到 [onMessageReceived](#接收文本消息) 回调,可以调用 `ChatClient.getInstance().chatManager()?.downloadAttachment(message)` 方法下载视频原文件。 + +```typescript +let msgListener: ChatMessageListener = { + onMessageReceived: (messages: ChatMessage[]): void => { + messages.forEach( message => { + if (message.getType() === ContentType.VIDEO) { + let callback: ChatCallback = { + onSuccess: (): void => { + // 附件下载成功 + }, + onError: (code: number, error: string): void => { + // 附件下载失败 + }, + onProgress: (progress: number): void => { + // 附件下载进度 + } + } + message.setMessageStatusCallback(callback); + // 下载附件 + ChatClient.getInstance().chatManager()?.downloadAttachment(message); + } + }) + } +} +``` + +3. 获取视频缩略图和视频原文件。 + +```typescript +let body = message.getBody() as VideoMessageBody; +// 从服务器端获取视频文件。 +let imgRemoteUrl = body.getRemoteUrl(); +// 从服务器获取视频缩略图文件。 +let thumbnailUrl = body.getThumbnailRemoteUrl(); +// 从本地获取视频文件文件。 +let localPath = body.getLocalPath(); +// 从本地获取视频缩略图文件。 +let localThumbPath = body.getThumbnailLocalPath(); +``` + +### 接收文件消息 + +1. 接收方收到 [onMessageReceived](#接收文本消息) 回调,调用 `downloadAttachment` 方法下载文件。 + +```typescript +/** + * 下载文件。 + */ +private downloadFile(message: ChatMessage) { + let callback: ChatCallback = { + onSuccess: (): void => { + // 附件下载成功 + }, + onError: (code: number, error: string): void => { + // 附件下载失败 + }, + onProgress: (progress: number): void => { + // 附件下载进度 + } + } + message.setMessageStatusCallback(callback); + // 下载附件 + ChatClient.getInstance().chatManager()?.downloadAttachment(message); +} +``` + +2. 调用以下方法从服务器或本地获取文件附件: + +```typescript +let fileMessageBody = message.getBody() as FileMessageBody; +// 从服务器获取文件。 +let fileRemoteUrl = fileMessageBody.getRemoteUrl(); +// 从本地获取文件。 +let fileLocalPath = fileMessageBody.getLocalPath(); +``` + +## 接收位置消息 + +接收位置消息与文本消息一致,详见 [接收文本消息](#接收文本消息)。 + +接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +## 接收透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +接收方通过 [onMessageReceived](#接收文本消息) 和 `onCmdMessageReceived` 回调接收透传消息,方便用户进行不同的处理。 + +```typescript +let msgListener: ChatMessageListener = { + onMessageReceived: (messages: ChatMessage[]): void => { + // 接收到消息 + }, + onCmdMessageReceived: (messages: ChatMessage[]): void => { + // 接收到透传消息 + } +} +``` + +## 接收自定义类型消息 + +你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +接收自定义消息与其他类型消息一致,详见 [接收文本消息](#接收文本消息)。 + +## 接收合并消息 + +为了方便消息互动,SDK 支持将多个消息合并在一起进行转发。 + +接收合并消息与接收普通消息的操作相同,详见 [接收文本消息](#接收文本消息)。 +- 对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 +- 合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 +- 对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: + - 若附件已存在,该方法会直接解析附件并返回原始消息列表。 + - 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 + +```typescript +ChatClient.getInstance().chatManager()?.downloadAndParseCombineMessage(message).then((result) => { + // 处理并展示消息列表 +}).catch((e: ChatError) => { + // 处理出错信息 +}); +``` \ No newline at end of file diff --git a/docs/document/harmonyos/message_send.md b/docs/document/harmonyos/message_send.md new file mode 100644 index 000000000..63dc7a6b1 --- /dev/null +++ b/docs/document/harmonyos/message_send.md @@ -0,0 +1,317 @@ +# 发送消息 + +环信即时通讯 IM HarmonyOS SDK 通过 [`ChatManager`](https://sdkdocs.easemob.com/apidoc/harmony/chat3.0/classes/ChatManager.ChatManager.html) 类和 [`ChatMessage`](https://sdkdocs.easemob.com/apidoc/harmony/chat3.0/classes/message_ChatMessage.ChatMessage.html) 类实现文本、图片、音频、视频和文件等类型的消息的发送。 + +- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要 [开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 +- 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 +关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 发送文本消息 + +1. 发送方调用 `ChatMessage#createTextSendMessage` 类构造一条消息。 + +默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 + +```typescript +// 创建一条文本消息,`content` 为消息文字内容。 +// `conversationId` 为消息接收方,单聊时为对端用户 ID、群聊时为群组 ID,聊天室时为聊天室 ID。 +let message = ChatMessage.createTextSendMessage(conversationId, content); +if (!message) { + return; +} +// 会话类型:单聊为 ChatType.Chat,群聊为 ChatType.GroupChat, ChatType.ChatRoom,默认为单聊。 +message.setChatType(ChatType.Chat); +// 发送消息。 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +2. 通过 `ChatManager#sendMessage` 将该消息发出。发送消息时可以设置 `ChatCallback` 的实例,获取消息发送状态。 + +```typescript +// 发送消息时可以设置 `ChatCallback` 的实例,获得消息发送的状态。可以在该回调中更新消息的显示状态。例如消息发送失败后的提示等等。 +let callback: ChatCallback = { + onSuccess: (): void => { + // 发送消息成功 + }, + onError: (code: number, error: string): void => { + // 发送消息失败 + }, + onProgress: (progress: number): void => { + // 附件消息附件的上传进度 + } +} +message.setMessageStatusCallback(callback); + // 发送消息。 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +## 发送附件消息 + +除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 + +附件消息的发送过程如下: + +1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器。 +2. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 + +自 1.7.0 版本开始,即时通讯 IM 支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户必须调用 SDK 的 `downloadAttachment` 方法下载消息附件。 + +### 发送语音消息 + +1. 发送语音消息前,在应用层录制语音文件。 +2. 发送方调用 `createVoiceSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)、语音文件的路径和语音时长创建语音消息,然后调用 `sendMessage` 方法发送消息。SDK 会将语音文件上传至环信服务器。 + +```typescript +// `filePathOrUri` 为语音文件的本地路径或者文件的 URI,`duration` 为语音时长(单位为秒)。 +let message = ChatMessage.createVoiceSendMessage(to, filePathOrUri, duration); +if (!message) { + return; +} +// 设置会话类型,即`ChatMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +message.setChatType(ChatType.GroupChat); +// 发送消息 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +### 发送图片消息 + +1. 发送方调用 `createImageSendMessage` 方法传入图片的本地资源标志符 URI、设置是否发送原图以及接收方的用户 ID (群聊或聊天室分别为群组 ID 或聊天室 ID)创建图片消息。 +2. 发送方调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 + +```typescript +// `imageFilePathOrUri` 为图片本地路径或者Uri。 +let message = ChatMessage.createImageSendMessage(toChatUsername, imageFilePathOrUri); +// 会话类型,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +message.setChatType(ChatType.GroupChat); +// 发送消息 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +### 发送 GIF 图片消息 + +- 自 HarmonyOS SDK 1.7.0 开始,支持发送 GIF 图片消息。 + +- GIF 图片缩略图的生成和下载与普通图片消息相同,详见 [发送和接收图片消息](#发送和接收图片消息)。 + +- GIF 图片消息是一种特殊的图片消息,与普通图片消息不同,**GIF 图片发送时不能压缩**。// TODO:这句话是 Android 的,合适吗? + +发送 GIF 图片消息的过程如下: + +- 发送方调用 `ChatMessage#createImageSendMessage` 方法构造 GIF 图片消息体。 +- 发送方调用 `ChatManager#sendMessage` 方法发送消息。 + +```typescript +// `imageUri` 为图片本地资源标志符 +let isGif = true; // 是否为 GIF 图片,默认为 false。 +let message = ChatMessage.createImageSendMessage(this.to, this.imageUri, isGif); +// 设置会话类型,即`ChatMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +// message.setChatType(ChatType.GroupChat); +// 发送消息 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +### 发送视频消息 + +1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 +2. 发送方调用 `ChatMessage#createVideoSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)、视频文件的本地路径、视频时长以及缩略图的本地存储路径。 +3. 发送方调用 `ChatManager#sendMessage` 方法发送消息。SDK 会将视频文件上传至消息服务器。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `createVideoSendMessage` 方法。 + +```typescript +// 在应用层获取视频首帧 +let thumbPath = this.getThumbPath(videoPath); +let message = ChatMessage.createVideoSendMessage(toChatUsername, videoPath, videoLength, thumbPath); +if (!message) { + return; +} +// 会话类型,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 +message.setChatType(ChatType.GroupChat); +// 发送消息 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +### 发送文件消息 + +1. 发送方调用 `ChatMessage#createFileSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)和文件的本地路径创建文件消息。 +2. 发送方调用 `sendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 + +```typescript +// `fileLocalPathOrUri` 为本地文件路径或者本地文件Uri。 +let message = ChatMessage.createFileSendMessage(toChatUsername, fileLocalPathOrUri); +if (!message) { + return; +} +// 如果是群聊,设置 `ChatType` 为 `GroupChat`,该参数默认是单聊(`Chat`)。 +message.setChatType(ChatType.GroupChat); +// 发送消息 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +## 发送位置消息 + +1. 发送方调用 `ChatMessage#createLocationSendMessage` 方法创建位置消息。 +2. 发送方调用 `ChatManager#sendMessage` 方法发送位置消息 + +发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 + +```typescript +// `latitude` 为纬度,`longitude` 为经度,`locationAddress` 为具体位置内容。 +let message = ChatMessage.createLocationSendMessage(toChatUsername, latitude, longitude, locationAddress); +if (!message) { + return; +} +// 如果是群聊,设置 `ChatType` 为 `GroupChat`,该参数默认是单聊(`Chat`)。 +message.setChatType(ChatType.GroupChat); +// 发送消息 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +## 发送透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +发送透传消息的过程如下: + +1. 发送方调用 `ChatMessage#createSendMessage` 方法创建透传消息。 +2. 发送方调用 `ChatManager#sendMessage` 方法发送透传消息。 + +```typescript +let action = "action1"; +// `action` 可以自定义。 +let cmdBody = new CmdMessageBody(action); +let toUsername = "test1"; +// 支持单聊、群聊和聊天室,默认为单聊。 +let cmdMsg = ChatMessage.createSendMessage(toUsername, cmdBody, ChatType.GroupChat); +if (!cmdMsg) { + return; +} +// 发送消息 +ChatClient.getInstance().chatManager()?.sendMessage(cmdMsg); +``` + +## 发送自定义类型消息 + +除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +1. 发送方调用 `ChatMessage#createSendMessage` 方法创建自定义消息。 +2. 发送方调用 `ChatManager#sendMessage` 方法发送自定义消息。 + +```typescript +// `event` 为需要传递的自定义消息事件,比如礼物消息,可以设置: +let event = "gift"; +let customBody = new CustomMessageBody(event); +// `params` 类型为 `Map`。 +customBody.setParams(params); +// 创建一条发送消息,`to` 指另一方环信用户 ID(或者群组 ID,聊天室 ID); +// 如果是群聊,设置 `ChatType` 为 `GroupChat`,该参数默认是单聊(`Chat`)。 +let customMessage = ChatMessage.createSendMessage(to, customBody, ChatType.GroupChat); +// 发送消息 +ChatClient.getInstance().chatManager()?.sendMessage(customMessage); +``` + +## 发送合并消息 + +为了方便消息互动,SDK 支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: + +1. 利用原始消息列表创建一条合并消息。 +2. 发送合并消息。 + +:::tip +对于转发合并消息,例如,用户 A 向 用户 B 发送了合并消息,用户 B 将该合并消息转发给用户 C,需要调用转发单条合并消息的 API。详见 [转发单条消息](message_forward.html#转发单条消息)。 +::: + +你可以调用 `createCombinedSendMessage` 方法创建一条合并消息,然后调用 `sendMessage` 方法发送该条消息。 + +创建合并消息时,需要设置以下参数: + +| 属性 | 类型 | 描述 | +| :-------------- | :-------------------- | :-------------------- | +| `title` | String | 合并消息的标题。 | +| `summary` | String | 合并消息的概要。 | +| `compatibleText` | String | 合并消息的兼容文本。
兼容文本起向下兼容不支持消息合并转发的版本的作用。当支持合并消息的 SDK 向不支持合并消息的低版本 SDK 发送消息时,低版本的 SDK 会将该属性解析为文本消息的消息内容。 | +| `messageIds` | Array | 合并消息的原始消息 ID 数组。该数组最多包含 300 个消息 ID。 | +| `to` | String | 消息接收方。该字段的设置取决于会话类型:
- 单聊:对方用户 ID;
- 群聊:群组 ID;
- 聊天室聊天:聊天室 ID。| + +:::tip +1. 合并转发支持嵌套,最多支持 10 层嵌套,每层最多 300 条消息。 +2. 不论 `ChatOptions#setAutoTransferMessageAttachments` 设置为 `false` 或 `true`,SDK 都会将合并消息附件上传到环信服务器。 +3. 合并消息不支持搜索。 +::: + +示例代码如下: + +```typescript +let title = "A和B的聊天记录"; +let summary = "A:这是A的消息内容\nB:这是B的消息内容"; +let compatibleText = "您当前的版本不支持该消息,请升级到最新版本"; +let message = ChatMessage.createCombinedSendMessage(title, {summary: summary, compatibleText: compatibleText, messageIds: ["msgId1", "msgId2"]}); +let messageCallback: ChatCallback = { + onSuccess: () => { + // 消息发送成功的处理逻辑 + }, + onError: (code: number, error: string) => { + // 消息发送失败的处理逻辑 + } +} +message.setMessageStatusCallback(messageCallback); +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +## 更多 + +### 聊天室消息优先级与消息丢弃逻辑 + +- **消息优先级**:对于聊天室消息,环信即时通讯提供消息分级功能,支持高、普通和低三种优先级,高优先级的消息会优先送达。你可以在创建消息时对指定消息类型或指定成员的消息设置为高优先级,确保这些消息优先送达。这种方式可以确保在聊天室内消息并发量较大或消息发送频率过高的情况下,服务器首先丢弃低优先级消息,将资源留给高优先级消息,确保重要消息(如打赏、公告等)优先送达,以此提升重要消息的可靠性。请注意,该功能并不保证高优先级消息必达。在聊天室内消息并发量过大的情况下,为保证用户实时互动的流畅性,即使是高优先级消息仍然会被丢弃。 + +- **消息丢弃逻辑**:对于单个聊天室,每秒发送的消息数量默认超过 20 条,则会触发消息丢弃逻辑,即首先丢弃低优先级的消息,优先保留高优先级的消息。若带有优先级的消息超过了 20 条/秒,则按照消息发送时间顺序处理,丢弃后发送的消息。 + +```typescript +let message = ChatMessage.createTextSendMessage(conversationId, content); +if (!message) { + return; +} +message.setChatType(ChatType.ChatRoom); +// 聊天室消息的优先级。如果不设置,默认值为 `PriorityNormal`,即“普通”优先级。 +message.setPriority(ChatroomMessagePriority.PriorityHigh); +sendMessage(message); +``` + +### 获取发送附件消息的进度 + +发送附件类型消息时,可以在 `onProgress` 回调中获取附件上传的进度,以百分比表示,示例代码如下: + +```typescript +// 发送消息时可以设置 `ChatCallback` 的实例,获得消息发送的状态。可以在该回调中更新消息的显示状态。例如,消息发送失败后的提示等等。 + let callback: ChatCallback = { + onSuccess: (): void => { + // 发送消息成功 + }, + onError: (code: number, error: string): void => { + // 发送消息失败 + }, + onProgress: (progress: number): void => { + // 消息发送的状态,这里只用于附件类型的消息。 + } +} +message.setMessageStatusCallback(callback); + // 发送消息。 +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +### 发送消息前的内容审核 + +[内容审核服务会关注消息 body 中指定字段的内容,不同类型的消息审核不同的字段](/product/moderation/moderation_mechanism.html),若创建消息时在这些字段中传入了很多业务信息,可能会影响审核效果。因此,创建消息时需要注意内容审核的字段不涉及业务信息,建议业务信息放在扩展字段中。 + diff --git a/docs/document/harmonyos/message_send_receive.md b/docs/document/harmonyos/message_send_receive.md deleted file mode 100644 index e7c2b625f..000000000 --- a/docs/document/harmonyos/message_send_receive.md +++ /dev/null @@ -1,601 +0,0 @@ -# 发送和接收消息 - -环信即时通讯 IM HarmonyOS SDK 通过 [`ChatManager`](https://sdkdocs.easemob.com/apidoc/harmony/chat3.0/classes/ChatManager.ChatManager.html) 类和 [`ChatMessage`](https://sdkdocs.easemob.com/apidoc/harmony/chat3.0/classes/message_ChatMessage.ChatMessage.html) 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 - -- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - -- 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 - -关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 - -## 前提条件 - -开始前,请确保满足以下条件: - -- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 -- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 - -## 发送和接收文本消息 - -1. 首先,利用 `ChatMessage` 类构造一条消息。 - -默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 - -```typescript -// 创建一条文本消息,`content` 为消息文字内容。 -// `conversationId` 为消息接收方,单聊时为对端用户 ID、群聊时为群组 ID,聊天室时为聊天室 ID。 -let message = ChatMessage.createTextSendMessage(conversationId, content); -if (!message) { - return; -} -// 会话类型:单聊为 ChatType.Chat,群聊为 ChatType.GroupChat, ChatType.ChatRoom,默认为单聊。 -message.setChatType(ChatType.Chat); -// 发送消息。 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -2. 通过 `ChatManager` 将该消息发出。发送消息时可以设置 `ChatCallback` 的实例,获取消息发送状态。 - -```typescript -// 发送消息时可以设置 `ChatCallback` 的实例,获得消息发送的状态。可以在该回调中更新消息的显示状态。例如消息发送失败后的提示等等。 -let callback: ChatCallback = { - onSuccess: (): void => { - // 发送消息成功 - }, - onError: (code: number, error: string): void => { - // 发送消息失败 - }, - onProgress: (progress: number): void => { - // 附件消息附件的上传进度 - } -} -message.setMessageStatusCallback(callback); - // 发送消息。 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -3. 你可以用注册监听 `ChatMessageListener` 接收消息。该 `ChatMessageListener` 可以多次添加,请记得在不需要的时候移除 `listener`。 - -在新消息到来时,你会收到 `onMessageReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。 - -对于聊天室消息,你可以通过消息的 `ChatMessage#isBroadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```typescript -let msgListener: ChatMessageListener = { - onMessageReceived: (messages: ChatMessage[]): void => { - // 收到消息,遍历消息队列,解析和显示。 - } -} -// 注册消息监听 -ChatClient.getInstance().chatManager()?.addMessageListener(msgListener); -// 解注册消息监听 -ChatClient.getInstance().chatManager()?.removeMessageListener(msgListener); -``` - -## 发送和接收附件消息 - -除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 - -附件消息的发送和接收过程如下: - -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器。 -2. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 -3. 获取附件的服务器地址和本地路径。 - -自 1.7.0 版本开始,即时通讯 IM 支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户必须调用 SDK 的 `downloadAttachment` 方法下载消息附件。 - -### 发送和接收语音消息 - -发送和接收语音消息的过程如下: - -1. 发送语音消息前,在应用层录制语音文件。 -2. 发送方调用 `createVoiceSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)、语音文件的路径和语音时长创建语音消息,然后调用 `sendMessage` 方法发送消息。SDK 会将语音文件上传至环信服务器。 - -```typescript -// `filePathOrUri` 为语音文件的本地路径或者文件的 URI,`duration` 为语音时长(单位为秒)。 -let message = ChatMessage.createVoiceSendMessage(to, filePathOrUri, duration); -if (!message) { - return; -} -// 设置会话类型,即`ChatMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -message.setChatType(ChatType.GroupChat); -// 发送消息 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -3. 接收方收到语音消息时,自动下载语音文件。 - -4. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),调用 `getRemoteUrl` 或 `getLocalPath` 方法获取语音文件的服务器地址或本地路径,从而获取语音文件。 - -```typescript -let voiceBody = message.getBody() as VoiceMessageBody; -// 获取语音文件在服务器的地址。 -let voiceRemoteUrl = voiceBody.getRemoteUrl(); -// 本地语音文件的本地路径。 -let voiceLocalPath = voiceBody.getLocalPath(); -``` - -### 发送和接收图片消息 - -发送和接收图片消息的流程如下: - -1. 发送方调用 `createImageSendMessage` 方法传入图片的本地资源标志符 URI、设置是否发送原图以及接收方的用户 ID (群聊或聊天室分别为群组 ID 或聊天室 ID)创建图片消息,然后调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 - -```typescript -// `imageFilePathOrUri` 为图片本地路径或者Uri。 -let message = ChatMessage.createImageSendMessage(toChatUsername, imageFilePathOrUri); -// 会话类型,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -message.setChatType(ChatType.GroupChat); -// 发送消息 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -2. 接收方收到图片消息,自动下载图片缩略图。 - -- 默认情况下,SDK 自动下载缩略图,即 `ChatOptions.setAutoDownloadThumbnail` 设置为 `true`。 -- 若设置为手动下载缩略图,即 `ChatOptions.setAutoDownloadThumbnail` 设置为 `false` ,需调用 `ChatClient.getInstance().chatManager()?.downloadThumbnail(message)` 下载。 - -3. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),调用 `downloadAttachment` 下载原图。 - -```typescript -let msgListener: ChatMessageListener = { - onMessageReceived: (messages: ChatMessage[]): void => { - messages.forEach( message => { - if (message.getType() === ContentType.IMAGE) { - let callback: ChatCallback = { - onSuccess: (): void => { - // 附件下载成功 - }, - onError: (code: number, error: string): void => { - // 附件下载失败 - }, - onProgress: (progress: number): void => { - // 附件下载进度 - } - } - message.setMessageStatusCallback(callback); - // 下载附件 - ChatClient.getInstance().chatManager()?.downloadAttachment(message); - } - }) - } -} -``` - -4. 获取图片消息的缩略图和附件。 - -```typescript -let imgBody = message.getBody() as ImageMessageBody; -// 从服务器端获取图片文件。 -let imgRemoteUrl = imgBody.getRemoteUrl(); -// 从服务器端获取图片缩略图。 -let thumbnailUrl = imgBody.getThumbnailRemoteUrl(); -// 从本地获取图片文件。 -let imgLocalPath = imgBody.getLocalPath(); -// 从本地获取图片缩略图。 -let thumbnailLocalPath = imgBody.getThumbnailLocalPath(); -``` - -### 发送和接收 GIF 图片消息 - -自 HarmonyOS SDK 1.7.0 开始,支持发送和接收 GIF 图片消息。 - -GIF 图片缩略图的生成和下载与普通图片消息相同,详见 [发送和接收图片消息](#发送和接收图片消息)。 - -#### 发送 GIF 图片消息 - -你可以通过以下方式构造 GIF 图片消息: - -- 使用 `ChatMessage#createImageSendMessage` 方法构造 GIF 图片消息体。 - -```typescript -// `imageUri` 为图片本地资源标志符 -let isGif = true; // 是否为 GIF 图片,默认为 false。 -let message = ChatMessage.createImageSendMessage(this.to, this.imageUri, isGif); -// 设置会话类型,即`ChatMessage` 类的 `ChatType` 属性,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -// message.setChatType(ChatType.GroupChat); -// 发送消息 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -#### 接收 GIF 图片消息 - -与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onMessageReceived` 回调方法。接收方判断为图片消息后,读取消息体的 `isGif` 属性,若值是 `YES`, 则为 GIF 图片消息。 - -```typescript -ChatClient.getInstance().chatManager()?.addMessageListener({ - onMessageReceived: (messages) => { - messages.forEach(message => { - if (message.getType() === ContentType.IMAGE) { - let body = message.getBody() as ImageMessageBody; - if (body.isGif()) { - // 根据业务情况处理gif message, 例如下载展示该消息 - } - } - }) - } -}); -``` - -### 发送和接收视频消息 - -发送和接收视频消息的流程如下: - -1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 - -2. 发送方调用 `createVideoSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)、视频文件的本地路径、视频时长以及缩略图的本地存储路径,然后调用 `sendMessage` 方法发送消息。SDK 会将视频文件上传至消息服务器。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `createVideoSendMessage` 方法。 - -```typescript -// 在应用层获取视频首帧 -let thumbPath = this.getThumbPath(videoPath); -let message = ChatMessage.createVideoSendMessage(toChatUsername, videoPath, videoLength, thumbPath); -if (!message) { - return; -} -// 会话类型,包含 `Chat`、`GroupChat` 和 `ChatRoom`,表示单聊、群聊或聊天室,默认为单聊。 -message.setChatType(ChatType.GroupChat); -// 发送消息 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -3. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#发送和接收图片消息)。 - -4. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),可以调用 `ChatClient.getInstance().chatManager()?.downloadAttachment(message)` 方法下载视频原文件。 - -```typescript -let msgListener: ChatMessageListener = { - onMessageReceived: (messages: ChatMessage[]): void => { - messages.forEach( message => { - if (message.getType() === ContentType.VIDEO) { - let callback: ChatCallback = { - onSuccess: (): void => { - // 附件下载成功 - }, - onError: (code: number, error: string): void => { - // 附件下载失败 - }, - onProgress: (progress: number): void => { - // 附件下载进度 - } - } - message.setMessageStatusCallback(callback); - // 下载附件 - ChatClient.getInstance().chatManager()?.downloadAttachment(message); - } - }) - } -} -``` - -5. 获取视频缩略图和视频原文件。 - -```typescript -let body = message.getBody() as VideoMessageBody; -// 从服务器端获取视频文件。 -let imgRemoteUrl = body.getRemoteUrl(); -// 从服务器获取视频缩略图文件。 -let thumbnailUrl = body.getThumbnailRemoteUrl(); -// 从本地获取视频文件文件。 -let localPath = body.getLocalPath(); -// 从本地获取视频缩略图文件。 -let localThumbPath = body.getThumbnailLocalPath(); -``` - -### 发送和接收文件消息 - -发送和接收文件消息的流程如下: - -1. 发送方调用 `createFileSendMessage` 方法传入接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)和文件的本地路径创建文件消息,然后调用 `sendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 - -```typescript -// `fileLocalPathOrUri` 为本地文件路径或者本地文件Uri。 -let message = ChatMessage.createFileSendMessage(toChatUsername, fileLocalPathOrUri); -if (!message) { - return; -} -// 如果是群聊,设置 `ChatType` 为 `GroupChat`,该参数默认是单聊(`Chat`)。 -message.setChatType(ChatType.GroupChat); -// 发送消息 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -2. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),调用 `downloadAttachment` 方法下载文件。 - -```typescript -/** - * 下载文件。 - */ -private downloadFile(message: ChatMessage) { - let callback: ChatCallback = { - onSuccess: (): void => { - // 附件下载成功 - }, - onError: (code: number, error: string): void => { - // 附件下载失败 - }, - onProgress: (progress: number): void => { - // 附件下载进度 - } - } - message.setMessageStatusCallback(callback); - // 下载附件 - ChatClient.getInstance().chatManager()?.downloadAttachment(message); -} -``` - -3. 调用以下方法从服务器或本地获取文件附件: - -```typescript -let fileMessageBody = message.getBody() as FileMessageBody; -// 从服务器获取文件。 -let fileRemoteUrl = fileMessageBody.getRemoteUrl(); -// 从本地获取文件。 -let fileLocalPath = fileMessageBody.getLocalPath(); -``` - -## 发送和接收位置消息 - -1. 创建和发送位置消息。 - -发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 - -```typescript -// `latitude` 为纬度,`longitude` 为经度,`locationAddress` 为具体位置内容。 -let message = ChatMessage.createLocationSendMessage(toChatUsername, latitude, longitude, locationAddress); -if (!message) { - return; -} -// 如果是群聊,设置 `ChatType` 为 `GroupChat`,该参数默认是单聊(`Chat`)。 -message.setChatType(ChatType.GroupChat); -// 发送消息 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -2. 接收位置消息与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - - 接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 - -## 发送和接收透传消息 - -透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 - -具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 - -:::tip -- 透传消息发送后,不支持撤回。 -- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 -::: - -1. 创建和发送透传消息。 - -```typescript -let action = "action1"; -// `action` 可以自定义。 -let cmdBody = new CmdMessageBody(action); -let toUsername = "test1"; -// 支持单聊、群聊和聊天室,默认为单聊。 -let cmdMsg = ChatMessage.createSendMessage(toUsername, cmdBody, ChatType.GroupChat); -if (!cmdMsg) { - return; -} -// 发送消息 -ChatClient.getInstance().chatManager()?.sendMessage(cmdMsg); -``` - -2. 接收方通过 `onMessageReceived` 和 `onCmdMessageReceived` 回调接收透传消息,方便用户进行不同的处理。 - -```typescript -let msgListener: ChatMessageListener = { - onMessageReceived: (messages: ChatMessage[]): void => { - // 接收到消息 - }, - onCmdMessageReceived: (messages: ChatMessage[]): void => { - // 接收到透传消息 - } -} -``` - -## 发送自定义类型消息 - -除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 - -1. 创建和发送自定义类型消息。 - -```typescript -// `event` 为需要传递的自定义消息事件,比如礼物消息,可以设置: -let event = "gift"; -let customBody = new CustomMessageBody(event); -// `params` 类型为 `Map`。 -customBody.setParams(params); -// 创建一条发送消息,`to` 指另一方环信用户 ID(或者群组 ID,聊天室 ID); -// 如果是群聊,设置 `ChatType` 为 `GroupChat`,该参数默认是单聊(`Chat`)。 -let customMessage = ChatMessage.createSendMessage(to, customBody, ChatType.GroupChat); -// 发送消息 -ChatClient.getInstance().chatManager()?.sendMessage(customMessage); -``` - -2. 接收自定义消息与其他类型消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -## 发送和接收合并消息 - -为了方便消息互动,SDK 支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: - -1. 利用原始消息列表创建一条合并消息。 -2. 发送合并消息。 -3. 对端收到合并消息后进行解析,获取原始消息列表。合并消息转发后在接收端显示该消息的标题和预览图。 - -:::tip -对于转发合并消息,例如,用户 A 向 用户 B 发送了合并消息,用户 B 将该合并消息转发给用户 C,需要调用转发单条合并消息的 API。详见[转发单条消息](message_forward.html#转发单条消息)。 -::: - -#### 创建和发送合并消息 - -你可以调用 `createCombinedSendMessage` 方法创建一条合并消息,然后调用 `sendMessage` 方法发送该条消息。 - -创建合并消息时,需要设置以下参数: - -| 属性 | 类型 | 描述 | -| :-------------- | :-------------------- | :-------------------- | -| `title` | String | 合并消息的标题。 | -| `summary` | String | 合并消息的概要。 | -| `compatibleText` | String | 合并消息的兼容文本。
兼容文本起向下兼容不支持消息合并转发的版本的作用。当支持合并消息的 SDK 向不支持合并消息的低版本 SDK 发送消息时,低版本的 SDK 会将该属性解析为文本消息的消息内容。 | -| `messageIds` | Array | 合并消息的原始消息 ID 数组。该数组最多包含 300 个消息 ID。 | -| `to` | String | 消息接收方。该字段的设置取决于会话类型:
- 单聊:对方用户 ID;
- 群聊:群组 ID;
- 聊天室聊天:聊天室 ID。| - -:::tip -1. 合并转发支持嵌套,最多支持 10 层嵌套,每层最多 300 条消息。 -2. 不论 `ChatOptions#setAutoTransferMessageAttachments` 设置为 `false` 或 `true`,SDK 都会将合并消息附件上传到环信服务器。 -3. 合并消息不支持搜索。 -::: - -示例代码如下: - -```typescript -let title = "A和B的聊天记录"; -let summary = "A:这是A的消息内容\nB:这是B的消息内容"; -let compatibleText = "您当前的版本不支持该消息,请升级到最新版本"; -let message = ChatMessage.createCombinedSendMessage(title, {summary: summary, compatibleText: compatibleText, messageIds: ["msgId1", "msgId2"]}); -let messageCallback: ChatCallback = { - onSuccess: () => { - // 消息发送成功的处理逻辑 - }, - onError: (code: number, error: string) => { - // 消息发送失败的处理逻辑 - } -} -message.setMessageStatusCallback(messageCallback); -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 - -对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: - -- 若附件已存在,该方法会直接解析附件并返回原始消息列表。 -- 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 - -```typescript -ChatClient.getInstance().chatManager()?.downloadAndParseCombineMessage(message).then((result) => { - // 处理并展示消息列表 -}).catch((e: ChatError) => { - // 处理出错信息 -}); -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: - -1. 创建一条群组或聊天室消息。 -2. 设置消息的接收方。 -3. 发送定向消息。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```typescript -// 创建一条文本消息。 -let message = ChatMessage.createTextSendMessage(groupId, content); -// 会话类型:群组和聊天室聊天,分别为 `GroupChat` 和 `ChatRoom`。 -message.setChatType(ChatMessage.ChatType.GroupChat); -let receives = ["张三", "李四"]; -// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`,则消息发送给群组或聊天室的所有成员。 -message.setReceiverList(receives); -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -接收群定向消息与接收普通消息的操作相同,详见[接收消息](#发送和接收文本消息)。 - -## 使用消息扩展字段 - -当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 - -```typescript -let message = ChatMessage.createTxtSendMessage(toChatUsername, content); -if (!message) { - return; -} -// 增加自定义属性。 -let attributes = new Map(); -attributes.set("attribute1", "value"); -attributes.set("attribute2", true); -attributes.set("attribute3", 123); -attributes.set("attribute4", { - nickname: 'Nickname', - avatarUrl: 'https://www.easemob.com/example.png', - gender: Gender.MALE -} as UserInfo); -message.setExt(attributes); -ChatClient.getInstance().chatManager()?.sendMessage(message); -// 获取自定义属性 -let exts = message.ext(); -let attr1 = exts.get("attribute1") as string; -let attr2 = exts.get("attribute2") as boolean; -let attr3 = exts.get("attribute3") as boolean; -let attr4 = exts.get("attribute4") as UserInfo; -``` - -:::tip -1.6.0 版本 `ChatMessage.setExt` 方法支持 object 数据类型,用于设置 JSON 结构的扩展信息。 -::: - -## 更多 - -### 聊天室消息优先级与消息丢弃逻辑 - -- **消息优先级**:对于聊天室消息,环信即时通讯提供消息分级功能,支持高、普通和低三种优先级,高优先级的消息会优先送达。你可以在创建消息时对指定消息类型或指定成员的消息设置为高优先级,确保这些消息优先送达。这种方式可以确保在聊天室内消息并发量较大或消息发送频率过高的情况下,服务器首先丢弃低优先级消息,将资源留给高优先级消息,确保重要消息(如打赏、公告等)优先送达,以此提升重要消息的可靠性。请注意,该功能并不保证高优先级消息必达。在聊天室内消息并发量过大的情况下,为保证用户实时互动的流畅性,即使是高优先级消息仍然会被丢弃。 - -- **消息丢弃逻辑**:对于单个聊天室,每秒发送的消息数量默认超过 20 条,则会触发消息丢弃逻辑,即首先丢弃低优先级的消息,优先保留高优先级的消息。若带有优先级的消息超过了 20 条/秒,则按照消息发送时间顺序处理,丢弃后发送的消息。 - -```typescript -let message = ChatMessage.createTextSendMessage(conversationId, content); -if (!message) { - return; -} -message.setChatType(ChatType.ChatRoom); -// 聊天室消息的优先级。如果不设置,默认值为 `PriorityNormal`,即“普通”优先级。 -message.setPriority(ChatroomMessagePriority.PriorityHigh); -sendMessage(message); -``` - -### 获取发送附件消息的进度 - -发送附件类型消息时,可以在 `onProgress` 回调中获取附件上传的进度,以百分比表示,示例代码如下: - -```typescript -// 发送消息时可以设置 `ChatCallback` 的实例,获得消息发送的状态。可以在该回调中更新消息的显示状态。例如,消息发送失败后的提示等等。 - let callback: ChatCallback = { - onSuccess: (): void => { - // 发送消息成功 - }, - onError: (code: number, error: string): void => { - // 发送消息失败 - }, - onProgress: (progress: number): void => { - // 消息发送的状态,这里只用于附件类型的消息。 - } -} -message.setMessageStatusCallback(callback); - // 发送消息。 -ChatClient.getInstance().chatManager()?.sendMessage(message); -``` - -### 发送消息前的内容审核 - -[内容审核服务会关注消息 body 中指定字段的内容,不同类型的消息审核不同的字段](/product/moderation/moderation_mechanism.html),若创建消息时在这些字段中传入了很多业务信息,可能会影响审核效果。因此,创建消息时需要注意内容审核的字段不涉及业务信息,建议业务信息放在扩展字段中。 - diff --git a/docs/document/harmonyos/message_target.md b/docs/document/harmonyos/message_target.md new file mode 100644 index 000000000..14868b4aa --- /dev/null +++ b/docs/document/harmonyos/message_target.md @@ -0,0 +1,32 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 + +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: + +1. 创建一条群组或聊天室消息。 +2. 设置消息的接收方。 +3. 发送定向消息。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```typescript +// 创建一条文本消息。 +let message = ChatMessage.createTextSendMessage(groupId, content); +// 会话类型:群组和聊天室聊天,分别为 `GroupChat` 和 `ChatRoom`。 +message.setChatType(ChatMessage.ChatType.GroupChat); +let receives = ["张三", "李四"]; +// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`,则消息发送给群组或聊天室的所有成员。 +message.setReceiverList(receives); +ChatClient.getInstance().chatManager()?.sendMessage(message); +``` + +接收群定向消息与接收普通消息的操作相同,详见[接收消息](#发送和接收文本消息)。 \ No newline at end of file diff --git a/docs/document/ios/message_extension.md b/docs/document/ios/message_extension.md new file mode 100644 index 000000000..86311716c --- /dev/null +++ b/docs/document/ios/message_extension.md @@ -0,0 +1,22 @@ +# 消息扩展 + +当 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"]; } + } +``` \ No newline at end of file diff --git a/docs/document/ios/message_receive.md b/docs/document/ios/message_receive.md new file mode 100644 index 000000000..154eb768f --- /dev/null +++ b/docs/document/ios/message_receive.md @@ -0,0 +1,223 @@ +# 接收消息 + + + +环信即时通讯 IM iOS SDK 通过 `EMChatManagerDelegate` 类实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +- 你可以用注册监听 `EMChatManagerDelegate` 接收消息。该 `EMChatManagerDelegate` 可以多次添加,请记得在不需要的时候移除 `Delegate`,如在 `ViewController` `dealloc()` 时。 +- 在新消息到来时,你会收到 `messagesDidReceive` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `EMOptions#includeSendMessageInMessageListener` 开关,则该回调中会返回发送成功的消息。 +- 对于聊天室消息,你可以通过消息的 `EMChatMessage#broadcast` 属性判断该消息是否为 [通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```objectivec +// 添加代理。 +[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil]; + +// 收到消息回调。 + +- (void)messagesDidReceive:(NSArray *)aMessages + { + // 收到消息,遍历消息列表。 + for (EMChatMessage *message in aMessages) { + // 消息解析和展示。 + } + } + +// 移除代理。 + +- (void)dealloc + { + [[EMClient sharedClient].chatManager removeDelegate:self]; + } +``` + +## 接收附件消息 + +除文本消息外,SDK 还支持接收附件类型消息,包括语音、图片、视频和文件消息。 + +附件消息的接收过程如下: + +1. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 +2. 获取附件的服务器地址和本地路径。 + +自 ISO SDK 4.14.0 版本开始,支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户必须调用 SDK 的 API `downloadMessageAttachment` 下载消息附件。 + +### 接收语音消息 + +1. 接收方收到语音消息时,自动下载语音文件。 + +2. 接收方收到 [messagesDidReceive 回调](#发送和接收文本消息),调用 `remotePath` 或 `localPath` 方法获取语音文件的服务器地址或本地路径,从而获取语音文件。 + +```objectivec +EMVoiceMessageBody *voiceBody = (EMVoiceMessageBody *)message.body; +// 获取语音文件在服务器的地址。 +NSString *voiceRemotePath = voiceBody.remotePath; +// 本地语音文件的资源路径。 +NSString *voiceLocalPath = voiceBody.localPath; +``` + +### 接收图片消息 + +1. 接收方收到图片消息,自动下载图片缩略图。 + +- 默认情况下,SDK 自动下载缩略图,即 `[EMClient sharedClient].options.isAutoDownloadThumbnail;` 为 `YES`。 +- 若设置为手动下载缩略图,即 `[EMClient sharedClient].options.isAutoDownloadThumbnail(NO);`,需调用 `[[EMClient sharedClient].chatManager downloadMessageThumbnail:message progress:nil completion:nil];` 下载。 + +2. 接收方收到 [messagesDidReceive 回调](#发送和接收文本消息),调用 `downloadMessageAttachment` 下载原图。 + +下载完成后,在回调里调用相应消息 `body` 的 `thumbnailLocalPath` 获取缩略图路径。 + +```objectivec +EMImageMessageBody *imageBody = (EMImageMessageBody *)message.body; +// 图片文件的本地缩略图资源路径。 +NSString *thumbnailLocalPath = imageBody.thumbnailLocalPath; +``` + +3. 获取图片消息的附件。 + +```objectivec +[[EMClient sharedClient].chatManager downloadMessageAttachment:message progress:nil completion:^(EMChatMessage *message, EMError *error) { + if (!error) { + EMImageMessageBody *imageBody = (EMImageMessageBody *)message.body; + NSString *localPath = imageBody.localPath; + } + }]; +``` + +### 接收 GIF 图片消息 + +自 iOS SDK 4.14.0 开始,支持接收 GIF 图片消息。 + +图片缩略图的下载与普通图片消息相同,详见 [接收图片消息](#接收图片消息)。 + +与普通消息相同,接收 GIF 图片消息时,接收方会收到 `messagesDidReceive` 回调方法。接收方判断为图片消息后,读取消息体的 `isGif` 属性,若值是 `YES`, 则为 GIF 图片消息。 + +```objectivec +- (void)messagesDidReceive:(NSArray *)aMessages +{ + // 收到消息,遍历消息列表。 + for (EMChatMessage *message in aMessages) { + // 消息解析和展示。 + if (message.body.type == EMMessageBodyTypeImage) { + EMImageMessageBody *body = (EMImageMessageBody *)message.body; + if (body.isGif) { + // 是 GIF 图片消息 + } + } + } +} +``` + +### 接收视频消息 + +1. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#接收图片消息)。 +2. 接收方收到 [messagesDidReceive 回调](#接收文本消息),可以调用 `downloadMessageAttachment` 方法下载视频原文件。 +3. 获取视频缩略图和视频原文件。 + +```objectivec +// 发送成功后,获取视频消息缩略图及附件。 +EMVideoMessageBody *body = (EMVideoMessageBody *)message.body; +// 从服务器端获取视频文件的地址。 +NSString *remotePath = body.remotePath; +// 从服务器端获取视频缩略图。 +NSString *thumbnailPath = body.thumbnailRemotePath; +// 从本地获取视频文件。 +NSString *localPath = body.localPath; +// 从本地获取视频缩略图。 +NSString *thumbnailLocalPath = body.thumbnailLocalPath; +``` + +### 接收文件消息 + +1. 接收方收到 [messagesDidReceive 回调](#发送和接收文本消息),调用 `downloadMessageAttachment` 方法下载文件。 + +```objectivec +[[EMClient sharedClient].chatManager downloadMessageAttachment:message progress:nil completion:^(EMChatMessage *message, EMError *error) { + if (!error) { + // 附件下载成功 + } + }]; +``` + +2. 调用以下方法从服务器或本地获取文件附件: + +```objectivec +EMFileMessageBody *body = (EMFileMessageBody *)message.body; +// 从服务器端获取文件路径。 +NSString *remotePath = body.remotePath; +// 从本地获取文件路径。 +NSString *localPath = body.localPath; +``` + +## 接收位置消息 + +接收位置消息与文本消息一致,详见[接收文本消息](#接收文本消息)。 + + 接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +## 接收透传消息 + +可将透传消息理解为一条指令,通过发送这条指令给对方,通知对方要执行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 `action` 为内部保留字段,注意不要使用。 + +透传消息适用于更新头像、更新昵称等场景。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +接收方通过 `cmdMessagesDidReceive` 回调接收透传消息,方便用户进行不同的处理。 + +```objectivec +// 收到透传消息。 +- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages{ + for (EMChatMessage *message in aCmdMessages) { + EMCmdMessageBody *body = (EMCmdMessageBody *)message.body; + // 进行透传消息 body 解析。 + } + } +``` + +## 接收自定义类型消息 + +除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +接收自定义消息与其他类型消息一致,详见 [接收文本消息](#接收文本消息)。 + +## 接收合并消息 + +为了方便消息互动,即时通讯 IM 自 4.1.0 版本开始支持将多个消息合并在一起进行转发。 + +接收合并消息与接收普通消息的操作相同,详见 [接收消息](#接收文本消息)。 + +- 对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 +- 合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 +- 对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: + - 若附件已存在,该方法会直接解析附件并返回原始消息列表。 + - 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 + +```objectivec +- (void)messagesDidReceive:(NSArray *)aMessages +{ + + for (EMChatMessage* msg in aMessages) { + if (msg.body.type == EMMessageBodyTypeCombine) { + // 合并消息类型,解析合并消息 + [EMClient.sharedClient.chatManager downloadAndParseCombineMessage:msg completion:^(NSArray * _Nullable messages, EMError * _Nullable error) { + + }]; + } + } +} +``` + diff --git a/docs/document/ios/message_send_receive.md b/docs/document/ios/message_send.md similarity index 52% rename from docs/document/ios/message_send_receive.md rename to docs/document/ios/message_send.md index c1b215ca8..8ad590c4c 100644 --- a/docs/document/ios/message_send_receive.md +++ b/docs/document/ios/message_send.md @@ -1,14 +1,12 @@ -# 发送和接收消息 +# 发送消息 -环信即时通讯 IM iOS SDK 通过 `ChatManager` 类和 `EMChatMessage` 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 - -- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 +环信即时通讯 IM iOS SDK 通过 `ChatManager` 类和 `EMChatMessage` 类实现文本、图片、音频、视频和文件等类型的消息的发送。 +- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要 [开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 - -关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 +- 关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的相关文档。 ## 前提条件 @@ -17,9 +15,9 @@ - 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 - 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -## 发送和接收文本消息 +## 发送文本消息 -1. 你可以利用 `EMChatMessage` 类构造一条消息,然后通过 `ChatManager` 将该消息发出。 +你可以利用 `EMChatMessage` 类构造一条消息,然后通过 `ChatManager` 将该消息发出。 默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `EMErrorMessageCurrentLimiting`。示例代码如下: @@ -40,52 +38,18 @@ message.chatType = EMChatTypeChatRoom; ``` -2. 你可以用注册监听 `EMChatManagerDelegate` 接收消息。该 `EMChatManagerDelegate` 可以多次添加,请记得在不需要的时候移除 `Delegate`,如在 `ViewController` `dealloc()` 时。 - -在新消息到来时,你会收到 `messagesDidReceive` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `EMOptions#includeSendMessageInMessageListener` 开关,则该回调中会返回发送成功的消息。 - -对于聊天室消息,你可以通过消息的 `EMChatMessage#broadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```objectivec -// 添加代理。 -[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil]; - -// 收到消息回调。 - -- (void)messagesDidReceive:(NSArray *)aMessages - { - // 收到消息,遍历消息列表。 - for (EMChatMessage *message in aMessages) { - // 消息解析和展示。 - } - } - -// 移除代理。 - -- (void)dealloc - { - [[EMClient sharedClient].chatManager removeDelegate:self]; - } -``` - -## 发送和接收附件消息 +## 发送附件消息 除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 -附件消息的发送和接收过程如下: +发送附件消息分为以下两步: -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器。 -2. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `downloadAttachment` 方法。 -3. 获取附件的服务器地址和本地路径。 +1. 创建和发送附件类型消息。 +2. SDK 将附件上传到环信服务器。 -自 ISO SDK 4.14.0 版本开始,支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户必须调用 SDK 的 API `downloadMessageAttachment` 下载消息附件。 +### 发送语音消息 -### 发送和接收语音消息 - -发送和接收语音消息的过程如下: - -1. 发送语音消息前,在应用层录制语音文件。 - +1. 发送语音消息前,在应用层录制语音文件。 2. 发送方调用 `initWithLocalPath` 和 `initWithConversationID` 方法传入语音文件的 URI、语音时长和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建语音消息,然后调用 `sendMessage` 方法发送消息。SDK 会将文件上传至环信服务器。 ```objectivec @@ -98,23 +62,10 @@ message.chatType = EMChatTypeGroupChat; [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; ``` -3. 接收方收到语音消息时,自动下载语音文件。 +### 发送图片消息 -4. 接收方收到 [messagesDidReceive 回调](#发送和接收文本消息),调用 `remotePath` 或 `localPath` 方法获取语音文件的服务器地址或本地路径,从而获取语音文件。 - -```objectivec -EMVoiceMessageBody *voiceBody = (EMVoiceMessageBody *)message.body; -// 获取语音文件在服务器的地址。 -NSString *voiceRemotePath = voiceBody.remotePath; -// 本地语音文件的资源路径。 -NSString *voiceLocalPath = voiceBody.localPath; -``` - -### 发送和接收图片消息 - -发送和接收图片消息的流程如下: - -1. 发送方调用 `initWithData` 和 `initWithConversationID` 方法传入图片的本地资源标志符 URI、设置是否发送原图以及接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建图片消息,然后调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 +1. 发送方调用 `initWithData` 和 `initWithConversationID` 方法传入图片的本地资源标志符 URI、设置是否发送原图以及接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建图片消息。 +2. 发送方调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 ```objectivec // `imageData` 为图片本地资源,`displayName` 为附件的显示名称。 @@ -140,47 +91,17 @@ NSString *localPath = body.localPath; NSString *thumbnailLocalPath = body.thumbnailLocalPath; ``` -2. 接收方收到图片消息,自动下载图片缩略图。 - -- 默认情况下,SDK 自动下载缩略图,即 `[EMClient sharedClient].options.isAutoDownloadThumbnail;` 为 `YES`。 -- 若设置为手动下载缩略图,即 `[EMClient sharedClient].options.isAutoDownloadThumbnail(NO);`,需调用 `[[EMClient sharedClient].chatManager downloadMessageThumbnail:message progress:nil completion:nil];` 下载。 - -3. 接收方收到 [messagesDidReceive 回调](#发送和接收文本消息),调用 `downloadMessageAttachment` 下载原图。 +### 发送 GIF 图片消息 -下载完成后,在回调里调用相应消息 `body` 的 `thumbnailLocalPath` 获取缩略图路径。 +- 自 iOS SDK 4.14.0 开始,支持发送 GIF 图片消息。 +- GIF 图片消息是一种特殊的图片消息,与普通图片消息不同,**GIF 图片发送时不能压缩**。 +- 图片缩略图的生成与普通图片消息相同,详见 [发送图片消息](#发送图片消息)。 -```objectivec -EMImageMessageBody *imageBody = (EMImageMessageBody *)message.body; -// 图片文件的本地缩略图资源路径。 -NSString *thumbnailLocalPath = imageBody.thumbnailLocalPath; -``` +发送 GIF 图片消息的过程如下: -4. 获取图片消息的附件。 - -```objectivec -[[EMClient sharedClient].chatManager downloadMessageAttachment:message progress:nil completion:^(EMChatMessage *message, EMError *error) { - if (!error) { - EMImageMessageBody *imageBody = (EMImageMessageBody *)message.body; - NSString *localPath = imageBody.localPath; - } - }]; -``` - -### 发送和接收 GIF 图片消息 - -自 iOS SDK 4.14.0 开始,支持发送和接收 GIF 图片消息。 - -GIF 图片消息是一种特殊的图片消息,与普通图片消息不同,**GIF 图片发送时不能压缩**。 - -图片缩略图的生成和下载与普通图片消息相同,详见 [发送和接收图片消息](#发送和接收图片消息)。 - -#### 发送 GIF 图片消息 - -你可以通过以下两种方式构造 GIF 图片消息: - -- 构造 `EMImageMessageBody` 后,设置 `isGif` 为 `true`。 - -- 使用 `EMImageMessageBody#initWithGifFilePath:displayName` 方法构造图片消息体。 +1. 构造 `EMImageMessageBody` 后,设置 `isGif` 为 `true`。 +2. 使用 `EMImageMessageBody#initWithGifFilePath:displayName` 方法构造图片消息体。 +3. 调用 `ChatManager#sendMessage` 方法发送消息。 ```objectivec //使用 EMImageMessageBody @@ -197,33 +118,11 @@ EMChatMessage *message = [[EMChatMessage alloc] initWithConversationID:toChatUse [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; ``` -#### 接收 GIF 图片消息 - -与普通消息相同,接收 GIF 图片消息时,接收方会收到 `messagesDidReceive` 回调方法。接收方判断为图片消息后,读取消息体的 `isGif` 属性,若值是 `YES`, 则为 GIF 图片消息。 - -```objectivec -- (void)messagesDidReceive:(NSArray *)aMessages -{ - // 收到消息,遍历消息列表。 - for (EMChatMessage *message in aMessages) { - // 消息解析和展示。 - if (message.body.type == EMMessageBodyTypeImage) { - EMImageMessageBody *body = (EMImageMessageBody *)message.body; - if (body.isGif) { - // 是 GIF 图片消息 - } - } - } -} -``` - -### 发送和接收视频消息 - -发送和接收视频消息的流程如下: +### 发送视频消息 1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 - -2. 发送方调用 `initWithLocalPath` 方法传入视频文件的本地资源标志符、消息的显示名称和视频时长,构建视频消息体。然后,调用 `initWithConversationID` 方法传入会话 ID 和视频消息体,构建视频消息。最后,调用 `sendMessage` 方法发送消息。SDK 会将视频文件上传至环信消息服务器,自动将视频的首帧作为视频缩略图。 +2. 发送方调用 `initWithLocalPath` 方法传入视频文件的本地资源标志符、消息的显示名称和视频时长,构建视频消息体。然后,调用 `initWithConversationID` 方法传入会话 ID 和视频消息体,构建视频消息。最后, +3. 发送方调用 `sendMessage` 方法发送消息。SDK 会将视频文件上传至环信消息服务器,自动将视频的首帧作为视频缩略图。 ```objectivec // `localPath` 为本地资源路径,`displayName` 为视频的显示名称。 @@ -237,30 +136,10 @@ message.chatType = EMChatTypeGroupChat; [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; ``` -3. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#发送和接收图片消息)。 - -4. 接收方收到 [messagesDidReceive 回调](#发送和接收文本消息),可以调用 `downloadMessageAttachment` 方法下载视频原文件。 - -5. 获取视频缩略图和视频原文件。 - -```objectivec -// 发送成功后,获取视频消息缩略图及附件。 -EMVideoMessageBody *body = (EMVideoMessageBody *)message.body; -// 从服务器端获取视频文件的地址。 -NSString *remotePath = body.remotePath; -// 从服务器端获取视频缩略图。 -NSString *thumbnailPath = body.thumbnailRemotePath; -// 从本地获取视频文件。 -NSString *localPath = body.localPath; -// 从本地获取视频缩略图。 -NSString *thumbnailLocalPath = body.thumbnailLocalPath; -``` - -### 发送和接收文件消息 +### 发送文件消息 -发送和接收文件消息的流程如下: - -1. 发送方调用 `initWithData` 和 `initWithConversationID` 方法传入文件的本地资源标志符和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建文件消息,然后调用 `sendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 +1. 发送方调用 `initWithData` 和 `initWithConversationID` 方法传入文件的本地资源标志符和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建文件消息。 +2. 发送方调用 `sendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 ```objectivec // `fileData` 为本地资源,`fileName` 为附件的显示名称。 @@ -272,29 +151,10 @@ message.chatType = EMChatTypeGroupChat; [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; ``` -2. 接收方收到 [messagesDidReceive 回调](#发送和接收文本消息),调用 `downloadMessageAttachment` 方法下载文件。 - -```objectivec -[[EMClient sharedClient].chatManager downloadMessageAttachment:message progress:nil completion:^(EMChatMessage *message, EMError *error) { - if (!error) { - // 附件下载成功 - } - }]; -``` - -3. 调用以下方法从服务器或本地获取文件附件: +## 发送位置消息 -```objectivec -EMFileMessageBody *body = (EMFileMessageBody *)message.body; -// 从服务器端获取文件路径。 -NSString *remotePath = body.remotePath; -// 从本地获取文件路径。 -NSString *localPath = body.localPath; -``` - -## 发送和接收位置消息 - -1. 创建和发送位置消息。 +1. 发送方调用 `initWithLatitude` 方法和 `initWithConversationID` 方法创建位置消息。 +2. 发送方调用 `sendMessage` 方法发送位置消息。 发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 @@ -309,16 +169,10 @@ message.chatType = EMChatTypeGroupChat; [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; ``` -2. 接收位置消息与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - - 接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 - -## 发送和接收透传消息 +## 发送透传消息 可将透传消息理解为一条指令,通过发送这条指令给对方,通知对方要执行的操作,收到消息可以自定义处理。 - 具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 `action` 为内部保留字段,注意不要使用。 - 透传消息适用于更新头像、更新昵称等场景。 :::tip @@ -326,7 +180,10 @@ message.chatType = EMChatTypeGroupChat; - 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 ::: -1. 创建和发送透传消息。 +发送透传消息的过程如下: + +1. 发送方调用 `initWithAction` 方法创建透传消息。 +2. 发送方调用 `sendMessage` 方法发送透传消息。 ```objectivec // `action` 自定义 `NSString` 类型的命令内容。 @@ -341,23 +198,12 @@ EMCmdMessageBody *body = [[EMCmdMessageBody alloc] initWithAction:action]; [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; ``` -2. 接收方通过 `cmdMessagesDidReceive` 回调接收透传消息,方便用户进行不同的处理。 - -```objectivec -// 收到透传消息。 -- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages{ - for (EMChatMessage *message in aCmdMessages) { - EMCmdMessageBody *body = (EMCmdMessageBody *)message.body; - // 进行透传消息 body 解析。 - } - } -``` - -## 发送和接收自定义类型消息 +## 发送自定义类型消息 -除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 +你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 -1. 创建和发送自定义类型消息。 +1. 发送方调用 `initWithEvent` 和 `initWithConversationID` 方法创建自定义消息。 +2. 发送方调用 `sendMessage` 方法发送自定义消息。 ```objectivec // event 为需要传递的自定义消息事件,比如名片消息,可以设置 "userCard";`ext` 为事件扩展字段,比如可以设置 `uid`,`nickname`,`avatar`。 @@ -370,21 +216,12 @@ message.chatType = EMChatTypeGroupChat; [[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:nil]; ``` -2. 接收自定义消息与其他类型消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -## 发送和接收合并消息 +## 发送合并消息 为了方便消息互动,即时通讯 IM 自 4.1.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: 1. 利用原始消息列表创建一条合并消息。 2. 发送合并消息。 -3. 对端收到合并消息后进行解析,获取原始消息列表。 - -:::tip -对于转发合并消息,例如,用户 A 向 用户 B 发送了合并消息,用户 B 将该合并消息转发给用户 C,需要调用转发单条合并消息的 API。详见[转发单条消息](message_forward.html#转发单条消息)。 -::: - -#### 创建和发送合并消息 你可以调用 `EMCombineMessageBody#initWithTitle:summary:compatibleText:messageList` 方法构造一条合并消息体,然后创建消息 `EMChatMessage` 并调用 `sendMessage` 方法发送该条消息。 @@ -398,10 +235,10 @@ message.chatType = EMChatTypeGroupChat; | `messageIdList` | List | 合并消息的原始消息 ID 列表。该列表最多包含 300 个消息 ID。 | :::tip - 1. 合并转发支持嵌套,最多支持 10 层嵌套,每层最多 300 条消息。 2. 只有成功发送或接收的消息才能合并转发。 3. 不论 `EMOptions#isAutoTransferMessageAttachments` 设置为 `false` 或 `true`,SDK 都会将合并消息附件上传到环信服务器。 +4. 对于转发合并消息,例如,用户 A 向 用户 B 发送了合并消息,用户 B 将该合并消息转发给用户 C,需要调用转发单条合并消息的 API。详见[转发单条消息](message_forward.html#转发单条消息)。 ::: 示例代码如下: @@ -414,94 +251,6 @@ EMChatMessage* msg = [[EMChatMessage alloc] initWithConversationID:@"conversatio }]; ``` -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,详见[接收消息](#发送和接收文本消息)。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 - -对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: - -- 若附件已存在,该方法会直接解析附件并返回原始消息列表。 -- 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 - -```objectivec -- (void)messagesDidReceive:(NSArray *)aMessages -{ - - for (EMChatMessage* msg in aMessages) { - if (msg.body.type == EMMessageBodyTypeCombine) { - // 合并消息类型,解析合并消息 - [EMClient.sharedClient.chatManager downloadAndParseCombineMessage:msg completion:^(NSArray * _Nullable messages, EMError * _Nullable error) { - - }]; - } - } -} -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 仅 SDK 4.0.3 及以上版本支持。 -2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: - -1. 创建一条群组或聊天室消息。 -2. 设置消息的接收方。 -3. 发送定向消息。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```objectivec -// 创建一条文本消息。 -EMTextMessageBody* textBody = [[EMTextMessageBody alloc] initWithText:@"hello"]; -EMChatMessage* msg = [[EMChatMessage alloc] initWithConversationID:@"groupId" body:textBody ext:nil]; -// 会话类型:群组和聊天室聊天,分别为 `EMChatTypeGroupChat` 和 `EMChatTypeChatRoom`。 -msg.chatType = EMChatTypeGroupChat; -// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `nil`,则消息发送给群组或聊天室的所有成员。 -msg.receiverList = @[@"A",@"B"]; -// 发送消息。 -[EMClient.sharedClient.chatManager sendMessage:msg progress:nil completion:^(EMChatMessage * _Nullable message, EMError * _Nullable error) { - -}]; -``` - -接收定向消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 - -## 使用消息扩展字段 - -当 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/ios/message_target.md b/docs/document/ios/message_target.md new file mode 100644 index 000000000..279a61309 --- /dev/null +++ b/docs/document/ios/message_target.md @@ -0,0 +1,36 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 + +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 仅 SDK 4.0.3 及以上版本支持。 +2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: + +1. 创建一条群组或聊天室消息。 +2. 设置消息的接收方。 +3. 发送定向消息。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```objectivec +// 创建一条文本消息。 +EMTextMessageBody* textBody = [[EMTextMessageBody alloc] initWithText:@"hello"]; +EMChatMessage* msg = [[EMChatMessage alloc] initWithConversationID:@"groupId" body:textBody ext:nil]; +// 会话类型:群组和聊天室聊天,分别为 `EMChatTypeGroupChat` 和 `EMChatTypeChatRoom`。 +msg.chatType = EMChatTypeGroupChat; +// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `nil`,则消息发送给群组或聊天室的所有成员。 +msg.receiverList = @[@"A",@"B"]; +// 发送消息。 +[EMClient.sharedClient.chatManager sendMessage:msg progress:nil completion:^(EMChatMessage * _Nullable message, EMError * _Nullable error) { + +}]; +``` + +接收定向消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 diff --git a/docs/document/react-native/message_extension.md b/docs/document/react-native/message_extension.md new file mode 100644 index 000000000..99759a9f7 --- /dev/null +++ b/docs/document/react-native/message_extension.md @@ -0,0 +1,14 @@ +# 消息扩展 + +当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```typescript +const msg = ChatMessage.createTextMessage(targetId, '文本消息', chatType); +msg.attributes = { + key: "value", + { + key2: 100 + } +}; +EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); +``` \ No newline at end of file diff --git a/docs/document/react-native/message_receive.md b/docs/document/react-native/message_receive.md new file mode 100644 index 000000000..81e23df74 --- /dev/null +++ b/docs/document/react-native/message_receive.md @@ -0,0 +1,171 @@ +# 接收消息 + + + +环信即时通讯 IM React Native SDK 通过 `ChatMessageEventListener` 类实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +- 你可以用注册监听 `ChatMessageEventListener` 接收消息。该监听可添加多次,可在不需要的时移除。 +- 在新消息到来时,你会收到 `onMessagesReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `ChatOptions#messagesReceiveCallbackIncludeSend` 开关,则该回调中会返回发送成功的消息。 +- 对于聊天室消息,你可以通过消息的 `ChatMessage.isBroadcast` 属性判断该消息是否为 [通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```typescript +// 继承并实现 ChatMessageEventListener +class ChatMessageEvent implements ChatMessageEventListener { + onMessagesReceived(messages: ChatMessage[]): void { + console.log(`onMessagesReceived: `, messages); + } + // 其他回调接收省略,实际开发中需要实现 +} + +// 注册监听器 +const listener = new ChatMessageEvent(); +ChatClient.getInstance().chatManager.addMessageListener(listener); + +// 移除监听器 +ChatClient.getInstance().chatManager.removeMessageListener(listener); + +// 移除所有监听器 +ChatClient.getInstance().chatManager.removeAllMessageListener(); +``` + +## 接收附件消息 + +除文本消息外,SDK 还支持接收附件类型消息,包括语音、图片、视频和文件消息。 + +附件消息的接收过程如下: + +1. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用下载附件方法。 +2. 获取附件的服务器地址和本地路径。 + +### 接收语音消息 + +1. 接收方收到语音消息时,自动下载语音文件。 +2. 接收方收到 `onMessagesReceived` 回调,消息对象属性包括语音文件的服务器地址 `msg.body.remotePath` 或本地路径 `msg.body.localPath`,从而获取语音文件。 + +### 接收图片消息 + +1. 接收方收到图片消息,自动下载图片缩略图。 + +```typescript +ChatClient.getInstance().init( + new ChatOptions({ + appKey, + isAutoDownload: true, + }) +); +``` + +如果设置为手动下载,则需要设置 `isAutoDownload` 为 `false`,并且调用方法 `downloadThumbnail`。 + +```typescript +ChatClient.getInstance() + .chatManager.downloadThumbnail(msg, callback) + .then() + .catch(); +``` + +2. 接收方收到 [onMessageReceived 回调](#接收文本消息),调用 `downloadAttachment` 下载原图。 + +```typescript +ChatClient.getInstance() + .chatManager.downloadAttachment(msg, callback) + .then() + .catch(); +``` + +4. 获取图片消息的附件信息可以通过图片消息的消息体对象 `body` 获取。 + +### 接收视频消息 + +1. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#接收图片消息)。 + +2. 接收方收到 [onMessageReceived 回调](#接收文本消息),可以调用 `downloadAttachment` 方法下载视频原文件。 + +```typescript +ChatClient.getInstance() + .chatManager.downloadAttachment(msg, callback) + .then() + .catch(); +``` + +3. 视频消息的信息可以通过消息体 `body` 对象获取。 + +### 接收文件消息 + +1. 接收方收到 [onMessagesReceived](#接收文本消息) 回调,调用 `downloadAttachment` 方法下载文件。 + +```typescript +ChatClient.getInstance() + .chatManager.downloadAttachment(msg, callback) + .then() + .catch(); +``` + +2. 通过文件消息对象的消息体对象 `body` 获取文件信息。 + +## 接收位置消息 + +接收位置消息与文本消息一致,详见[接收文本消息](#接收文本消息)。 + +接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +## 接收透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +请注意透传消息的接收方,也是由单独的回调进行通知,方便用户进行不同的处理。 + +```typescript +let listener = new (class implements ChatMessageEventListener { + onCmdMessagesReceived(messages: ChatMessage[]): void { + // 这里接收透传消息数据 + } +})(); +ChatClient.getInstance().chatManager.addMessageListener(listener); +``` + +## 接收自定义类型消息 + +除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +接收自定义消息与其他类型消息一致,详见[接收文本消息](#接收文本消息)。 + +## 接收合并消息 + +为了方便消息互动,即时通讯 IM 自 1.2.0 版本开始支持将多个消息合并在一起进行转发,例如,发送聊天记录。 + +接收合并消息与接收普通消息的操作相同,详见[接收消息](#接收文本消息)。 +- 对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 +- 合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `fetchCombineMessageDetail` 方法获取原始消息列表。 +- 对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: + - 若附件已存在,该方法会直接解析附件并返回原始消息列表。 + - 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 + +```typescript +// message: 合并消息对象 +// 通过异步返回原始消息列表。 +ChatClient.getInstance() + .chatManager.fetchCombineMessageDetail(message) + .then((messages: ChatMessage[]) => { + console.log("success: ", messages); + }) + .catch((error) => { + console.log("fail: ", error); + }); +``` \ No newline at end of file diff --git a/docs/document/react-native/message_send_receive.md b/docs/document/react-native/message_send.md similarity index 56% rename from docs/document/react-native/message_send_receive.md rename to docs/document/react-native/message_send.md index 00ec2f7fe..fcdc51ae1 100644 --- a/docs/document/react-native/message_send_receive.md +++ b/docs/document/react-native/message_send.md @@ -1,14 +1,12 @@ -# 发送和接收消息 +# 发送消息 -环信即时通讯 IM React Native SDK 通过 `ChatManager` 类和 `ChatMessage` 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 - -- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 +环信即时通讯 IM React Native SDK 通过 `ChatManager` 类和 `ChatMessage` 类实现文本、图片、音频、视频和文件等类型的消息的发送。 +- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要 [开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 - -关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 +- 关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 ## 前提条件 @@ -17,9 +15,9 @@ - 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 - 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -## 发送和接收文本消息 +## 发送文本消息 -1. 首先,利用 `ChatMessage` 类构造一条消息。 +1. 发送方调用 `ChatMessage#createTextMessage` 方法构造一条消息。 默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509。 @@ -64,54 +62,26 @@ ChatClient.getInstance() }); ``` -2. 通过 `ChatManager` 将该消息发出。发送消息时可以设置 `EMCallBack` 的实例,获取消息发送状态。 +2. 发送方调用 `ChatManager#sendMessage` 方法将该消息发出。发送消息时可以设置 `EMCallBack` 的实例,获取消息发送状态。 ```typescript ChatClient.getInstance().chatManager.sendMessage(msg!, callback).then().catch(); ``` -3. 你可以用注册监听 `ChatMessageEventListener` 接收消息。该监听可添加多次,可在不需要的时移除。 - -在新消息到来时,你会收到 `onMessagesReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `ChatOptions#messagesReceiveCallbackIncludeSend` 开关,则该回调中会返回发送成功的消息。 - -对于聊天室消息,你可以通过消息的 `ChatMessage.isBroadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```typescript -// 继承并实现 ChatMessageEventListener -class ChatMessageEvent implements ChatMessageEventListener { - onMessagesReceived(messages: ChatMessage[]): void { - console.log(`onMessagesReceived: `, messages); - } - // 其他回调接收省略,实际开发中需要实现 -} - -// 注册监听器 -const listener = new ChatMessageEvent(); -ChatClient.getInstance().chatManager.addMessageListener(listener); - -// 移除监听器 -ChatClient.getInstance().chatManager.removeMessageListener(listener); - -// 移除所有监听器 -ChatClient.getInstance().chatManager.removeAllMessageListener(); -``` - -## 发送和接收附件消息 +## 发送附件消息 除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 -附件消息的发送和接收过程如下: +发送附件消息分为以下两步: -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器。 -2. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用下载附件方法。 -3. 获取附件的服务器地址和本地路径。 +1. 创建和发送附件类型消息。 +2. SDK 将附件上传到环信服务器。 -### 发送和接收语音消息 - -发送和接收语音消息的过程如下: +### 发送语音消息 1. 发送语音消息前,在应用层录制语音文件。 -2. 发送方调用 `createVoiceMessage` 方法传入语音文件的 URI、语音时长和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建语音消息,然后调用发送消息方法发送消息。SDK 会将语音文件上传至环信服务器。 +2. 发送方调用 `createVoiceMessage` 方法传入语音文件的 URI、语音时长和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建语音消息。 +3. 发送方调用发送消息方法发送消息。SDK 会将语音文件上传至环信服务器。 ```typescript // 构建语音消息 @@ -127,15 +97,10 @@ const msg = ChatMessage.createVoiceMessage(targetId, filePath, chatType, { EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -3. 接收方收到语音消息时,自动下载语音文件。 - -4. 接收方收到 `onMessagesReceived` 回调,消息对象属性包括语音文件的服务器地址 `msg.body.remotePath`或本地路径 `msg.body.localPath`,从而获取语音文件。 - -### 发送和接收图片消息 +### 发送图片消息 -发送和接收图片消息的流程如下: - -1. 发送方调用 `createImageMessage` 方法传入图片的本地资源标志符 URI、设置是否发送原图以及接收方的用户 ID (群聊或聊天室分别为群组 ID 或聊天室 ID)创建图片消息,然后调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 +1. 发送方调用 `createImageMessage` 方法传入图片的本地资源标志符 URI、设置是否发送原图以及接收方的用户 ID (群聊或聊天室分别为群组 ID 或聊天室 ID)创建图片消息。 +2. 发送方调用 `sendMessage` 方法发送该消息。SDK 会将图片上传至环信服务器,服务器自动生成图片缩略图。 ```typescript // 构建图片消息 @@ -153,44 +118,12 @@ const msg = ChatMessage.createImageMessage(targetId, filePath, chatType, { EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -2. 接收方收到图片消息,自动下载图片缩略图。 - -```typescript -ChatClient.getInstance().init( - new ChatOptions({ - appKey, - isAutoDownload: true, - }) -); -``` - -如果设置为手动下载,则需要设置 `isAutoDownload` 为 `false`,并且调用方法 `downloadThumbnail`。 - -```typescript -ChatClient.getInstance() - .chatManager.downloadThumbnail(msg, callback) - .then() - .catch(); -``` - -3. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),调用 `downloadAttachment` 下载原图。 - -```typescript -ChatClient.getInstance() - .chatManager.downloadAttachment(msg, callback) - .then() - .catch(); -``` - -4. 获取图片消息的附件信息可以通过图片消息的消息体对象 `body` 获取。 -### 发送和接收视频消息 - -发送和接收视频消息的流程如下: +### 发送视频消息 1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 - -2. 发送方调用 `createVideoMessage` 方法传入视频文件的本地资源标志符、缩略图的本地存储路径、视频时长以及接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID),然后调用 `sendMessage` 方法发送消息。SDK 会将视频文件上传至消息服务器。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `createVideoMessage` 方法。 +2. 发送方调用 `createVideoMessage` 方法传入视频文件的本地资源标志符、缩略图的本地存储路径、视频时长以及接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)。 +3. 发送方调用 `sendMessage` 方法发送消息。SDK 会将视频文件上传至消息服务器。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `createVideoMessage` 方法。 ```typescript // 构建视频消息 @@ -213,24 +146,10 @@ const msg = ChatMessage.createVideoMessage(targetId, filePath, chatType, { EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -3. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#发送和接收图片消息)。 - -4. 接收方收到 [onMessageReceived 回调](#发送和接收文本消息),可以调用 `downloadAttachment` 方法下载视频原文件。 - -```typescript -ChatClient.getInstance() - .chatManager.downloadAttachment(msg, callback) - .then() - .catch(); -``` - -5. 视频消息的信息可以通过消息体 `body` 对象获取。 - -### 发送和接收文件消息 - -发送和接收文件消息的流程如下: +### 发送文件消息 -1. 发送方调用 `createFileMessage` 方法传入文件的本地资源标志符和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建文件消息,然后调用 `sendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 +1. 发送方调用 `createFileMessage` 方法传入文件的本地资源标志符和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建文件消息。 +2. 发送方调用 `sendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 ```typescript // 构建文件消息 @@ -244,20 +163,12 @@ const msg = ChatMessage.createFileMessage(targetId, filePath, chatType, { EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -2. 接收方收到 `onMessagesReceived` 回调,调用 `downloadAttachment` 方法下载文件。 +## 发送位置消息 -```typescript -ChatClient.getInstance() - .chatManager.downloadAttachment(msg, callback) - .then() - .catch(); -``` - -3. 通过文件消息对象的消息体对象 `body` 获取文件信息。 +1. 发送方调用 `ChatMessage#createLocationMessage` 方法创建位置消息。 +2. 发送方调用 `ChatManager#sendMessage` 方法发送位置消息。 -## 发送和接收位置消息 - -当你要发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 +当你要发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 ```typescript // 构建位置消息 @@ -275,7 +186,7 @@ const msg = ChatMessage.createLocationMessage( EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -## 发送和接收透传消息 +## 发送透传消息 透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 @@ -286,6 +197,11 @@ EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); - 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 ::: +发送透传消息的过程如下: + +1. 发送方调用 `ChatMessage#createCmdMessage` 方法创建透传消息。 +2. 发送方调用 `ChatManager#sendMessage` 方法发送透传消息。 + ```typescript // 构建透传消息 // 根据透传消息可以执行具体的命令,命令的内容格式支持自定义 @@ -294,24 +210,12 @@ const msg = ChatMessage.createCmdMessage(targetId, action, chatType); EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -请注意透传消息的接收方,也是由单独的回调进行通知,方便用户进行不同的处理。 - -```typescript -let listener = new (class implements ChatMessageEventListener { - onCmdMessagesReceived(messages: ChatMessage[]): void { - // 这里接收透传消息数据 - } -})(); -ChatClient.getInstance().chatManager.addMessageListener(listener); -``` - ## 发送自定义类型消息 除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 -接收自定义消息与其他类型消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -以下为创建和发送自定义类型消息的示例代码: +1. 发送方调用 `ChatMessage#createCustomMessage` 方法创建自定义消息。 +2. 发送方调用 `ChatManager#sendMessage` 方法发送自定义消息。 ```typescript // 构建自定义消息 @@ -324,7 +228,7 @@ const msg = ChatMessage.createCustomMessage(targetId, event, chatType, { EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -## 发送和接收合并消息 +## 发送合并消息 为了方便消息互动,即时通讯 IM 自 1.2.0 版本开始支持将多个消息合并在一起进行转发,例如,发送聊天记录。 @@ -334,8 +238,6 @@ EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); 2. 发送合并消息。 3. 对端收到合并消息后进行解析,获取原始消息列表。 -#### 创建和发送合并消息 - 你可以调用 `createCombineMessage` 方法创建一条合并消息,然后调用 `sendMessage` 方法发送该条消息。 创建合并消息时,需要设置以下参数: @@ -367,79 +269,6 @@ const msg = ChatMessage.createCombineMessage(targetId, msgIdList, chatType, { EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); ``` -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,详见[接收消息](#发送和接收文本消息)。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `fetchCombineMessageDetail` 方法获取原始消息列表。 - -对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: -- 若附件已存在,该方法会直接解析附件并返回原始消息列表。 -- 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 - -```typescript -// message: 合并消息对象 -// 通过异步返回原始消息列表。 -ChatClient.getInstance() - .chatManager.fetchCombineMessageDetail(message) - .then((messages: ChatMessage[]) => { - console.log("success: ", messages); - }) - .catch((error) => { - console.log("fail: ", error); - }); -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 仅 SDK 1.2.0 及以上版本支持该功能。 -2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: - -1. 创建一条群组或聊天室消息。 -2. 设置消息的接收方。 -3. 发送定向消息。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```typescript -const content = "This is text message"; -msg = ChatMessage.createTextMessage(targetId, content, chatType); -msg.receiverList = ["001", "002"]; -ChatClient.getInstance().chatManager.sendMessage(msg, { - onSuccess: () => {}, - onError: () => {}, -} as ChatMessageStatusCallback); -``` - -接收群定向消息与接收普通消息的操作相同,详见[接收消息](#发送和接收文本消息)。 - -## 使用消息扩展字段 - -当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 - -```typescript -const msg = ChatMessage.createTextMessage(targetId, '文本消息', chatType); -msg.attributes = { - key: "value", - { - key2: 100 - } -}; -EMClient.getInstance().chatManager().sendMessage(msg, callback).then().catch(); -``` - ## 更多 ### 聊天室消息优先级与消息丢弃逻辑 diff --git a/docs/document/react-native/message_target.md b/docs/document/react-native/message_target.md new file mode 100644 index 000000000..3a5f04ce2 --- /dev/null +++ b/docs/document/react-native/message_target.md @@ -0,0 +1,32 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 + +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 仅 SDK 1.2.0 及以上版本支持该功能。 +2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: + +1. 创建一条群组或聊天室消息。 +2. 设置消息的接收方。 +3. 发送定向消息。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```typescript +const content = "This is text message"; +msg = ChatMessage.createTextMessage(targetId, content, chatType); +msg.receiverList = ["001", "002"]; +ChatClient.getInstance().chatManager.sendMessage(msg, { + onSuccess: () => {}, + onError: () => {}, +} as ChatMessageStatusCallback); +``` + +接收群定向消息与接收普通消息的操作相同,详见[接收消息](message_receive.html#接收文本消息)。 \ No newline at end of file diff --git a/docs/document/unity/message_extension.md b/docs/document/unity/message_extension.md new file mode 100644 index 000000000..1e2f6e572 --- /dev/null +++ b/docs/document/unity/message_extension.md @@ -0,0 +1,34 @@ +# 消息扩展 + +当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```csharp +Message msg = Message.CreateTextSendMessage(toChatUsername, content); + +// 增加自定义属性。 +AttributeValue attr1 = AttributeValue.Of("value", AttributeValueType.STRING); +AttributeValue attr2 = AttributeValue.Of(true, AttributeValueType.BOOL); +msg.Attributes.Add("attribute1", attr1); +msg.Attributes.Add("attribute2", attr2); + +// 发送消息。 +SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + Debug.Log($"{msg.MsgId}发送成功"); + }, + onError:(code, desc) => { + Debug.Log($"{msg.MsgId}发送失败,errCode={code}, errDesc={desc}"); + } +)); +// 接收消息的时候获取扩展属性。 +bool found = false; +string str = Message.GetAttributeValue(msg.Attributes, "attribute1", out found); +if (found) { + // 使用 str 变量。 +} +found = false; +bool b = Message.GetAttributeValue(msg.Attributes, "attribute2", out found); +if (found) { + // 使用 b 变量。 +} +``` \ No newline at end of file diff --git a/docs/document/unity/message_receive.md b/docs/document/unity/message_receive.md new file mode 100644 index 000000000..37900196d --- /dev/null +++ b/docs/document/unity/message_receive.md @@ -0,0 +1,270 @@ +# 接收消息 + +环信即时通讯 IM Unity SDK 通过 `IChatManagerDelegate` 类实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +- 你可以用注册监听 `IChatManagerDelegate` 接收消息。该 `IChatManagerDelegate` 可以多次添加,请记得在不需要的时候移除该监听。如在析构 `IChatManagerDelegate` 的继承实例之前。 +- 在新消息到来时,你会收到 `OnMessagesReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `Options#IncludeSendMessageInMessageListener` 开关,则该回调中会返回发送成功的消息。 +- 对于聊天室消息,你可以通过消息的 `Message#Broadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```csharp +//继承并实现 IChatManagerDelegate。 +public class ChatManagerDelegate : IChatManagerDelegate { + + //实现 OnMessagesReceived 回调。 + public void OnMessagesReceived(List messages) + { + //收到消息,遍历消息列表,解析和显示。 + } +} + +//申请并注册监听。 +ChatManagerDelegate adelegate = new ChatManagerDelegate(); +SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + +//移除监听。 +SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); +``` + +## 接收附件消息 + +除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 + +附件消息的接收过程如下: + +1. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `DownloadAttachment` 方法。 + +2. 获取附件的服务器地址和本地路径。 + +### 接收语音消息 + +1. 接收方收到语音消息时,自动下载语音文件。 + +2. 接收方收到 [OnMessagesReceived](#接收文本消息) 回调,获取语音文件的服务器地址或本地路径,从而获取语音文件。 + +```csharp + +foreach (var msg in messages) +{ + if (msg != null) + { + ChatSDK.MessageBody.VoiceBody vb = (ChatSDK.MessageBody.VoiceBody)msg.Body; + + //语音文件在服务器的路径。 + string voiceRemoteUrl = vb.RemotePath; + + //语音文件的本地路径。 + string voiceLocalUri = vb.LocalPath; + } + else { + Debug.Log($"未找到消息"); + } +} + +``` + +### 接收图片消息 + +1. 接收方收到图片消息,自动下载图片缩略图。 + +2. 图片消息的接收与文本消息一致,详见 [接收文本消息](#接收文本消息)。 + + 接收方收到图片消息后,参考如下示例代码获取图片消息的缩略图和附件。 + +- 接收方如果设置了自动下载,即 `Options.IsAutoDownload` 为 `true`,SDK 接收到消息后会下载缩略图。 + +- 如果未设置自动下载,需主动调用 `SDKClient.Instance.ChatManager.DownloadAttachment` 下载。 + +3. 使用`DownloadAttachment`下载完成后,可获取消息的图片文件和缩略图。 + +```csharp + +SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack( + onSuccess: () => { + Debug.Log($"下载附件成功"); + + Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); + if (msg != null) + { + ChatSDK.MessageBody.ImageBody ib = (ChatSDK.MessageBody.ImageBody)msg.Body; + + //服务器端图片文件路径。 + string imgRemoteUrl = ib.RemotePath; + + //服务器端图片缩略图路径。 + string thumbnailUrl = ib.ThumbnaiRemotePath; + + //本地图片文件路径。 + string imgLocalUri = ib.LocalPath; + + //本地图片缩略图路径。 + Uri thumbnailLocalUri = ib.ThumbnailLocalPath; + + } + else { + Debug.Log($"未找到消息"); + } + + }, + onProgress: (progress) => { + Debug.Log($"下载附件进度 {progress}"); + }, + onError: (code, desc) => { + Debug.Log($"附件下载失败,errCode={code}, errDesc={desc}"); + } +)); + +``` + +### 接收视频消息 + +1. 接收方收到视频消息时,自动下载视频缩略图。 + + 你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见 [设置图片缩略图自动下载](#接收图片消息)。 + +2. 接收方收到 [OnMessageReceive](#接收文本消息) 回调,可以调用 `SDKClient.Instance.ChatManager.DownloadAttachment` 下载视频附件。下载完成后,使用相应消息 `Body` 的 `LocalPath` 成员获取视频文件路径。 + +```csharp +// 接收到视频消息需先下载附件才能打开。 +SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack( + onSuccess: () => { + Debug.Log($"下载附件成功"); + + Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); + if (msg != null) + { + if (msg.Body.Type == ChatSDK.MessageBodyType.VIDEO) { + ChatSDK.MessageBody.VideoBody vb = (ChatSDK.MessageBody.VideoBody)msg.Body; + //从本地获取视频文件路径。 + string videoLocalUri = vb.LocalPath; + //这里可以根据本地路径打开文件。 + } + } + else { + Debug.Log($"未找到消息"); + } + + }, + onProgress: (progress) => { + Debug.Log($"下载附件进度 {progress}"); + }, + onError: (code, desc) => { + Debug.Log($"附件下载失败,errCode={code}, errDesc={desc}"); + } +)); +``` + +### 接收文件消息 + +接收方收到 [OnMessageReceive 回调](#接收文本消息),调用 `DownloadAttachment` 方法下载文件。 + +```csharp +/** + * 下载文件。 + */ +SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack( + onSuccess: () => { + Debug.Log($"下载附件成功"); + + Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); + if (msg != null) + { + ChatSDK.MessageBody.FileBody fb = (ChatSDK.MessageBody.FileBody)msg.Body; + + //服务器文件路径。 + string fileRemoteUrl = fb.RemotePath; + + //本地文件路径。 + string fileLocalUri = fb.LocalPath; + + } + else { + Debug.Log($"未找到消息"); + } + + }, + onProgress: (progress) => { + Debug.Log($"下载附件进度 {progress}"); + }, + onError: (code, desc) => { + Debug.Log($"附件下载失败,errCode={code}, errDesc={desc}"); + } +)); +``` + +## 接收位置消息 + +接收位置消息与文本消息一致,详见[接收文本消息](#接收文本消息)。 + +接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +## 接收透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +接收方通过 `OnMessagesReceived` 和 `OnCmdMessagesReceived` 回调接收透传消息,方便用户进行不同的处理。 + +```csharp +// 继承并实现 `IChatManagerDelegate`。 +public class ChatManagerDelegate : IChatManagerDelegate { + + // 收到消息。 + public void OnMessagesReceived(List messages) + { + // 收到消息,遍历消息列表,解析和显示。 + } + // 收到透传消息。 + void OnCmdMessagesReceived(List messages) + { + // 收到消息,遍历消息列表,解析和处理。 + } +} + +// 申请并注册监听。 +ChatManagerDelegate adelegate = new ChatManagerDelegate() +SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + +``` + +## 接收自定义类型消息 + +除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +接收自定义消息与其他类型消息一致,详见[接收文本消息](#接收文本消息)。 + +## 接收合并消息 + +接收合并消息与接收普通消息的操作相同,详见[接收消息](#接收文本消息)。 + +- 对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 +- 合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `FetchCombineMessageDetail` 方法下载合并消息附件并解析出原始消息列表。 +- 对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: + - 若附件已存在,该方法会直接解析附件并返回原始消息列表。 + - 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 + +```csharp +SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( + onSuccess: (list) => { + // 处理并展示消息列表 + }, + onError: (code, desc) => { + // 处理出错信息 + } +)); +``` + diff --git a/docs/document/unity/message_send_receive.md b/docs/document/unity/message_send.md similarity index 54% rename from docs/document/unity/message_send_receive.md rename to docs/document/unity/message_send.md index 02c37f0c9..0165df1c1 100644 --- a/docs/document/unity/message_send_receive.md +++ b/docs/document/unity/message_send.md @@ -1,8 +1,8 @@ -# 发送和接收消息 +# 发送消息 -环信即时通讯 IM Unity SDK 通过 `IChatManager` 和 `Message` 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 +环信即时通讯 IM Unity SDK 通过 `IChatManager` 和 `Message` 类实现文本、图片、音频、视频和文件等类型的消息的发送。 -- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 +- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要 [开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 @@ -15,9 +15,9 @@ - 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 - 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -## 发送和接收文本消息 +## 发送文本消息 -1. 你可以利用 `Message` 类构造一个消息,然后通过 `IChatManager` 将该消息发出。 +你可以利用 `Message` 类构造一个消息,然后通过 `IChatManager` 将该消息发出。 默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 @@ -49,44 +49,20 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 你可以用注册监听 `IChatManagerDelegate` 接收消息。该 `IChatManagerDelegate` 可以多次添加,请记得在不需要的时候移除该监听。如在析构 `IChatManagerDelegate` 的继承实例之前。 - -在新消息到来时,你会收到 `OnMessagesReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `Options#IncludeSendMessageInMessageListener` 开关,则该回调中会返回发送成功的消息。 - -对于聊天室消息,你可以通过消息的 `Message#Broadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```csharp -//继承并实现 IChatManagerDelegate。 -public class ChatManagerDelegate : IChatManagerDelegate { - - //实现 OnMessagesReceived 回调。 - public void OnMessagesReceived(List messages) - { - //收到消息,遍历消息列表,解析和显示。 - } -} - -//申请并注册监听。 -ChatManagerDelegate adelegate = new ChatManagerDelegate(); -SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); - -//移除监听。 -SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); -``` - -## 发送和接收附件消息 +## 发送接收附件消息 除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 附件消息的发送和接收过程如下: -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器。 -2. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `DownloadAttachment` 方法。 -3. 获取附件的服务器地址和本地路径。 +1. 创建和发送附件类型消息。 +2. SDK 将附件上传到环信服务器。 -### 发送和接收语音消息 +### 发送语音消息 -发送语音消息时,应用层需完成语音文件录制的功能,提供语音文件的 URI 和语音时长。 +1. 发送语音消息前,在应用层录制语音文件。 +2. 发送方调用 `Message#CreateVoiceSendMessage` 方法传入语音文件的 URI、本地语音文件路径、语音时长和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建语音消息。 +3. 发送方调用 `ChatManager#SendMessage` 方法发送消息。SDK 会将语音文件上传至环信服务器。 参考如下示例代码创建并发送语音消息: @@ -115,34 +91,14 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -语音消息的接收与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -接收方收到语音消息后,参考如下示例代码获取语音消息的附件: - -```csharp -// 注意:这里的 "Message ID" 是消息发送成功以后(CallBack 中的 onSuccess 被触发以后),被发送消息的 ID。 -Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); -if (msg != null) -{ - ChatSDK.MessageBody.VoiceBody vb = (ChatSDK.MessageBody.VoiceBody)msg.Body; - - //语音文件在服务器的路径。 - string voiceRemoteUrl = vb.RemotePath; - - //语音文件的本地路径。 - string voiceLocalUri = vb.LocalPath; -} -else { - Debug.Log($"未找到消息"); -} -``` - -### 发送和接收图片消息 +### 发送图片消息 -1. 创建并发送图片消息。 +1. 发送方调用 `Message#CreateImageSendMessage` 方法传入图片的本地资源路径、设置是否发送原图以及接收方的用户 ID 等参数创建图片消息。 图片消息默认会被压缩后发出,可通过设置 `original` 参数为 `true` 发送原图。 +2. 发送方调用 `ChatManager#SendMessage` 方法发送消息。SDK 会将图片文件上传至环信服务器。 + ```csharp //`localPath` 为图片本地资源路径。 //`displayName` 为图片显示名称。 @@ -170,45 +126,15 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 图片消息的接收与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -接收方收到图片消息后,参考如下示例代码获取图片消息的缩略图和附件。 - -- 接收方如果设置了自动下载,即 `Options.IsAutoDownload` 为 `true`,SDK 接收到消息后会下载缩略图 -- 如果未设置自动下载,需主动调用 `SDKClient.Instance.ChatManager.DownloadThumbnail` 下载。 - -下载完成后,调用相应消息 `msg.Body` 的 `ThumbnailLocalPath` 获取缩略图路径。 - -```csharp -//注意:这里的 "Message ID" 是消息发送成功以后(`CallBack` 中的 `onSuccess` 被触发以后),被发送消息的 ID。 -Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); -if (msg != null) -{ - ChatSDK.MessageBody.ImageBody ib = (ChatSDK.MessageBody.ImageBody)msg.Body; - - //服务器端图片文件路径。 - string imgRemoteUrl = ib.RemotePath; - - //服务器端图片缩略图路径。 - string thumbnailUrl = ib.ThumbnaiRemotePath; +### 发送视频消息 - //本地图片文件路径。 - string imgLocalUri = ib.LocalPath; - - //本地图片缩略图路径。 - Uri thumbnailLocalUri = ib.ThumbnailLocalPath; - -} -else { - Debug.Log($"未找到消息"); -} -``` - -### 发送和接收视频消息 +1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 发送视频消息时,应用层需要完成视频文件的选取或者录制。视频消息支持给出视频的时长作为参数,发送给接收方。 -1. 创建并发送视频消息。 +2. 发送方调用 `Message#CreateVideoSendMessage` 方法传入视频文件的本地资源标志符、缩略图的本地存储路径、视频时长以及接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID) 创建视频消息。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `thumbnailLocalPath` 方法。 + +3. 发送方调用 `ChatManager#SendMessage` 方法发送视频消息。SDK 会将视频文件上传至消息服务器。 ```csharp Message msg = Message.CreateVideoSendMessage(toChatUsername, localPath, displayName, thumbnailLocalPath, fileSize, duration, width, height); @@ -228,43 +154,11 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#发送和接收图片消息)。 - -视频文件本身需要通过 `SDKClient.Instance.ChatManager.DownloadAttachment` 下载,下载完成后,使用相应消息 `Body` 的 `LocalPath` 成员获取视频文件路径。 - -```csharp -// 接收到视频消息需先下载附件才能打开。 -SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack( - onSuccess: () => { - Debug.Log($"下载附件成功"); - - Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); - if (msg != null) - { - if (msg.Body.Type == ChatSDK.MessageBodyType.VIDEO) { - ChatSDK.MessageBody.VideoBody vb = (ChatSDK.MessageBody.VideoBody)msg.Body; - //从本地获取视频文件路径。 - string videoLocalUri = vb.LocalPath; - //这里可以根据本地路径打开文件。 - } - } - else { - Debug.Log($"未找到消息"); - } - - }, - onProgress: (progress) => { - Debug.Log($"下载附件进度 {progress}"); - }, - onError: (code, desc) => { - Debug.Log($"附件下载失败,errCode={code}, errDesc={desc}"); - } -)); -``` - -### 发送和接收文件消息 +### 发送文件消息 -1. 创建并发送文件消息。 +1. 发送方调用 `Message#CreateFileSendMessage` 方法传入文件的本地资源标志符和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)等参数创建文件消息。 + +2. 发送方调用 `ChatManager#SendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 ```csharp // localPath 为文件本地路径,displayName 为消息显示名称,fileSize 为文件大小。 @@ -287,34 +181,15 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( Debug.Log($"{msg.MsgId}发送失败,errCode={code}, errDesc={desc}"); } )); - -// 发送成功后,获取文件消息附件。 -// 注意:这里的 "Message ID" 是消息发送成功以后(CallBack 中的 onSuccess 被触发以后),被发送消息的 ID。 -Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); -if (msg != null) -{ - ChatSDK.MessageBody.FileBody fb = (ChatSDK.MessageBody.FileBody)msg.Body; - - //服务器文件路径。 - string fileRemoteUrl = fb.RemotePath; - - //本地文件路径。 - string fileLocalUri = fb.LocalPath; - -} -else { - Debug.Log($"未找到消息"); -} - ``` -2. 文件消息的接收与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 +## 发送位置消息 -## 发送和接收位置消息 +1. 发送方调用 `Message#CreateLocationSendMessage` 方法创建位置消息。 + +2. 发送方调用 `ChatManager#SendMessage` 方法发送位置消息。 -1. 创建和发送位置消息。 - -发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 +发送位置时,需要集成第三方地图服务,获取到位置点的经纬度信息。 ```csharp //`latitude` 为纬度,`longitude` 为经度,`locationAddress` 为具体位置内容,`buildingName` 为建筑名称。 @@ -330,11 +205,7 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 接收位置消息与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - - 接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 - -## 发送和接收透传消息 +## 发送透传消息 透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 @@ -345,7 +216,11 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 ::: -1. 创建和发送透传消息。 +发送透传消息的过程如下: + +1. 发送方调用 `Message#CreateCmdSendMessage` 方法创建透传消息。 + +2. 发送方调用 `ChatManager#SendMessage` 方法发送透传消息。 ```csharp //`action` 可以自定义。 @@ -361,35 +236,13 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 接收方通过 `OnMessagesReceived` 和 `OnCmdMessagesReceived` 回调接收透传消息,方便用户进行不同的处理。 - -```csharp -// 继承并实现 `IChatManagerDelegate`。 -public class ChatManagerDelegate : IChatManagerDelegate { - - // 收到消息。 - public void OnMessagesReceived(List messages) - { - // 收到消息,遍历消息列表,解析和显示。 - } - // 收到透传消息。 - void OnCmdMessagesReceived(List messages) - { - // 收到消息,遍历消息列表,解析和处理。 - } -} - -// 申请并注册监听。 -ChatManagerDelegate adelegate = new ChatManagerDelegate() -SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); - -``` - -## 发送和接收自定义类型消息 +## 发送自定义类型消息 除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 -1. 创建和发送自定义类型消息。 +1. 发送方调用 `Message#CreateCustomSendMessage` 方法创建自定义消息。 + +2. 发送方调用 `ChatManager#SendMessage` 方法发送自定义消息。 ```csharp //`event` 为字符串类型的自定义事件,比如礼物消息,可以设置: @@ -410,17 +263,12 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 接收自定义消息与其他类型消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -## 发送和接收合并消息 +## 发送合并消息 为了方便消息互动,即时通讯 IM 自 1.2.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: 1. 利用原始消息列表创建一条合并消息。 2. 发送合并消息。 -3. 对端收到合并消息后进行解析,获取原始消息列表。 - -#### 创建和发送合并消息 你可以调用 `CreateCombineSendMessage` 方法创建一条合并消息,然后调用 `SendMessage` 方法发送该条消息。 @@ -458,111 +306,6 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,详见[接收消息](#发送和接收文本消息)。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `FetchCombineMessageDetail` 方法下载合并消息附件并解析出原始消息列表。 - -对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: - -- 若附件已存在,该方法会直接解析附件并返回原始消息列表。 -- 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 - -```csharp -SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( - onSuccess: (list) => { - // 处理并展示消息列表 - }, - onError: (code, desc) => { - // 处理出错信息 - } -)); -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 仅 SDK 1.2.0 及以上版本支持。 -2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息计数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: - -1. 创建一条群组或聊天室消息。 -2. 设置消息的接收方。 -3. 发送定向消息。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```csharp -// 创建一条文本消息。 -Message msg = Message.CreateTextSendMessage(groupId, content); -// 会话类型:群组和聊天室聊天,分别为 `Group` 和 `Room`。 -msg.MessageType = MessageType.Group; - -List receives = new List(); -receives.Add("userId1"); -receives.Add("userId2"); - -// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`或者包含接收Id数目为0,则消息发送给群组或聊天室的所有成员。 -msg.ReceiverList = receives; - -SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - onSuccess: () => { - - }, - onError: (code, desc) => { - - } -)); -``` - -接收群定向消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 - -## 使用消息扩展字段 - -当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 - -```csharp -Message msg = Message.CreateTextSendMessage(toChatUsername, content); - -// 增加自定义属性。 -AttributeValue attr1 = AttributeValue.Of("value", AttributeValueType.STRING); -AttributeValue attr2 = AttributeValue.Of(true, AttributeValueType.BOOL); -msg.Attributes.Add("attribute1", attr1); -msg.Attributes.Add("attribute2", attr2); - -// 发送消息。 -SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - onSuccess: () => { - Debug.Log($"{msg.MsgId}发送成功"); - }, - onError:(code, desc) => { - Debug.Log($"{msg.MsgId}发送失败,errCode={code}, errDesc={desc}"); - } -)); -// 接收消息的时候获取扩展属性。 -bool found = false; -string str = Message.GetAttributeValue(msg.Attributes, "attribute1", out found); -if (found) { - // 使用 str 变量。 -} -found = false; -bool b = Message.GetAttributeValue(msg.Attributes, "attribute2", out found); -if (found) { - // 使用 b 变量。 -} -``` - ## 更多 ### 聊天室消息优先级与消息丢弃逻辑 diff --git a/docs/document/unity/message_target.md b/docs/document/unity/message_target.md new file mode 100644 index 000000000..7b00e17c7 --- /dev/null +++ b/docs/document/unity/message_target.md @@ -0,0 +1,45 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 + +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 仅 SDK 1.2.0 及以上版本支持。 +2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息计数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: + +1. 创建一条群组或聊天室消息。 +2. 设置消息的接收方。 +3. 发送定向消息。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```csharp +// 创建一条文本消息。 +Message msg = Message.CreateTextSendMessage(groupId, content); +// 会话类型:群组和聊天室聊天,分别为 `Group` 和 `Room`。 +msg.MessageType = MessageType.Group; + +List receives = new List(); +receives.Add("userId1"); +receives.Add("userId2"); + +// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`或者包含接收Id数目为0,则消息发送给群组或聊天室的所有成员。 +msg.ReceiverList = receives; + +SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + + }, + onError: (code, desc) => { + + } +)); +``` + +接收群定向消息与接收普通消息的操作相同,详见 [接收文本消息](message_receive.html#接收文本消息)。 \ No newline at end of file diff --git a/docs/document/web/message_extension.md b/docs/document/web/message_extension.md new file mode 100644 index 000000000..812f1a800 --- /dev/null +++ b/docs/document/web/message_extension.md @@ -0,0 +1,31 @@ +# 消息扩展 + +如果上述消息类型无法满足要求,你可以使用消息扩展为消息添加属性。这种情况可用于更复杂的消息传递场景,例如,消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```javascript +function sendTextMessage() { + let option = { + type: "txt", + msg: "message content", + to: "username", + chatType: "singleChat", + // 设置消息扩展信息。扩展字段为可选,若带有该字段,值不能为空,即 "ext:null" 会出错。 + ext: { + key1: "Self-defined value1", + key2: { + key3: "Self-defined value3", + }, + }, + }; + let msg = WebIM.message.create(option); + // 调用 `send` 方法发送该扩展消息。 + conn + .send(msg) + .then((res) => { + console.log("send private text Success"); + }) + .catch((e) => { + console.log("Send private text error"); + }); +} +``` \ No newline at end of file diff --git a/docs/document/web/message_receive.md b/docs/document/web/message_receive.md new file mode 100644 index 000000000..fc8979f22 --- /dev/null +++ b/docs/document/web/message_receive.md @@ -0,0 +1,176 @@ +# 接收消息 + + + +环信即时通讯 IM Web SDK 可以实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +- 你可以通过 `addEventHandler` 注册监听器监听消息事件。你可以添加多个事件。当不再监听事件时,请确保删除监听器。 +- 当消息到达时,接收方会收到 `onTextMessage` 回调。每个回调包含一条或多条消息。你可以遍历消息列表,并可以解析和展示回调中的消息。 +- 对于聊天室消息,你可以通过消息的 `broadcast` 属性判断该消息是否为 [通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + onTextMessage: function (message) {}, +}); +``` + +## 接收附件消息 + +语音、图片、视频和文件消息本质上是附件消息。 + +接收方可以自行下载语音、图片、图片缩略图、视频和文件。 + +自 SDK 4.14.0 开始,支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户须调用 SDK 的 API `EC.utils.download` 下载消息附件。 + +### 接收语音消息 + +接收方收到 `onAudioMessage` 回调,根据消息 `url` 字段获取语音文件的服务器地址,从而获取语音文件。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + // 当前用户收到语音消息。 + onAudioMessage: function (message) { + // 语音文件在服务器的地址。 + console.log(message.url); + }, +}); + +``` + +### 接收图片消息 + +接收方收到 `onImageMessage` 回调,根据消息 `url` 字段获取图片文件的服务器地址,从而获取图片文件。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + // 当前用户收到图片消息。 + onImageMessage: function (message) { + // 图片文件在服务器的地址。 + console.log(message.url); + // 图片缩略图文件在服务器的地址。 + console.log(message.thumb); + }, +}); + +``` + +### 接收 GIF 图片消息 + +自 SDK 4.14.0 开始,支持接收 GIF 图片消息。 + +与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onImageMessage` 回调方法。接收方收到消息后,读取消息体的 `isGif` 属性,若值是 `true`, 则为 GIF 图片消息。 + +```javascript +onImageMessage: (message) => { + if(message.isGif){ + // 图片为GIF + } +} +``` + +### 接收视频消息 + +接收方收到 `onVideoMessage` 回调,根据消息 `url` 字段获取视频文件的服务器地址,从而获取视频文件。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + // 当前用户收到视频消息。 + onVideoMessage: function (message) { + // 视频文件在服务器的地址。 + console.log(message.url); + // 视频首帧缩略图文件在服务器的地址。 + console.log(message.thumb); + }, +}); + +``` + +### 接收文件消息 + +接收方收到 `onFileMessage` 回调,根据消息 `url` 字段获取文件的服务器地址,从而获取文件。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + // 当前用户收到文件消息。 + onFileMessage: function (message) { + // 文件在服务器的地址。 + console.log(message.url); + }, +}); + +``` + +## 接收位置消息 + +接收方收到 `onLocationMessage` 回调,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + // 当前用户收到文件消息。 + onLocationMessage: function (message) {}, +}); +``` + +## 接收透传消息 + +透传消息是通知指定用户采取特定操作的命令消息。接收方自己处理透传消息。 + +:::tip +透传消息发送后,不支持撤回。 +::: + +接收方通过 `onCmdMessage` 回调接收透传消息。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + onCmdMessage: function (message) {}, +}); +``` + +## 接收自定义消息 + +自定义消息为用户自定义的键值对,包括消息类型和消息内容。 + +接收方通过 `onCustomMessage` 回调接收自定义消息。 + +```javascript +// 使用 `addEventHandler` 监听回调事件 +conn.addEventHandler("eventName", { + onCustomMessage: function (message) {}, +}); +``` + +## 接收合并消息 + +为了方便消息互动,即时通讯 IM 自 4.2.0 版本开始支持将多个消息合并在一起进行转发。 + +接收合并消息与接收普通消息的操作相同,唯一不同是对于合并消息来说,消息接收事件为 `onCombineMessage`。 +- 对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 +- 合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 + +```javascript +connection + .downloadAndParseCombineMessage({ + url: msg.url, + secret: msg.secret, + }) + .then((res) => { + console.log("合并消息解析后的消息列表", res); + }); +``` \ No newline at end of file diff --git a/docs/document/web/message_send_receive.md b/docs/document/web/message_send.md similarity index 65% rename from docs/document/web/message_send_receive.md rename to docs/document/web/message_send.md index cfb0ccc48..eeaf8fd07 100644 --- a/docs/document/web/message_send_receive.md +++ b/docs/document/web/message_send.md @@ -1,14 +1,12 @@ -# 发送和接收消息 +# 发送消息 环信即时通讯 IM Web SDK 可以实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 - 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - - 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 - -关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 +- 关于消息发送控制,详见 [单聊](/product/message_single_chat.html#单聊消息发送控制)、[群组聊天](/product/message_group.html#群组消息发送控制) 和 [聊天室](/product/message_chatroom.html#聊天室消息发送控制) 的 相关文档。 ## 前提条件 @@ -19,7 +17,7 @@ ## 发送和接收文本消息 -1. 使用 `Message` 类创建并发送文本消息。示例代码如下: +使用 `Message` 类创建并发送文本消息。示例代码如下:// TODO:有类的概念吗? 默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 @@ -47,32 +45,11 @@ function sendTextMessage() { } ``` -2. 你可以通过 `addEventHandler` 注册监听器监听消息事件。你可以添加多个事件。当不再监听事件时,请确保删除监听器。 - -当消息到达时,接收方会收到 `onTextMessage` 回调。每个回调包含一条或多条消息。你可以遍历消息列表,并可以解析和展示回调中的消息。 - -对于聊天室消息,你可以通过消息的 `broadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - onTextMessage: function (message) {}, -}); -``` - -## 发送和接收附件消息 +## 发送附件消息 -语音、图片、视频和文件消息本质上是附件消息。发送和接收附件消息的流程如下: - -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器,获取消息的基本信息以及服务器上附件文件的路径。 - - 对于图片消息来说,环信服务器会自动生成图片缩略图;而对于视频消息来说,视频的首帧为缩略图。 - -2. 接收附件消息。 - - 接收方可以自行下载语音、图片、图片缩略图、视频和文件。 - -自 SDK 4.14.0 开始,支持消息附件下载鉴权功能。该功能默认关闭,如要开通需联系环信商务。该功能开通后,用户须调用 SDK 的 API `EC.utils.download` 下载消息附件。 +- 语音、图片、视频和文件消息本质上是附件消息。 +- 创建和发送附件类型消息。SDK 将附件上传到环信服务器,获取消息的基本信息以及服务器上附件文件的路径。 +- 对于图片消息,环信服务器会自动生成图片缩略图;对于视频消息,视频首帧为缩略图。 对于消息附件,你也可以将附件上传到自己的服务器,而不是环信服务器,然后发送消息。这种情况下,需要在 SDK 初始化时将 [`Connection` 类中的 `useOwnUploadFun` 参数](https://doc.easemob.com/jsdoc/classes/Connection.Connection-1.html)设置为 `true`。例如,对于图片消息,上传附件后,调用 `sendPrivateUrlImg` 方法传入图片的 URL 发送图片消息。 @@ -94,11 +71,10 @@ function sendPrivateUrlImg() { } ``` -### 发送和接收语音消息 - -发送语音消息前,你应该在 app 级别实现录音,提供录制的语音文件的 URI 和时长(单位为秒)。 +### 发送语音消息 -1. 创建和发送语音消息。 +1. 发送语音消息前,在 app 级别实现录音,提供录制的语音文件的 URI 和时长(单位为秒)。 +2. 创建和发送语音消息。 ```javascript function sendPrivateAudio() { @@ -152,27 +128,11 @@ function sendPrivateAudio() { } ``` -2. 接收方收到 `onAudioMessage` 回调,根据消息 `url` 字段获取语音文件的服务器地址,从而获取语音文件。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - // 当前用户收到语音消息。 - onAudioMessage: function (message) { - // 语音文件在服务器的地址。 - console.log(message.url); - }, -}); - -``` - -### 发送和接收图片消息 +### 发送图片消息 对于图片消息,服务器会根据用户设置的 `thumbnailHeight` 和 `thumbnailWidth` 参数自动生成图片的缩略图。若这两个参数未传,则图片的高度和宽度均默认为 170 像素。你也可以在 [环信即时通讯控制台](https://console.easemob.com/user/login)的 `服务概览` 页面的 `设置` 区域修改该默认值。 -发送和接收图片消息的流程如下: - -1. 创建和发送图片消息。 +创建和发送图片消息,示例代码如下所示: ```javascript function sendPrivateImg() { @@ -230,31 +190,15 @@ function sendPrivateImg() { } ``` -2. 接收方收到 `onImageMessage` 回调,根据消息 `url` 字段获取图片文件的服务器地址,从而获取图片文件。 +### 发送 GIF 图片消息 -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - // 当前用户收到图片消息。 - onImageMessage: function (message) { - // 图片文件在服务器的地址。 - console.log(message.url); - // 图片缩略图文件在服务器的地址。 - console.log(message.thumb); - }, -}); +- 自 SDK 4.14.0 开始,支持发送 GIF 图片消息。 +- GIF 图片消息是一种特殊的图片消息,在发送图片消息时可以指定是否是 GIF 图片。 +- GIF 图片缩略图的生成与普通图片消息相同,详见 [发送图片消息](#发送图片消息)。 -``` +发送 GIF 图片消息过程如下: -### 发送和接收 GIF 图片消息 - -自 SDK 4.14.0 开始,支持发送和接收 GIF 图片消息。 - -GIF 图片消息是一种特殊的图片消息,在发送图片消息时可以指定是否是 GIF 图片。 - -#### 发送 GIF 图片消息 - -1. 构造消息时,设置 `isGif` 为 `true`。 +1. 构造消息,设置 `isGif` 为 `true`。 2. 调用 `send` 方法发送消息。 ```javascript @@ -272,23 +216,10 @@ sendGIFMsg(){ } ``` -#### 接收 GIF 图片消息 +### 发送视频消息 -与普通消息相同,接收 GIF 图片消息时,接收方会收到 `onImageMessage` 回调方法。接收方收到消息后,读取消息体的 `isGif` 属性,若值是 `true`, 则为 GIF 图片消息。 - -```javascript -onImageMessage: (message) => { - if(message.isGif){ - // 图片为GIF - } -} -``` - -### 发送和接收视频消息 - -在发送视频消息之前,应在 app 级别实现视频捕获,获得捕获的视频文件的时长,单位为秒。 - -1. 创建和发送视频消息。服务器自动生成视频消息的缩略图,即视频的首帧。 +1. 发送视频消息之前,在 app 级别实现视频捕获,获得捕获的视频文件的时长,单位为秒。 +2. 创建和发送视频消息。服务器自动生成视频缩略图。 ```javascript function sendPrivateVideo() { @@ -342,25 +273,9 @@ function sendPrivateVideo() { } ``` -2. 接收方收到 `onVideoMessage` 回调,根据消息 `url` 字段获取视频文件的服务器地址,从而获取视频文件。 +### 发送文件消息 -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - // 当前用户收到视频消息。 - onVideoMessage: function (message) { - // 视频文件在服务器的地址。 - console.log(message.url); - // 视频首帧缩略图文件在服务器的地址。 - console.log(message.thumb); - }, -}); - -``` - -### 发送和接收文件消息 - -1. 创建和发送文件消息。 +创建和发送文件消息,示例代码如下: ```javascript function sendPrivateFile() { @@ -417,25 +332,9 @@ function sendPrivateFile() { } ``` -2. 接收方收到 `onFileMessage` 回调,根据消息 `url` 字段获取文件的服务器地址,从而获取文件。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - // 当前用户收到文件消息。 - onFileMessage: function (message) { - // 文件在服务器的地址。 - console.log(message.url); - }, -}); - -``` - -## 发送和接收位置消息 - -发送和接收位置消息的流程如下: +## 发送位置消息 -1. 创建和发送位置消息。 +创建和发送位置消息。 发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 @@ -465,17 +364,7 @@ const sendLocMsg = () => { } ``` -2. 接收方收到 `onLocationMessage` 回调,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - // 当前用户收到文件消息。 - onLocationMessage: function (message) {}, -}); -``` - -## 发送和接收透传消息 +## 发送透传消息 透传消息是通知指定用户采取特定操作的命令消息。接收方自己处理透传消息。 @@ -483,7 +372,7 @@ conn.addEventHandler("eventName", { 透传消息发送后,不支持撤回。 ::: -1. 创建和发送透传消息。 +创建和发送透传消息,示例代码如下: ```javascript function sendCMDMessage() { @@ -515,22 +404,11 @@ function sendCMDMessage() { } ``` -2. 接收方通过 `onCmdMessage` 回调接收透传消息。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - onCmdMessage: function (message) {}, -}); -``` - -## 发送和接收自定义消息 +## 发送自定义消息 自定义消息为用户自定义的键值对,包括消息类型和消息内容。 -发送和接收自定义消息的流程如下: - -1. 创建和发送自定义消息。 +创建和发送自定义消息,示例代码如下: ```javascript function sendCustomMsg() { @@ -567,16 +445,7 @@ function sendCustomMsg() { } ``` -2. 接收方通过 `onCustomMessage` 回调接收自定义消息。 - -```javascript -// 使用 `addEventHandler` 监听回调事件 -conn.addEventHandler("eventName", { - onCustomMessage: function (message) {}, -}); -``` - -## 发送和接收合并消息 +## 发送合并消息 为了方便消息互动,即时通讯 IM 自 4.2.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: @@ -584,8 +453,6 @@ conn.addEventHandler("eventName", { 2. 发送合并消息。 3. 对端收到合并消息后进行解析,获取原始消息列表。 -#### 创建和发送合并消息 - 你可以调用 `message.create` 方法创建一条合并消息,然后调用 `connection.send` 方法发送该条消息。 创建合并消息时,需要设置以下参数: @@ -639,102 +506,6 @@ conn.send }); ``` -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,唯一不同是对于合并消息来说,消息接收事件为 `onCombineMessage`。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `downloadAndParseCombineMessage` 方法下载合并消息附件并解析出原始消息列表。 - -```javascript -connection - .downloadAndParseCombineMessage({ - url: msg.url, - secret: msg.secret, - }) - .then((res) => { - console.log("合并消息解析后的消息列表", res); - }); -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 仅 SDK 4.1.7 及以上版本支持。 -2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置定向消息的接收方。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```javascript -// 发送定向文本消息。 -function sendTextMessage() { - let option = { - // 消息类型。 - type: "txt", - // 消息内容。 - msg: "message content", - // 消息接收方所在群组或聊天室的 ID。 - to: "groupId", - // 会话类型:群聊和聊天室分别为 `groupChat` 和 `chatRoom`。 - chatType: "groupChat", - // 消息的接收方列表。最多可传 20 个接收方的用户 ID。若不设置该字段或传入数组类型之外的值,如字符串,则消息发送给群组或聊天室的所有成员。 - receiverList: ['uId1','uId2'], - }; - // 创建文本消息。 - let msg = WebIM.message.create(option); - // 调用 `send` 方法发送该文本消息。 - conn.send(msg).then((res)=>{ - console.log("Send message success",res); - }).catch((e)=>{ - console.log("Send message fail",e); - }); -} -``` - -接收定向消息与接收普通消息的操作相同,详见各类消息的接收描述。 - -## 使用消息扩展 - -如果上述消息类型无法满足要求,你可以使用消息扩展为消息添加属性。这种情况可用于更复杂的消息传递场景,例如,消息中需要携带被回复的消息内容或者是图文消息等场景。 - -```javascript -function sendTextMessage() { - let option = { - type: "txt", - msg: "message content", - to: "username", - chatType: "singleChat", - // 设置消息扩展信息。扩展字段为可选,若带有该字段,值不能为空,即 "ext:null" 会出错。 - ext: { - key1: "Self-defined value1", - key2: { - key3: "Self-defined value3", - }, - }, - }; - let msg = WebIM.message.create(option); - // 调用 `send` 方法发送该扩展消息。 - conn - .send(msg) - .then((res) => { - console.log("send private text Success"); - }) - .catch((e) => { - console.log("Send private text error"); - }); -} -``` - ## 更多 ### 聊天室消息优先级与消息丢弃逻辑 diff --git a/docs/document/web/message_target.md b/docs/document/web/message_target.md new file mode 100644 index 000000000..5bf785809 --- /dev/null +++ b/docs/document/web/message_target.md @@ -0,0 +1,44 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 + +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 仅 SDK 4.1.7 及以上版本支持。 +2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置定向消息的接收方。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```javascript +// 发送定向文本消息。 +function sendTextMessage() { + let option = { + // 消息类型。 + type: "txt", + // 消息内容。 + msg: "message content", + // 消息接收方所在群组或聊天室的 ID。 + to: "groupId", + // 会话类型:群聊和聊天室分别为 `groupChat` 和 `chatRoom`。 + chatType: "groupChat", + // 消息的接收方列表。最多可传 20 个接收方的用户 ID。若不设置该字段或传入数组类型之外的值,如字符串,则消息发送给群组或聊天室的所有成员。 + receiverList: ['uId1','uId2'], + }; + // 创建文本消息。 + let msg = WebIM.message.create(option); + // 调用 `send` 方法发送该文本消息。 + conn.send(msg).then((res)=>{ + console.log("Send message success",res); + }).catch((e)=>{ + console.log("Send message fail",e); + }); +} +``` + +接收定向消息与接收普通消息的操作相同,详见 [各类消息的接收描述](message_receive.html)。 \ No newline at end of file diff --git a/docs/document/windows/message_extension.md b/docs/document/windows/message_extension.md new file mode 100644 index 000000000..1e2f6e572 --- /dev/null +++ b/docs/document/windows/message_extension.md @@ -0,0 +1,34 @@ +# 消息扩展 + +当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型,例如消息中需要携带被回复的消息内容或者是图文消息等场景。 + +```csharp +Message msg = Message.CreateTextSendMessage(toChatUsername, content); + +// 增加自定义属性。 +AttributeValue attr1 = AttributeValue.Of("value", AttributeValueType.STRING); +AttributeValue attr2 = AttributeValue.Of(true, AttributeValueType.BOOL); +msg.Attributes.Add("attribute1", attr1); +msg.Attributes.Add("attribute2", attr2); + +// 发送消息。 +SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + Debug.Log($"{msg.MsgId}发送成功"); + }, + onError:(code, desc) => { + Debug.Log($"{msg.MsgId}发送失败,errCode={code}, errDesc={desc}"); + } +)); +// 接收消息的时候获取扩展属性。 +bool found = false; +string str = Message.GetAttributeValue(msg.Attributes, "attribute1", out found); +if (found) { + // 使用 str 变量。 +} +found = false; +bool b = Message.GetAttributeValue(msg.Attributes, "attribute2", out found); +if (found) { + // 使用 b 变量。 +} +``` \ No newline at end of file diff --git a/docs/document/windows/message_receive.md b/docs/document/windows/message_receive.md new file mode 100644 index 000000000..37900196d --- /dev/null +++ b/docs/document/windows/message_receive.md @@ -0,0 +1,270 @@ +# 接收消息 + +环信即时通讯 IM Unity SDK 通过 `IChatManagerDelegate` 类实现文本、图片、音频、视频和文件等类型的消息的接收。 + +## 前提条件 + +开始前,请确保满足以下条件: + +- 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 +- 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 + +## 接收文本消息 + +- 你可以用注册监听 `IChatManagerDelegate` 接收消息。该 `IChatManagerDelegate` 可以多次添加,请记得在不需要的时候移除该监听。如在析构 `IChatManagerDelegate` 的继承实例之前。 +- 在新消息到来时,你会收到 `OnMessagesReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `Options#IncludeSendMessageInMessageListener` 开关,则该回调中会返回发送成功的消息。 +- 对于聊天室消息,你可以通过消息的 `Message#Broadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 + +```csharp +//继承并实现 IChatManagerDelegate。 +public class ChatManagerDelegate : IChatManagerDelegate { + + //实现 OnMessagesReceived 回调。 + public void OnMessagesReceived(List messages) + { + //收到消息,遍历消息列表,解析和显示。 + } +} + +//申请并注册监听。 +ChatManagerDelegate adelegate = new ChatManagerDelegate(); +SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + +//移除监听。 +SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); +``` + +## 接收附件消息 + +除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 + +附件消息的接收过程如下: + +1. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `DownloadAttachment` 方法。 + +2. 获取附件的服务器地址和本地路径。 + +### 接收语音消息 + +1. 接收方收到语音消息时,自动下载语音文件。 + +2. 接收方收到 [OnMessagesReceived](#接收文本消息) 回调,获取语音文件的服务器地址或本地路径,从而获取语音文件。 + +```csharp + +foreach (var msg in messages) +{ + if (msg != null) + { + ChatSDK.MessageBody.VoiceBody vb = (ChatSDK.MessageBody.VoiceBody)msg.Body; + + //语音文件在服务器的路径。 + string voiceRemoteUrl = vb.RemotePath; + + //语音文件的本地路径。 + string voiceLocalUri = vb.LocalPath; + } + else { + Debug.Log($"未找到消息"); + } +} + +``` + +### 接收图片消息 + +1. 接收方收到图片消息,自动下载图片缩略图。 + +2. 图片消息的接收与文本消息一致,详见 [接收文本消息](#接收文本消息)。 + + 接收方收到图片消息后,参考如下示例代码获取图片消息的缩略图和附件。 + +- 接收方如果设置了自动下载,即 `Options.IsAutoDownload` 为 `true`,SDK 接收到消息后会下载缩略图。 + +- 如果未设置自动下载,需主动调用 `SDKClient.Instance.ChatManager.DownloadAttachment` 下载。 + +3. 使用`DownloadAttachment`下载完成后,可获取消息的图片文件和缩略图。 + +```csharp + +SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack( + onSuccess: () => { + Debug.Log($"下载附件成功"); + + Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); + if (msg != null) + { + ChatSDK.MessageBody.ImageBody ib = (ChatSDK.MessageBody.ImageBody)msg.Body; + + //服务器端图片文件路径。 + string imgRemoteUrl = ib.RemotePath; + + //服务器端图片缩略图路径。 + string thumbnailUrl = ib.ThumbnaiRemotePath; + + //本地图片文件路径。 + string imgLocalUri = ib.LocalPath; + + //本地图片缩略图路径。 + Uri thumbnailLocalUri = ib.ThumbnailLocalPath; + + } + else { + Debug.Log($"未找到消息"); + } + + }, + onProgress: (progress) => { + Debug.Log($"下载附件进度 {progress}"); + }, + onError: (code, desc) => { + Debug.Log($"附件下载失败,errCode={code}, errDesc={desc}"); + } +)); + +``` + +### 接收视频消息 + +1. 接收方收到视频消息时,自动下载视频缩略图。 + + 你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见 [设置图片缩略图自动下载](#接收图片消息)。 + +2. 接收方收到 [OnMessageReceive](#接收文本消息) 回调,可以调用 `SDKClient.Instance.ChatManager.DownloadAttachment` 下载视频附件。下载完成后,使用相应消息 `Body` 的 `LocalPath` 成员获取视频文件路径。 + +```csharp +// 接收到视频消息需先下载附件才能打开。 +SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack( + onSuccess: () => { + Debug.Log($"下载附件成功"); + + Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); + if (msg != null) + { + if (msg.Body.Type == ChatSDK.MessageBodyType.VIDEO) { + ChatSDK.MessageBody.VideoBody vb = (ChatSDK.MessageBody.VideoBody)msg.Body; + //从本地获取视频文件路径。 + string videoLocalUri = vb.LocalPath; + //这里可以根据本地路径打开文件。 + } + } + else { + Debug.Log($"未找到消息"); + } + + }, + onProgress: (progress) => { + Debug.Log($"下载附件进度 {progress}"); + }, + onError: (code, desc) => { + Debug.Log($"附件下载失败,errCode={code}, errDesc={desc}"); + } +)); +``` + +### 接收文件消息 + +接收方收到 [OnMessageReceive 回调](#接收文本消息),调用 `DownloadAttachment` 方法下载文件。 + +```csharp +/** + * 下载文件。 + */ +SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack( + onSuccess: () => { + Debug.Log($"下载附件成功"); + + Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); + if (msg != null) + { + ChatSDK.MessageBody.FileBody fb = (ChatSDK.MessageBody.FileBody)msg.Body; + + //服务器文件路径。 + string fileRemoteUrl = fb.RemotePath; + + //本地文件路径。 + string fileLocalUri = fb.LocalPath; + + } + else { + Debug.Log($"未找到消息"); + } + + }, + onProgress: (progress) => { + Debug.Log($"下载附件进度 {progress}"); + }, + onError: (code, desc) => { + Debug.Log($"附件下载失败,errCode={code}, errDesc={desc}"); + } +)); +``` + +## 接收位置消息 + +接收位置消息与文本消息一致,详见[接收文本消息](#接收文本消息)。 + +接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 + +## 接收透传消息 + +透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 + +具体功能可以根据自身业务需求自定义,例如实现头像、昵称的更新等。另外,以 `em_` 和 `easemob::` 开头的 action 为内部保留字段,注意不要使用。 + +:::tip +- 透传消息发送后,不支持撤回。 +- 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 +::: + +接收方通过 `OnMessagesReceived` 和 `OnCmdMessagesReceived` 回调接收透传消息,方便用户进行不同的处理。 + +```csharp +// 继承并实现 `IChatManagerDelegate`。 +public class ChatManagerDelegate : IChatManagerDelegate { + + // 收到消息。 + public void OnMessagesReceived(List messages) + { + // 收到消息,遍历消息列表,解析和显示。 + } + // 收到透传消息。 + void OnCmdMessagesReceived(List messages) + { + // 收到消息,遍历消息列表,解析和处理。 + } +} + +// 申请并注册监听。 +ChatManagerDelegate adelegate = new ChatManagerDelegate() +SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); + +``` + +## 接收自定义类型消息 + +除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 + +接收自定义消息与其他类型消息一致,详见[接收文本消息](#接收文本消息)。 + +## 接收合并消息 + +接收合并消息与接收普通消息的操作相同,详见[接收消息](#接收文本消息)。 + +- 对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 +- 合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `FetchCombineMessageDetail` 方法下载合并消息附件并解析出原始消息列表。 +- 对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: + - 若附件已存在,该方法会直接解析附件并返回原始消息列表。 + - 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 + +```csharp +SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( + onSuccess: (list) => { + // 处理并展示消息列表 + }, + onError: (code, desc) => { + // 处理出错信息 + } +)); +``` + diff --git a/docs/document/windows/message_send_receive.md b/docs/document/windows/message_send.md similarity index 54% rename from docs/document/windows/message_send_receive.md rename to docs/document/windows/message_send.md index 2764096ed..0165df1c1 100644 --- a/docs/document/windows/message_send_receive.md +++ b/docs/document/windows/message_send.md @@ -1,8 +1,8 @@ -# 发送和接收消息 +# 发送消息 -环信即时通讯 IM Unity SDK 通过 `IChatManager` 和 `Message` 类实现文本、图片、音频、视频和文件等类型的消息的发送和接收。 +环信即时通讯 IM Unity SDK 通过 `IChatManager` 和 `Message` 类实现文本、图片、音频、视频和文件等类型的消息的发送。 -- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要[开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 +- 对于单聊,环信即时通信 IM 默认支持陌生人之间发送消息,即无需添加好友即可聊天。若仅允许好友之间发送单聊消息,你需要 [开启好友关系检查](/product/enable_and_configure_IM.html#好友关系检查)。 - 对于群组和聊天室,用户每次只能向所属的单个群组和聊天室发送消息。 @@ -15,9 +15,9 @@ - 完成 SDK 初始化,详见 [初始化文档](initialization.html)。 - 了解环信即时通讯 IM 的使用限制,详见 [使用限制](/product/limitation.html)。 -## 发送和接收文本消息 +## 发送文本消息 -1. 你可以利用 `Message` 类构造一个消息,然后通过 `IChatManager` 将该消息发出。 +你可以利用 `Message` 类构造一个消息,然后通过 `IChatManager` 将该消息发出。 默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。 @@ -49,44 +49,20 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 你可以用注册监听 `IChatManagerDelegate` 接收消息。该 `IChatManagerDelegate` 可以多次添加,请记得在不需要的时候移除该监听。如在析构 `IChatManagerDelegate` 的继承实例之前。 - -在新消息到来时,你会收到 `OnMessagesReceived` 的回调,消息接收时可能是一条,也可能是多条。你可以在该回调里遍历消息队列,解析并显示收到的消息。若在初始化时打开了 `Options#IncludeSendMessageInMessageListener` 开关,则该回调中会返回发送成功的消息。 - -对于聊天室消息,你可以通过消息的 `Message#Broadcast` 属性判断该消息是否为[通过 REST API 发送的聊天室全局广播消息](/document/server-side/message_broadcast.html#发送聊天室全局广播消息)。 - -```csharp -//继承并实现 IChatManagerDelegate。 -public class ChatManagerDelegate : IChatManagerDelegate { - - //实现 OnMessagesReceived 回调。 - public void OnMessagesReceived(List messages) - { - //收到消息,遍历消息列表,解析和显示。 - } -} - -//申请并注册监听。 -ChatManagerDelegate adelegate = new ChatManagerDelegate(); -SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); - -//移除监听。 -SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate); -``` - -## 发送和接收附件消息 +## 发送接收附件消息 除文本消息外,SDK 还支持发送附件类型消息,包括语音、图片、视频和文件消息。 附件消息的发送和接收过程如下: -1. 创建和发送附件类型消息。SDK 将附件上传到环信服务器。 -2. 接收附件消息。SDK 自动下载语音消息,默认自动下载图片和视频的缩略图。若下载原图、视频和文件,需调用 `DownloadAttachment` 方法。 -3. 获取附件的服务器地址和本地路径。 +1. 创建和发送附件类型消息。 +2. SDK 将附件上传到环信服务器。 -### 发送和接收语音消息 +### 发送语音消息 -发送语音消息时,应用层需完成语音文件录制的功能,提供语音文件的 URI 和语音时长。 +1. 发送语音消息前,在应用层录制语音文件。 +2. 发送方调用 `Message#CreateVoiceSendMessage` 方法传入语音文件的 URI、本地语音文件路径、语音时长和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)创建语音消息。 +3. 发送方调用 `ChatManager#SendMessage` 方法发送消息。SDK 会将语音文件上传至环信服务器。 参考如下示例代码创建并发送语音消息: @@ -115,34 +91,14 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -语音消息的接收与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -接收方收到语音消息后,参考如下示例代码获取语音消息的附件: - -```csharp -// 注意:这里的 "Message ID" 是消息发送成功以后(CallBack 中的 onSuccess 被触发以后),被发送消息的 ID。 -Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); -if (msg != null) -{ - ChatSDK.MessageBody.VoiceBody vb = (ChatSDK.MessageBody.VoiceBody)msg.Body; - - //语音文件在服务器的路径。 - string voiceRemoteUrl = vb.RemotePath; - - //语音文件的本地路径。 - string voiceLocalUri = vb.LocalPath; -} -else { - Debug.Log($"未找到消息"); -} -``` - -### 发送和接收图片消息 +### 发送图片消息 -1. 创建并发送图片消息。 +1. 发送方调用 `Message#CreateImageSendMessage` 方法传入图片的本地资源路径、设置是否发送原图以及接收方的用户 ID 等参数创建图片消息。 图片消息默认会被压缩后发出,可通过设置 `original` 参数为 `true` 发送原图。 +2. 发送方调用 `ChatManager#SendMessage` 方法发送消息。SDK 会将图片文件上传至环信服务器。 + ```csharp //`localPath` 为图片本地资源路径。 //`displayName` 为图片显示名称。 @@ -170,45 +126,15 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 图片消息的接收与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -接收方收到图片消息后,参考如下示例代码获取图片消息的缩略图和附件。 - -- 接收方如果设置了自动下载,即 `Options.IsAutoDownload` 为 `true`,SDK 接收到消息后会下载缩略图 -- 如果未设置自动下载,需主动调用 `SDKClient.Instance.ChatManager.DownloadThumbnail` 下载。 - -下载完成后,调用相应消息 `msg.Body` 的 `ThumbnailLocalPath` 获取缩略图路径。 - -```csharp -//注意:这里的 "Message ID" 是消息发送成功以后(`CallBack` 中的 `onSuccess` 被触发以后),被发送消息的 ID。 -Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); -if (msg != null) -{ - ChatSDK.MessageBody.ImageBody ib = (ChatSDK.MessageBody.ImageBody)msg.Body; - - //服务器端图片文件路径。 - string imgRemoteUrl = ib.RemotePath; - - //服务器端图片缩略图路径。 - string thumbnailUrl = ib.ThumbnaiRemotePath; +### 发送视频消息 - //本地图片文件路径。 - string imgLocalUri = ib.LocalPath; - - //本地图片缩略图路径。 - Uri thumbnailLocalUri = ib.ThumbnailLocalPath; - -} -else { - Debug.Log($"未找到消息"); -} -``` - -### 发送和接收视频消息 +1. 发送视频消息前,在应用层完成视频文件的选取或者录制。 发送视频消息时,应用层需要完成视频文件的选取或者录制。视频消息支持给出视频的时长作为参数,发送给接收方。 -1. 创建并发送视频消息: +2. 发送方调用 `Message#CreateVideoSendMessage` 方法传入视频文件的本地资源标志符、缩略图的本地存储路径、视频时长以及接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID) 创建视频消息。若需要视频缩略图,你需自行获取视频首帧的路径,将该路径传入 `thumbnailLocalPath` 方法。 + +3. 发送方调用 `ChatManager#SendMessage` 方法发送视频消息。SDK 会将视频文件上传至消息服务器。 ```csharp Message msg = Message.CreateVideoSendMessage(toChatUsername, localPath, displayName, thumbnailLocalPath, fileSize, duration, width, height); @@ -228,43 +154,11 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 接收方收到视频消息时,自动下载视频缩略图。你可以设置自动或手动下载视频缩略图,该设置与图片缩略图相同,详见[设置图片缩略图自动下载](#发送和接收图片消息)。 - -视频文件本身需要通过 `SDKClient.Instance.ChatManager.DownloadAttachment` 下载,下载完成后,使用相应消息 `Body` 的 `LocalPath` 成员获取视频文件路径。 - -```csharp -// 接收到视频消息需先下载附件才能打开。 -SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack( - onSuccess: () => { - Debug.Log($"下载附件成功"); - - Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); - if (msg != null) - { - if (msg.Body.Type == ChatSDK.MessageBodyType.VIDEO) { - ChatSDK.MessageBody.VideoBody vb = (ChatSDK.MessageBody.VideoBody)msg.Body; - //从本地获取视频文件路径。 - string videoLocalUri = vb.LocalPath; - //这里可以根据本地路径打开文件。 - } - } - else { - Debug.Log($"未找到消息"); - } - - }, - onProgress: (progress) => { - Debug.Log($"下载附件进度 {progress}"); - }, - onError: (code, desc) => { - Debug.Log($"附件下载失败,errCode={code}, errDesc={desc}"); - } -)); -``` - -### 发送和接收文件消息 +### 发送文件消息 -1. 创建并发送文件消息。 +1. 发送方调用 `Message#CreateFileSendMessage` 方法传入文件的本地资源标志符和接收方的用户 ID(群聊或聊天室分别为群组 ID 或聊天室 ID)等参数创建文件消息。 + +2. 发送方调用 `ChatManager#SendMessage` 方法发送文件消息。SDK 将文件上传至环信服务器。 ```csharp // localPath 为文件本地路径,displayName 为消息显示名称,fileSize 为文件大小。 @@ -287,34 +181,15 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( Debug.Log($"{msg.MsgId}发送失败,errCode={code}, errDesc={desc}"); } )); - -// 发送成功后,获取文件消息附件。 -// 注意:这里的 "Message ID" 是消息发送成功以后(CallBack 中的 onSuccess 被触发以后),被发送消息的 ID。 -Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID"); -if (msg != null) -{ - ChatSDK.MessageBody.FileBody fb = (ChatSDK.MessageBody.FileBody)msg.Body; - - //服务器文件路径。 - string fileRemoteUrl = fb.RemotePath; - - //本地文件路径。 - string fileLocalUri = fb.LocalPath; - -} -else { - Debug.Log($"未找到消息"); -} - ``` -2. 文件消息的接收与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 +## 发送位置消息 -## 发送和接收位置消息 +1. 发送方调用 `Message#CreateLocationSendMessage` 方法创建位置消息。 + +2. 发送方调用 `ChatManager#SendMessage` 方法发送位置消息。 -1. 创建和发送位置消息。 - -发送位置时,需要集成第三方的地图服务,获取到位置点的经纬度信息。 +发送位置时,需要集成第三方地图服务,获取到位置点的经纬度信息。 ```csharp //`latitude` 为纬度,`longitude` 为经度,`locationAddress` 为具体位置内容,`buildingName` 为建筑名称。 @@ -330,11 +205,7 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 接收位置消息与文本消息一致,详见[接收文本消息](#发送和接收文本消息)。 - - 接收方接收到位置消息时,需要将该位置的经纬度,借由第三方的地图服务,将位置在地图上显示出来。 - -## 发送和接收透传消息 +## 发送透传消息 透传消息可视为命令消息,通过发送这条命令给对方,通知对方要进行的操作,收到消息可以自定义处理。 @@ -345,7 +216,11 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - 透传消息不会存入本地数据库中,所以在 UI 上不会显示。 ::: -1. 创建和发送透传消息。 +发送透传消息的过程如下: + +1. 发送方调用 `Message#CreateCmdSendMessage` 方法创建透传消息。 + +2. 发送方调用 `ChatManager#SendMessage` 方法发送透传消息。 ```csharp //`action` 可以自定义。 @@ -361,35 +236,13 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 接收方通过 `OnMessagesReceived` 和 `OnCmdMessagesReceived` 回调接收透传消息,方便用户进行不同的处理。 - -```csharp -// 继承并实现 `IChatManagerDelegate`。 -public class ChatManagerDelegate : IChatManagerDelegate { - - // 收到消息。 - public void OnMessagesReceived(List messages) - { - // 收到消息,遍历消息列表,解析和显示。 - } - // 收到透传消息。 - void OnCmdMessagesReceived(List messages) - { - // 收到消息,遍历消息列表,解析和处理。 - } -} - -// 申请并注册监听。 -ChatManagerDelegate adelegate = new ChatManagerDelegate() -SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate); - -``` - -## 发送和接收自定义类型消息 +## 发送自定义类型消息 除了几种消息之外,你可以自己定义消息类型,方便业务处理,即首先设置一个消息类型名称,然后可添加多种自定义消息。 -1. 创建和发送自定义类型消息的示例代码: +1. 发送方调用 `Message#CreateCustomSendMessage` 方法创建自定义消息。 + +2. 发送方调用 `ChatManager#SendMessage` 方法发送自定义消息。 ```csharp //`event` 为字符串类型的自定义事件,比如礼物消息,可以设置: @@ -410,17 +263,12 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -2. 接收自定义消息与其他类型消息一致,详见[接收文本消息](#发送和接收文本消息)。 - -## 发送和接收合并消息 +## 发送合并消息 为了方便消息互动,即时通讯 IM 自 1.2.0 版本开始支持将多个消息合并在一起进行转发。你可以采取以下步骤进行消息的合并转发: 1. 利用原始消息列表创建一条合并消息。 2. 发送合并消息。 -3. 对端收到合并消息后进行解析,获取原始消息列表。 - -#### 创建和发送合并消息 你可以调用 `CreateCombineSendMessage` 方法创建一条合并消息,然后调用 `SendMessage` 方法发送该条消息。 @@ -458,111 +306,6 @@ SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( )); ``` -#### 接收和解析合并消息 - -接收合并消息与接收普通消息的操作相同,详见[接收消息](#发送和接收文本消息)。 - -对于不支持合并转发消息的 SDK 版本,该类消息会被解析为文本消息,消息内容为 `compatibleText` 携带的内容,其他字段会被忽略。 - -合并消息实际上是一种附件消息。收到合并消息后,你可以调用 `FetchCombineMessageDetail` 方法下载合并消息附件并解析出原始消息列表。 - -对于一条合并消息,首次调用该方法会下载和解析合并消息附件,然后返回原始消息列表,而后续调用会存在以下情况: - -- 若附件已存在,该方法会直接解析附件并返回原始消息列表。 -- 若附件不存在,该方法首先下载附件,然后解析附件并返回原始消息列表。 - -```csharp -SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>( - onSuccess: (list) => { - // 处理并展示消息列表 - }, - onError: (code, desc) => { - // 处理出错信息 - } -)); -``` - -## 发送和接收定向消息 - -发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 - -该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 - -:::tip -1. 仅 SDK 1.2.0 及以上版本支持。 -2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息计数。 -3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 -4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 -::: - -发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: - -1. 创建一条群组或聊天室消息。 -2. 设置消息的接收方。 -3. 发送定向消息。 - -下面以文本消息为例介绍如何发送定向消息,示例代码如下: - -```csharp -// 创建一条文本消息。 -Message msg = Message.CreateTextSendMessage(groupId, content); -// 会话类型:群组和聊天室聊天,分别为 `Group` 和 `Room`。 -msg.MessageType = MessageType.Group; - -List receives = new List(); -receives.Add("userId1"); -receives.Add("userId2"); - -// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`或者包含接收Id数目为0,则消息发送给群组或聊天室的所有成员。 -msg.ReceiverList = receives; - -SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - onSuccess: () => { - - }, - onError: (code, desc) => { - - } -)); -``` - -接收群定向消息与接收普通消息的操作相同,详见[接收文本消息](#发送和接收文本消息)。 - -## 使用消息扩展字段 - -当 SDK 提供的消息类型不满足需求时,你可以通过消息扩展字段传递自定义的内容,从而生成自己需要的消息类型,例如,消息中需要携带被回复的消息内容或者是图文消息等场景。 - -```csharp -Message msg = Message.CreateTextSendMessage(toChatUsername, content); - -// 增加自定义属性。 -AttributeValue attr1 = AttributeValue.Of("value", AttributeValueType.STRING); -AttributeValue attr2 = AttributeValue.Of(true, AttributeValueType.BOOL); -msg.Attributes.Add("attribute1", attr1); -msg.Attributes.Add("attribute2", attr2); - -// 发送消息。 -SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( - onSuccess: () => { - Debug.Log($"{msg.MsgId}发送成功"); - }, - onError:(code, desc) => { - Debug.Log($"{msg.MsgId}发送失败,errCode={code}, errDesc={desc}"); - } -)); -// 接收消息的时候获取扩展属性。 -bool found = false; -string str = Message.GetAttributeValue(msg.Attributes, "attribute1", out found); -if (found) { - // 使用 str 变量。 -} -found = false; -bool b = Message.GetAttributeValue(msg.Attributes, "attribute2", out found); -if (found) { - // 使用 b 变量。 -} -``` - ## 更多 ### 聊天室消息优先级与消息丢弃逻辑 diff --git a/docs/document/windows/message_target.md b/docs/document/windows/message_target.md new file mode 100644 index 000000000..7b00e17c7 --- /dev/null +++ b/docs/document/windows/message_target.md @@ -0,0 +1,45 @@ +# 定向消息 + +发送定向消息是指向群组或聊天室的单个或多个指定的成员发送消息,其他成员不会收到该消息。 + +该功能适用于文本消息、图片消息和音视频消息等全类型消息,最多可向群组或聊天室的 20 个成员发送定向消息。 + +:::tip +1. 仅 SDK 1.2.0 及以上版本支持。 +2. 定向消息不写入服务端会话列表,不计入服务端会话的未读消息计数。 +3. 群组定向消息的漫游功能默认关闭,使用前需联系商务开通。 +4. 聊天室定向消息的漫游功能默认关闭,使用前需联系商务开通聊天室消息漫游和定向消息漫游功能。 +::: + +发送定向消息的流程与发送普通消息相似,唯一区别是需要设置消息的接收方,具体操作如下: + +1. 创建一条群组或聊天室消息。 +2. 设置消息的接收方。 +3. 发送定向消息。 + +下面以文本消息为例介绍如何发送定向消息,示例代码如下: + +```csharp +// 创建一条文本消息。 +Message msg = Message.CreateTextSendMessage(groupId, content); +// 会话类型:群组和聊天室聊天,分别为 `Group` 和 `Room`。 +msg.MessageType = MessageType.Group; + +List receives = new List(); +receives.Add("userId1"); +receives.Add("userId2"); + +// 设置消息接收方列表。最多可传 20 个接收方的用户 ID。若传入 `null`或者包含接收Id数目为0,则消息发送给群组或聊天室的所有成员。 +msg.ReceiverList = receives; + +SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack( + onSuccess: () => { + + }, + onError: (code, desc) => { + + } +)); +``` + +接收群定向消息与接收普通消息的操作相同,详见 [接收文本消息](message_receive.html#接收文本消息)。 \ No newline at end of file From 13c10ef2a86319e1776908a0d83cdcac55eab3da Mon Sep 17 00:00:00 2001 From: haoxiuwen Date: Thu, 19 Jun 2025 08:56:47 +0800 Subject: [PATCH 3/3] modify --- docs/document/flutter/demo.md | 2 +- docs/document/web/message_send.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/document/flutter/demo.md b/docs/document/flutter/demo.md index 164c7ff31..198a4ce25 100644 --- a/docs/document/flutter/demo.md +++ b/docs/document/flutter/demo.md @@ -60,7 +60,7 @@ App Server 为 Demo 提供以下功能: ## Demo 项目结构 ``` -. + ├── custom │ └── chat_route_filter.dart // chat-uikit 自定义拦截类,所有对 chat-uikit 的自定义通过该文件实现。 ├── demo_config.dart // Demo 运行的配置类,包含 appkey, agoraAppId, appServer diff --git a/docs/document/web/message_send.md b/docs/document/web/message_send.md index eeaf8fd07..d2f2bbedf 100644 --- a/docs/document/web/message_send.md +++ b/docs/document/web/message_send.md @@ -17,7 +17,7 @@ ## 发送和接收文本消息 -使用 `Message` 类创建并发送文本消息。示例代码如下:// TODO:有类的概念吗? +使用 `Message` 类创建并发送文本消息。示例代码如下: 默认情况下,SDK 对单个用户发送消息的频率未做限制。如果你联系了环信商务设置了该限制,一旦在单聊、群聊或聊天室中单个用户的消息发送频率超过设定的上限,SDK 会上报错误,即错误码 509 `MESSAGE_CURRENT_LIMITING`。