消息接收(已不再维护)
更新时间: 2022/09/30 17:04:08
SDK 提供一套完善的消息传输管理服务,包括收发消息,存储消息,上传下载附件等。支持发送文本,语音,图片,视频,文件,地理位置等类型消息,同时支持用户发送自定义类型的消息。
SDK 中用于表示消息的结构为 IMMessage
,不同消息类型以 MsgTypeEnum
作区分。IMMessage
不支持继承扩展。
参数说明及消息发送、重发、撤回、语音消息等相关说明请查看消息发送。
消息接收
添加消息接收观察者 MsgServiceObserve#observeReceiveMessage
,在有新消息到达时,第三方 APP 就可以接收到通知。
- API 原型
/**
* 注册/注销消息接收观察者。
* 通知的消息列表中的消息不一定全是接收的消息,也有可能是自己发出去,比如其他端发的消息漫游过来,
* 或者调用MsgService#saveMessageToLocal(IMMessage, boolean)后,notify参数设置为true,通知出来的消息。
* @param observer 观察者, 参数为收到的消息列表,消息列表中的消息均保证来自同一个聊天对象。
* @param register true为注册,false为注销
*/
public void observeReceiveMessage(Observer<List<IMMessage>> observer, boolean register);
- 示例
Observer<List<IMMessage>> incomingMessageObserver =
new Observer<List<IMMessage>>() {
@Override
public void onEvent(List<IMMessage> messages) {
// 处理新收到的消息,为了上传处理方便,SDK 保证参数 messages 全部来自同一个聊天对象。
}
}
NIMClient.getService(MsgServiceObserve.class)
.observeReceiveMessage(incomingMessageObserver, true);
通知类消息接收
一些特定场景的行为,云信服务器预置了一些通知消息。通知消息也是一种特定消息,开发者需要解析消息中附带的信息,来获取通知内容。如最常见的通知消息是群通知事件,如有新成员进群,则群内已有成员将收到此通知消息。目前不支持从客户端发出通知消息。
通知消息属于会话内的一种消息,其对应的数据结构为 IMMessage
,消息类型为 MsgTypeEnum.notification
。目前用于群通知和聊天室通知事件。
通知消息需要进行解析,具体参见群组通知消息。
多媒体类消息接收
多媒体类消息,如语音消息、图片消息、文件消息和视频消息,需要考虑收到消息后下载资源的情况。 针对使用云信上传服务的多媒体类消息:
- 如果收到的是图片,视频消息,SDK默认会在收到消息时,自动下载缩略图和封面图片。
- 如果收到的是语音消息,SDK默认会在收到消息时,自动下载原音频。
- 如果收到的是文件消息,不会下载原文件。
若要关闭默认策略,自主选择下载时机,可以使用以下方法来完成:
- 关闭自动下载
修改初始化配置参数 SDKOptions - preloadAttach
为 false 。
- 主动下载附件:
原型
/**
* 正常情况收到消息后附件会自动下载。如果下载失败,可调用该接口重新下载
*
* @param msg 附件所在的消息体
* @param thumb 是否只下载缩略图。为true时,仅下载缩略图。
* 该参数仅对图片和视频类消息有效
* @return AbortableFuture 调用跟踪。可设置回调函数,可中止下载操作
*/
public AbortableFuture<Void> downloadAttachment(IMMessage msg, boolean thumb);
- 参数说明
参数 | 说明 |
---|---|
msg | 附件所在的消息体 |
thumb | 是否只下载缩略图。为 true 时,仅下载缩略图。该参数仅对图片和视频类消息有效 |
- 示例
// 下载之前判断一下是否已经下载。若重复下载,会报错误码414。(以SnapChatAttachment为例)
private boolean isOriginImageHasDownloaded(final IMMessage message) {
if (message.getAttachStatus() == AttachStatusEnum.transferred &&
!TextUtils.isEmpty(((SnapChatAttachment) message.getAttachment()).getPath())) {
return true;
}
return false;
}
// 因为下载的文件可能会很大,这个接口返回类型为 AbortableFuture ,允许用户中途取消下载。
AbortableFuture future = NIMClient.getService(MsgService.class).downloadAttachment(message, false);
- 附件参数说明
下载完成后,可以通过对应的MsgAttachment获取到具体的附件内容。多媒体附件的基类是 FileAttachment,继承自 MsgAttachment。它的子类主要有:
- 视频消息附件 VideoAttachment
- 图片消息附件 ImageAttachment
- 音频消息附件 AudioAttachment
以 FileAttachment 为例,说明附件参数:
返回值 | FileAttachment 接口 | 说明 |
---|---|---|
String | getPath() | 获取文件本地路径,若文件不存在,返回 null。 语音消息的文件路径,在附件下载完成之后可以获取。 图片或视频的文件路径,需要手动下载之后获取,收到消息时,SDK 只默认自动下载缩略图文件 |
String | getPathForSave() | 获取用于保存该文件的位置 |
String | getThumbPath() | 获取缩略图文件的本地路径,若文件不存在,返回 null。 当消息状态显示缩略图下载完成之后,可获取缩略图文件路径 |
String | getThumbPathForSave() | 获取用于保存缩略图文件的位置 |
void | setPath(String path) | 设置文件路径 |
long | getSize() | 获取文件大小,单位为byte |
void | setSize(long size) | 设置文件大小,单位为 byte |
String | getMd5() | 获取文件内容 MD5 |
void | setMd5(String md5) | 设置文件内容 MD5 |
String | getUrl() | 获取文件在服务器上的下载 url。若文件还未上传,返回 null |
void | setUrl(String url) | 设置文件在服务器上下载 url |
String | getExtension() | 获取文件后缀名 |
void | setExtension(String extension) | 设置文件后缀名 |
String | getFileName() | 获取文件名 |
String | getDisplayName() | 获取文件的显示名。可以和文件名不同,仅用于界面展示 |
String | setDisplayName() | 设置文件显示名 |
其他类型附件属性详见客户端API文档。
监听消息状态
该接口可以监听消息接收或发送状态 MsgStatusEnum 和 消息附件接收或发送状态 AttachStatusEnum 的变化。当状态更改为 AttachStatusEnum.transferred 表示附件下载成功。
- 原型
/**
* 注册/注销消息状态变化观察者
* @param observer 观察者, 参数为改变的消息体,更改的状态可能包含status和attachStatus
* @param register true为注册,false为注销
*/
public void observeMsgStatus(Observer<IMMessage> observer, boolean register);
- 参数说明
MsgStatusEnum 属性说明
MsgStatusEnum 属性说明 | 说明 |
---|---|
draft | 草稿 |
sending | 正在发送中 |
success | 发送成功 |
fail | 发送失败 |
read | 一般用于收到的音频消息,当前登录用户有无听过 |
unread | 未读状态 |
AttachStatusEnum 属性说明
AttachStatusEnum 属性说明 | 说明 |
---|---|
def | 默认状态,未开始 |
transferring | 正在传输 |
transferred | 传输成功, 附件下载成功标志 |
fail | 传输失败 |
- 示例
// 监听消息状态变化
NIMClient.getService(MsgServiceObserve.class).observeMsgStatus(statusObserver, register);
private Observer<IMMessage> statusObserver = new Observer<IMMessage>() {
@Override
public void onEvent(IMMessage msg) {
// 1、根据sessionId判断是否是自己的消息
// 2、更改内存中消息的状态
// 3、刷新界面
}
};
聊天室接收消息
详见聊天室章节。
消息过滤
SDK提供消息过滤忽略的功能。消息过滤后,SDK将不存储对应的消息,也不会上抛给接收回调,因此应用层不会收到对应的消息。
消息过滤仅对在线消息、离线消息、漫游消息有效。查询本地和云端历史记录是无法过滤的。
不建议在不要在消息过滤函数或方法中进行耗时操作,否则将导致线程阻塞。
请注意,注册过滤器的时机,建议放在 Application 的 onCreate 中, SDK 初始化之后。
- API 原型
/**
* 注册消息过滤器
*
* @param filter 上层实现的消息过滤器,决定是否过滤消息(不存储到数据库中),传 null 表示注销(取消)通知消息过滤器
*/
void registerIMMessageFilter(IMMessageFilter filter);
- 参数说明
返回值 | IMMessageFilter接口 | 说明 |
---|---|---|
boolean | shouldIgnore(IMMessage message) | 是否过滤消息。 返回 true 表示过滤(那么 SDK 将不存储此消息,上层也不会收到此消息), 默认 false 即不过滤(默认存储到 db 并通知上层) |
- 示例
SDK 过滤群头像变更通知类型消息。
// 在 Application启动时注册,保证漫游、离线消息也能够回调此过滤器进行过滤。注意,过滤器的实现不要有耗时操作。
NIMClient.getService(MsgService.class).registerIMMessageFilter(new IMMessageFilter() {
@Override
public boolean shouldIgnore(IMMessage message) {
if (UserPreferences.getMsgIgnore() && message.getAttachment() != null) {
if (message.getAttachment() instanceof UpdateTeamAttachment) {
UpdateTeamAttachment attachment = (UpdateTeamAttachment) message.getAttachment();
for (Map.Entry<TeamFieldEnum, Object> field : attachment.getUpdatedFields().entrySet()) {
if (field.getKey() == TeamFieldEnum.ICON) {
return true; // 过滤
}
}
}
}
return false; // 不过滤
}
});
已读回执
当发送方需要知道接收方是否已经阅读了自己发送的消息时,需要使用已读回执的功能。
单聊消息已读回执
发送已读回执:
在会话界面中调用发送已读回执的接口并传入当前会话的最后一条消息,即表示这之前的消息本方都已读。
- API 原型
/**
* 发送消息已读回执
* @param sessionId 会话ID(聊天对象账号)
* @param message 已读的消息(一般是当前接收的最后一条消息)
*/
NIMClient.getService(MsgService.class).sendMessageReceipt(sessionId, message);
- 示例
// 该帐号为示例,请先注册
String account = "testAccount";
// message为会话中已读的最后一条消息
NIMClient.getService(MsgService.class).sendMessageReceipt(account, message);
监听已读回执:
- API 原型
/**
* 注册/注销消息已读回执观察者
* @param observer 观察者, 参数为已读回执集合。
* @param register true为注册,false为注销
*/
public void observeMessageReceipt(Observer<List<MessageReceipt>> observer, boolean register);
- 参数说明
返回值 | MessageReceipt接口 | 说明 |
---|---|---|
String | getSessionId() | 聊天对象的 ID,如果是单聊,为用户帐号,如果是群聊,为群组 ID |
long | getTime() | 该会话最后一条已读消息的时间,比该时间早的消息都视为已读 |
- 示例
// 注册/注销观察者
NIMClient.getService(MsgServiceObserve.class).observeMessageReceipt(messageReceiptObserver, register);
private Observer<List<MessageReceipt>> messageReceiptObserver = new Observer<List<MessageReceipt>>() {
@Override
public void onEvent(List<MessageReceipt> messageReceipts) {
receiveReceipt();
}
};
此外,可以根据 IMMessage 中的 isRemoteRead()
方法来判断该条消息对方是否已读。
群聊消息已读回执
群消息已读回执功能,需要联系商务顾问申请开通后才能使用。同时,使用该功能时需要将群成员控制在100人以内。
- 启用群消息已读回执功能
初始化SDK时,配置SDKOptions - enableTeamMsgAck
参数为 true 来启用群消息已读回执功能。
- 设置其他群成员收到此消息需要发送已读回执
发送群消息时,通过IMMessage - setMsgAck()
方法标记该消息需要已读回执。接收群消息时,通过IMMessage - needMsgAck
属性获取该消息是否需要已读回执。
示例
// 创建待发送消息
IMMessage message = MessageBuilder.createTextMessage(sessionId, SessionTypeEnum.Team, "content");
// 标记该消息需要已读回执反馈
message.setMsgAck();
// 发送消息
NIMClient.getService(MsgService.class).sendMessage(message, false);
- 消息接收方发送群消息已读回执
原型
/**
* (群消息接收方)标记群组消息已读
*
* @param message 群组消息
* @return InvocationFuture 可设置回调函数,监听发送结果。
*/
InvocationFuture<Void> sendTeamMessageReceipt(IMMessage message);
示例
NIMSDK.getTeamService().sendTeamMessageReceipt(message)
此外,可以通过IMMessage - hasSendAck()
来判断是否已经发送过群消息已读回执。
- 消息发送方监听群消息已读回执
原型
/**
* 注册/注销群消息已读回执观察者(群成员发出需要已读回执的消息时,当有群成员已读后,该观察者会回调)
*
* @param observer 观察者,参数为已读回执信息集合
* @param register true为注册,false为注销
*/
public void observeTeamMessageReceipt(Observer<List<TeamMessageReceipt>> observer, boolean register);
参数说明
TeamMessageReceipt 接口说明
返回值 | TeamMessageReceipt 接口 | 说明 |
---|---|---|
String | getMsgId() | 获取消息 id |
int | getAckCount() | 获取已读人数 |
int | getUnAckCount() | 获取未读人数 |
示例
// 注册监听器
NIMClient.getService(MsgServiceObserve.class).observeTeamMessageReceipt(teamMessageReceiptObserver, register);
// 监听器的实现
private Observer<List<TeamMessageReceipt>> teamMessageReceiptObserver = new Observer<List<TeamMessageReceipt>>() {
@Override
public void onEvent(List<TeamMessageReceipt> teamMessageReceipts) {
...
}
};
- 批量刷新群组消息已读、未读的数量
原型
/**
* (群消息发送方)批量刷新群组消息已读、未读的数量信息,没有异步回调
* 如果已读、未读数有变更,会通过 {@link com.netease.nimlib.sdk.msg.MsgServiceObserve#observeTeamMessageReceipt(Observer, boolean)}来批量通知,没有变更则不会通知
*
* @param messages 请求刷新的群组消息集合
*/
void refreshTeamMessageReceipt(List<IMMessage> messages);
一般在加载消息进行批量刷新。反复刷新,SDK实际上不会发出网络请求。只有已读、未读数量有变更,才会通过观察者接口进行通知。该API为异步无回调接口。
示例
// messages为接收到的批量消息
NIMSDK.getTeamService().refreshTeamMessageReceipt(messages);
- 查询单条群组消息的已读、未读账号列表
原型
/**
* (群消息发送方)查询单条群组消息已读、未读账号列表
*
* @param message 待查询的消息
* @return 该消息的已读、未读账号列表
*/
InvocationFuture<TeamMsgAckInfo> fetchTeamMessageReceiptDetail(IMMessage message);
/**
* (群消息发送方)查询单条群组消息在指定用户中的已读、未读账号列表
*
* @param message 待查询的消息
* @param accountSet 指定的用户的账号组成的{@link Set<String>}。
* 如果传空,则返回的列表也是空
* @return 该消息的已读、未读账号列表
*/
InvocationFuture<TeamMsgAckInfo> fetchTeamMessageReceiptDetail(IMMessage message, Set<String> accountSet);
示例
// message为待查询的消息,accountSet为账号组成的集合
NIMSDK.getTeamService().fetchTeamMessageReceiptDetail(message, accountSet).setCallback(new RequestCallback<TeamMsgAckInfo>() {
@Override
public void onSuccess(TeamMsgAckInfo param) {
// 获取成功
}
@Override
public void onFailed(int code) {
// 获取失败
}
@Override
public void onException(Throwable exception) {
// 异常
}
});
- 从数据库查询单条群组消息已读、未读账号列表
注意:这里直接从数据库获取,很可能是陈旧信息
原型
/**
* 从本地数据库查询单条群组消息已读、未读账号列表(同步接口)
* 注意!!!:这里获取的数据通常比离线前的列表信息更陈旧
*
* @param message 待查询的消息
* @return 该消息的已读、未读账号列表
*/
TeamMsgAckInfo queryTeamMessageReceiptDetailBlock(IMMessage message);
/**
* 从本地数据库查询单条群组消息在指定用户中的已读、未读账号列表(同步接口)
* 注意!!!:这里获取的数据通常比离线前的列表信息更陈旧
*
* @param message 待查询的消息
* @param accountSet 指定的用户的账号组成的{@link Set<String>}。
* 如果传空,则返回的列表也是空
* @return 该消息的已读、未读账号列表
*/
TeamMsgAckInfo queryTeamMessageReceiptDetailBlock(IMMessage message, Set<String> accountSet);
示例
// message为待查询的消息,accountSet为账号组成的集合
NIMSDK.getTeamService().queryTeamMessageReceiptDetailBlock(message, accountSet);
- 查询单条群组消息已读、未读账号数量
通过 IMMessage 接口的 getTeamMsgAckCount()方法来获取群消息已读账号数量,通过 getTeamMsgUnAckCount() 方法来获取群消息未读账号数量。
广播消息接收
网易云信支持全员广播消息,广播消息由服务端接口发起,对应用内的所有用户发送一条广播消息。客户端不支持发送, SDK 收到广播之后直接往上层通知,不支持客户端存储。
1秒内默认最多可调该接口10次。如需上调上限,请在官网首页通过微信、在线消息或电话等方式咨询商务人员。
- API 原型
/**
* 注册/注销全员广播消息观察者
* @param observer 观察者,参数全员广播消息。
* @param register true为注册,false为注销
*/
public void observeBroadcastMessage(Observer<BroadcastMessage> observer, boolean register);
- BroadcastMessage 参数说明
参数 | 说明 |
---|---|
id | 广播id |
fromAccount | 广播发送者账号 |
time | 广播消息时间戳 |
content | 广播消息内容 |
- 示例
/**
* 注册云信全服广播接收器
*
* @param register
*/
private void registerNimBroadcastMessage(boolean register) {
NIMClient.getService(MsgServiceObserve.class).observeBroadcastMessage(new Observer<BroadcastMessage>() {
@Override
public void onEvent(BroadcastMessage broadcastMessage) {
// 处理
}
}, register);
}