Static
get初始化 SDK
整个 App 生命周期内,原则上 SDK 只能初始化一次
SDK 允许调用该方法重复初始化 SDK,但是我们不建议这么做
因为 SDK 重复初始化之后,之前的连接、监听等均会失效,需要将初始化后的操作重新做一遍,如重新连接,并重新设置各种监听
// 在 UIAbility 中获取 context
let context = this.context
let initOption = new InitOption();
let appKey = "从融云后台获取的 appKey";
IMEngine.getInstance().init(context, appKey, initOption);
上下文,为空则初始化失败
融云 appKey,为空则初始化失败
初始化配置,见 InitOption
上设置断线重连时是否踢出重连设备。
用户没有开通多设备登录功能的前提下,同一个账号在一台新设备上登录的时候,会把这个账号在之前登录的设备上踢出。
由于 SDK 有断线重连功能,存在下面情况: 用户在 A 设备登录,A 设备网络不稳定,没有连接成功,SDK 启动重连机制。 用户此时又在 B 设备登录,B 设备连接成功。 A
设备网络稳定之后,用户在 A 设备连接成功,B 设备被踢出。 这个接口就是为这种情况加的。
let kickEnable = true;
IMEngine.getInstance().setReconnectKickEnable(kickEnable);
设置为 true 时,SDK 重连的时候发现此时已有别的设备连接成功,踢出当前重连设备,不再强行踢出别的设备
设置鸿蒙推送 token
1. SDK 初始化之前设置:SDK 会将推送 token 缓存,连接成功后上报
2. SDK 初始化之后连接之前设置:连接成功后 SDK 自动上报
3. SDK 连接成功后设置:SDK 立即上报
import { pushService } from '@kit.PushKit';
pushService.getToken((error: BusinessError, token: string) => {
if (token) {
IMEngine.getInstance().setPushToken(token);
}
});
推送 token
设置数据库状态监听
数据库打开的时机:参考 DatabaseStatusListener.onDatabaseStatusChange()
IMEngine.getInstance().setDatabaseStatusListener((status: DatabaseStatus) => {
hilog.info(0x0000, 'IM-App', 'setDatabaseStatusListener onChanged status:%{public}d', status);
});
监听
增加数据库状态监听
数据库打开的时机:参考 DatabaseStatusListener.onDatabaseStatusChange()
let dbListener: DatabaseStatusListener = {
onDatabaseStatusChange: (status: DatabaseStatus): void => {
// status 为具体的数据库状态
}
}
IMEngine.getInstance().addDatabaseStatusListener(dbListener);
监听
监听
连接 IM
调用该接口,SDK 会在 timeLimit 秒内尝试重连,直到出现下面三种情况之一
第一、连接成功,回调 IConnectResult.code === EngineError.Success
第二、超时,回调 IConnectResult.code === EngineError.ConnectionTimeout,需要手动调用该接口继续连接
第三、出现 SDK 无法处理的错误,回调 IConnectResult.code 为具体的错误码
常见的错误如下:
ClientNotInit :SDK 没有初始化,请先调用 init 接口
NaviRespTokenIncorrect :检查一下 APP 使用的 appKey 和 APP Server 使用的 appKey 是否相同
ConnectTokenIncorrect :检查一下 APP 使用的 appKey 和 APP Server 使用的 appKey 是否相同
ConnectOneTimePasswordUsed :重新请求 Token
ConnectPlatformError :重新请求 Token
ConnectTokenExpired :重新请求 Token
ConnectAppBlockOrDelete : 给用户提示 AppKey 已经封禁或删除
ConnectUserBlocked :给用户提示被封禁
DisconnectUserKicked :给用户提示被提掉线
DisconnectUserBlocked :给用户提示被封禁
ConnectUserDeleteAccount :给用户提示已销号
let token = "IMToken";
let timeout = 5;
IMEngine.getInstance().connect(token, timeout).then(result => {
if (EngineError.Success === result.code) {
// 连接成功
let userId = result.userId;
return;
}
if (EngineError.ConnectTokenExpired === result.code) {
// Token 过期,从 APP 服务请求新 token,获取到新 token 后重新 connect()
} else if (EngineError.ConnectionTimeout === result.code) {
// 连接超时,弹出提示,可以引导用户等待网络正常的时候再次点击进行连接
} else {
//其它业务错误码,请根据相应的错误码作出对应处理。
}
});
从您服务器端获取的 token (用户身份令牌)
超时时间,整型,单位秒,timeout <= 0:不设置超时时长,一直连接直到成功或失败;timeout > 0: 在对应的时间内连接未成功则返回超时错误
连接结果
设置连接状态监听
每个连接状态都有详细的描述和处理意见,参考 ConnectionStatusListener.onConnectionStatusChanged()
IMEngine.getInstance().setConnectionStatusListener((status: ConnectionStatus) => {
// status 为具体的连接状态
});
监听
增加连接监听。每个连接状态都有详细的描述和处理意见
每个连接状态都有详细的描述和处理意见,参考 ConnectionStatusListener.onConnectionStatusChanged()
let statusListener: ConnectionStatusListener = {
onConnectionStatusChanged: (status: ConnectionStatus): void => {
// status 为具体的连接状态
}
}
IMEngine.getInstance().addConnectionStatusListener(statusListener);
监听
连接监听
获取当前连接状态
IMEngine.getInstance().getCurrentConnectionStatus().then(result => {
if (EngineError.Success !== result.code) {
// 获取当前连接状态失败
return;
}
if (!result.data) {
// 获取的当前连接状态为空
return;
}
let status = result.data as ConnectionStatus;
});
连接状态
获取当前用户 ID
IMEngine.getInstance().getCurrentUserId().then(result => {
if (EngineError.Success !== result.code) {
// 获取用户 ID 失败
return;
}
if (!result.data) {
// 获取的用户 ID 为空
return;
}
let userId = result.data as string;
});
连接成功后才会有值
设置消息接收监听
IMEngine.getInstance().setMessageReceivedListener((message: Message, info: ReceivedInfo) => {
// 针对接收离线消息时,服务端会将 200 条消息打成一个包发到客户端,客户端对这包数据进行解析。该参数表示每个数据包数据逐条上抛后,还剩余的条数
let left = info.left;
// 消息是否离线消息
let isOffline = info.isOffline;
// 是否在服务端还存在未下发的消息包
let hasPackage = info.hasPackage;
});
监听
添加消息接收监听,可以添加多个监听
let messageReceiveListener: MessageReceivedListener = {
onMessageReceived: (message: Message, info: ReceivedInfo): void => {
// 收到了单条消息
},
onOfflineMessageSyncCompleted: (): void => {
// 离线消息已全部拉取完成
}
};
IMEngine.getInstance().addMessageReceivedListener(messageReceiveListener);
监听
监听
设置消息撤回监听,撤回了之后,原始消息会变成 RecallNotificationMessage 消息
IMEngine.getInstance().setMessageRecalledListener((message: Message, recallMessage: RecallNotificationMessage) => {
});
监听
增加消息撤回监听。撤回了之后,原始消息会变成 RecallNotificationMessage 消息
let recalledListener : MessageRecalledListener = {
onMessageRecalled: (message: Message, recallMessage: RecallNotificationMessage): void => {
// 消息撤回
}
}
IMEngine.getInstance().addMessageRecalledListener(recalledListener);
监听
监听
设置消息敏感词拦截监听
IMEngine.getInstance().setMessageBlockedListener((blockInfo: MessageBlockInfo) => {
});
监听
增加消息敏感词拦截监听
let blockedListener : MessageBlockedListener = {
onMessageBlocked: (blockInfo: MessageBlockInfo): void => {
}
}
IMEngine.getInstance().addMessageBlockedListener(blockedListener);
监听
监听
发送消息
如果遇到 DatabaseNotOpened = 34301 ,原因是在 IM 连接成功前发送了消息
IM 连接成功后 SDK 才会打开对应用户的消息数据库
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 id";
let textMsg = new TextMessage();
textMsg.content = "文本消息的内容";
let msg = new Message(conId, textMsg);
let option: ISendMsgOption = {};
IMEngine.getInstance().sendMessage(msg, option, (msg: Message) => {
// 消息入库回调
}).then(result => {
if (EngineError.Success !== result.code) {
// 发送消息失败
return;
}
if (!result.data) {
// 消息数据为空
return;
}
let msg = result.data as Message;
})
消息对象
消息发送的配置
消息入库的回调
消息发送结果
发送媒体消息
如果遇到 DatabaseNotOpened = 34301 ,原因是在 IM 连接成功前发送了消息
IM 连接成功后 SDK 才会打开对应用户的消息数据库
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 id";
let imgMsg = new ImageMessage();
// 使用沙盒路径创建图片消息。系统路径的图片 SDK 无法访问(例如相册的图片路径 SDK 就无法访问)
imgMsg.localPath = localPath;
let msg = new Message(conId, imgMsg);
let option: ISendMsgOption = {};
IMEngine.getInstance().sendMediaMessage(msg, option, (msg: Message) => {
// 消息保存到数据库
}, (msg: Message, progress: number) => {
// 媒体上传进度 [1 ~ 100]
}).then(result => {
if (EngineError.Success !== result.code) {
//发送消息失败
return;
}
if (!result.data) {
// 消息为空
return;
}
let msg = result.data as Message;
})
消息体
消息发送的配置
消息入库的回调
媒体文件上传进度
媒体消息发送结果
发送普通定向消息
此方法用于在群组中发送消息给其中的部分用户,其它用户不会收到这条消息。
如果遇到 DatabaseNotOpened = 34301 ,原因是在 IM 连接成功前发送了消息
IM 连接成功后 SDK 才会打开对应用户的消息数据库
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 id";
let textMsg = new TextMessage();
textMsg.content = "文本消息的内容";
let msg = new Message(conId, textMsg);
let option: ISendMsgOption = {};
// 填入实际的用户 id
let userIdArray = ["userId1", "userId2"];
IMEngine.getInstance().sendDirectionalMessage(msg, option, userIdArray, (msg: Message) => {
// 消息入库回调
}).then(result => {
if (EngineError.Success !== result.code) {
// 发送消息失败
return;
}
if (!result.data) {
// 消息数据为空
return;
}
let msg = result.data as Message;
})
消息对象
消息发送的配置
消息指定接收者
消息入库的回调,
消息发送结果
发送媒体定向消息
此方法用于在群组中发送消息给其中的部分用户,其它用户不会收到这条消息。
如果遇到 DatabaseNotOpened = 34301 ,原因是在 IM 连接成功前发送了消息
IM 连接成功后 SDK 才会打开对应用户的消息数据库
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 id";
let imgMsg = new ImageMessage();
// 使用沙盒路径创建图片消息。系统路径的图片 SDK 无法访问(例如相册的图片路径 SDK 就无法访问)
imgMsg.localPath = localPath;
let msg = new Message(conId, imgMsg);
let option: ISendMsgOption = {};
// 填入实际的用户 id
let userIdArray = ["userId1", "userId2"];
IMEngine.getInstance().sendDirectionalMediaMessage(msg, option, userIdArray, (msg: Message) => {
// 消息保存到数据库
}, (msg: Message, progress: number) => {
// 媒体上传进度 [1 ~ 100]
}).then(result => {
if (EngineError.Success !== result.code) {
//发送消息失败
return;
}
if (!result.data) {
// 消息为空
return;
}
let msg = result.data as Message;
})
消息体
消息发送的配置
消息指定接收者
消息发送的配置
媒体文件上传进度
媒体消息发送结果
下载媒体消息
let messageId = 234;
IMEngine.getInstance().downloadMediaMessage(messageId).then(result => {
if (EngineError.Success === result.code) {
// 本地路径
let localPath = result.data as string;
}
});
消息 id,对应的消息必须是 MediaMessageContent 子类
媒体消息下载成功的本地路径,存储路径见 InitOption.mediaSavePath
下载媒体消息,含下载进度
let messageId = 123;
IMEngine.getInstance().downloadMediaMessageWithProgress(messageId, (messageId: number, progress: number) => {
// 下载进度,取值范围 [0 , 100]
}).then(result => {
if (EngineError.Success === result.code) {
// 本地路径
let localPath = result.data as string;
}
});
消息 Id,对应的消息必须是 MediaMessageContent 子类
下载进度监听,取值范围 [0 , 100]
媒体消息下载成功的本地路径,存储路径见 InitOption.mediaSavePath
取消下载媒体消息,配合 downloadMediaMessageWithProgress 方法
let messageId = 123;
IMEngine.getInstance().cancelDownloadMediaMessage(messageId).then(result => {
if (EngineError.Success === result.code) {
// 下载取消成功,此时 downloadMediaMessageWithProgress 会返回 EngineError.RequestCanceled
} else {
// 下载取消失败
}
});
消息 Id
取消下载结果
下载文件(带下载进度)
如果是下载媒体消息,请调用 downloadMediaMessageWithProgress 方法,下载成功 SDK 会更新媒体消息的本地路径
不是媒体消息的媒体文件需要下载时,才调用 downloadFileWithProgress
会将 file_name 最后一个 . 之前的特殊替换为下划线。如 abc@123.png 会被替换为 abc_123.png。
如果多次请求 file_name 相同,后一次下载会加入序号,如 abc.png,abc(1).png,abc(2).png。
let remoteUrl = "https://expamle.com/1.jpg";
let fileName = "1.jpg";
IMEngine.getInstance().downloadFileWithProgress(remoteUrl, fileName, (uniqueId: number) => {
// 开始下载,下载唯一标识 uniqueId
}, (uniqueId: number, progress: number) => {
// 下载进度
}).then(result => {
if (EngineError.Success !== result.code) {
// 下载失败
return;
}
if (!result.data) {
// 下载的本地路径为空
return;
}
// 本地路径
let localPath = result.data as string;
});
媒体的远端地址
本地文件名
开始下载。uniqueId 下载唯一标识,可以调用 cancelDownloadFile 取消下载
下载进度监听,取值范围 [0 , 100]
媒体文件下载成功的本地路径,存储路径见 InitOption.mediaSavePath
取消下载文件,配合 downloadFileWithProgress 方法
// uniqueId 必须是调用 downloadFileWithProgress 时由 SDK 生成的,此处进行了简写
let uniqueId = 1234;
IMEngine.getInstance().cancelDownloadFile(uniqueId).then(result => {
if (EngineError.Success !== result.code) {
// 取消下载失败
return;
}
// 取消下载成功,此时 downloadFileWithProgress 会返回 EngineError.RequestCanceled
})
下载唯一标识
下载的结果
撤回消息
// 必须用发送成功的消息,此处进行了简写
let message : Message;
IMEngine.getInstance().recallMessage(message).then(result => {
if (EngineError.Success !== result.code) {
// 消息撤回失败
return;
}
if (!result.data) {
// 撤回小灰条消息为空
return;
}
// 撤回小灰条消息
let recallNtfMsg = result.data as RecallNotificationMessage;
})
需要撤回的消息,发送成功的消息才能撤回(必须有有效的 MessageUid)
撤回成功后的小灰条消息
注册自定义消息,初始化之后,连接之前调用
import { JsonConverter, MessageContent, MessageFlag, MessageTag } from '@rongcloud/imlib';
import List from '@ohos.util.List';
const CustomOrderMessageObjectName = "App:OrderMsg";
const CustomOrderMessageFlag = MessageFlag.Count;
// 1. 继承 MessageContent 并实现 MessageTag 注解
@MessageTag(CustomOrderMessageObjectName,CustomOrderMessageFlag)
class CustomOrderMessage extends MessageContent {
// 2. 按需增加属性
id: string = ""; // 订单 ID
name: string = ""; // 订单名称
price: number = 0; // 订单价格
// 3. 必须声明无参的构造方法,因为注册自定义消息时候,只能用无参构造方法
constructor() {
super();
}
// 4. 将消息对象转为 JSON 字符串
encode(): string {
// 4.1 将基类的数据保存到 map 中
let map = super.encodeBaseData();
// 4.2 将本类的独有属性放到 map 中
// 说明:ts 的 map 必须指定 kv 的类型,所以存多种类型数据,需要转为 Object
if (this.id) {
map.set("id", this.id as Object);
}
if (this.name) {
map.set("name", this.name as Object);
}
map.set("price", this.price as Object);
// 4.3 将 map 转为 字符串
return JsonConverter.stringifyFromHashMap(map);
}
// 5. 将字符串转为消息对象
decode(contentJson: string): void {
// 5.1 将字符串转为 map
let map = JsonConverter.parseToHashMap(contentJson);
// 5.2 将基类的数据解析出来
super.decodeBaseData(map);
// 5.3 将本类的独有属性解析
// 说明:需要将 Object 转为对应的数据类型
if (map.get("id")) {
this.id = map.get("id") as string;
}
if (map.get("name")) {
this.name = map.get("name") as string;
}
if (map.get("price")) {
this.price = map.get("price") as number;
}
}
// 6. 将当前类名返回:该方法的作用是防止代码混淆或者压缩后无法获取正常的类名
// 直接写字符串可能会出现拼写错误的情况,所以此处建议直接使用 类名.name
getClassName(): string {
return CustomOrderMessage.name;
}
// 7. 返回搜索字段
// 1) 不实现该方法,该类消息无法被搜索
// 2) 实现该方法,返回 null 或者 List 长度为 0,无法被搜索
// 3) 实现该方法, List 里面的 空字符串 和 null 会被忽略
// 4) List 中必须包含有效的字符串才能被搜索到
getSearchableWord(): List<string> | null {
if (!this.name) {
return null;
}
let list = new List<string>();
list.add(this.name);
return list;
}
}
export { CustomOrderMessage, CustomOrderMessageObjectName }
let clazzList: List<MessageContentConstructor> = new List();
clazzList.add(CustomOrderMessage);
IMEngine.getInstance().registerMessageType(clazzList);
自定义消息数组
获取 SDK 中所有的消息 objectName 和存储标识的映射关系
1. 映射关系集合包含 内置消息 和 自定义消息
2. 必须在所有自定义消息注册完成之后再调用该方法,否则会导致无法正确获取自定义消息的映射关系
3. 不要频繁调用该方法:建议 app 调用该方法之后, app 自行保存整个集合
iOS 通过 RCMessagePersistentCompatible.persistentFlag 获取消息存储标识
Android 通过 getClass().getAnnotation(MessageTag.class) 获取消息存储标识
鸿蒙需要通过本方法获取
1. 发送消息时需要手动构造指定的消息体,可以直接获取到 objectName:例如创建文本消息时一定知道是文本消息的 objectName
2. 接收消息时通过 Message 对象获取:Message.objectName
3. 读取会话时通过 Conversation 对象获取:Conversation.objectName
let hashMap = IMEngine.getInstance().getMessageTypeMap();
映射关系集合。 key :objectName 、 value : MessageFlag
消息批量入库(多用于数据迁移)
conversationType 会话类型
targetId 会话 ID
channelId 所属会话的业务标识,长度限制 20 字符
direction 消息方向
senderId 发送者 ID
receivedStatus 接收状态
sentStatus 发送状态
sentTime 发送时间
content 消息内容
objectName 消息类型,设置 content 的时候 SDK 会自动赋值对应的 objectName
messageUid 服务端生产的消息唯一 ID,如要携带该字段需要保证入库后是唯一的
extra 扩展信息
// 必须是有效的消息集合,此处进行了简写
let msgList : List<Message> ;
IMEngine.getInstance().batchInsertMessage(msgList).then(result => {
if (EngineError.Success !== result.code) {
// 批量入库失败
return;
}
// 批量入库成功
});
需要入库的消息,范围 [1 ~ 500],会话类型不支持聊天室和超级群
入库结果
单条消息入库
conversationType 会话类型
targetId 会话 ID
direction 消息方向,默认为发送
senderId 发送者 ID
receivedStatus 接收状态,默认为未读
sentStatus 发送状态,默认为发送失败
sentTime 发送时间
content 消息内容
objectName 消息类型,设置 content 的时候 SDK 会自动赋值对应的 objectName
messageUid 服务端生产的消息唯一 ID,如要携带该字段需要保证入库后是唯一的
extra 扩展信息
// 必须是有效的消息对象,此处进行了简写
let msg : Message;
IMEngine.getInstance().insertMessage(msg).then(result => {
if (EngineError.Success !== result.code) {
// 入库失败
return;
}
if (!result.data) {
// 入库的消息体为空
return;
}
// 入库成功的消息,含有效的 messageId
let dbMsg = result.data as Message;
});
入库结果
通过 messageId 获取单条消息
let messageId = 123;
IMEngine.getInstance().getMessageById(messageId).then(result => {
if (EngineError.Success !== result.code) {
// 获取本地消息失败
return;
}
if (!result.data) {
// 获取本地消息为空
return;
}
// 获取到有效的本地消息
let dbMsg = result.data as Message;
})
消息的本地数据库自增 ID
消息数据
通过 messageUid 获取单条消息
let messageUid = "CH2C-A072-OGM5-E3HL";
IMEngine.getInstance().getMessageByUid(messageUid).then(result => {
if (EngineError.Success !== result.code) {
// 获取本地消息失败
return;
}
if (!result.data) {
// 获取本地消息为空
return;
}
// 获取到有效的本地消息
let dbMsg = result.data as Message;
})
消息发送成功后的服务唯一 ID,固定格式的字符串,例如 : CH2C-A072-OGM5-E3HL
消息数据
获取批量本地消息,基于 messageId 获取
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let option: IGetLocalMsgByIdOption = {
messageId: 100,
beforeCount: 5,
afterCount: 5
}
IMEngine.getInstance().getHistoryMessagesById(conId, option).then(result => {
if (EngineError.Success !== result.code) {
// 获取消息失败
return;
}
if (!result.data) {
// 消息不存在
return;
}
// 消息体集合
let msgList = result.data as List<Message>;
});
会话标识
配置
返回本地消息结果
获取批量本地消息,基于 time 获取
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let option: IGetLocalMsgByTimeOption = {
time: Date.now(),
beforeCount: 5,
afterCount: 5
};
IMEngine.getInstance().getHistoryMessagesByTime(conId, option).then(result => {
if (EngineError.Success !== result.code) {
// 获取消息失败
return;
}
if (!result.data) {
// 消息不存在
return;
}
// 消息列表
let msgList = result.data as List<Message>;
});
会话标识
配置
返回本地消息结果
获取批量远端消息
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let option: IGetRemoteMsgOption = {
time: Date.now(),
count: 10,
order: Order.Descending,
isCheckDup: true
}
IMEngine.getInstance().getRemoteHistoryMessages(conId, option).then(result => {
if (EngineError.Success !== result.code) {
// 获取聊天室消息失败
return;
}
if (!result.data) {
// 消息数据为空
return;
}
// 消息列表
let msgList = result.data as List<Message>;
});
会话标识
配置
返回远端消息结果
获取本地会话中 @ 自己的未读消息列表
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let option: ICountOption = {
count: 10,
order: Order.Descending
};
IMEngine.getInstance().getUnreadMentionedMessages(conId, option).then(result => {
if (EngineError.Success !== result.code) {
// 获取消息失败
return;
}
if (!result.data) {
// 消息不存在
return;
}
// 消息列表
let msgList = result.data as List<Message>;
});
会话标识
配置
返回本地消息结果
获取会话里第一条未读消息
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
IMEngine.getInstance().getFirstUnreadMessage(conId).then(result => {
if (EngineError.Success !== result.code) {
// 获取消息失败
return;
}
if (!result.data) {
// 消息不存在
return;
}
let msg = result.data as Message;
});
会话标识
消息,如果该会话没有未读,返回 null
删除本地会话的指定一批消息
let idList = new List<number>();
idList.add(msg.messageId);
IMEngine.getInstance().deleteHistoryMessagesByIds(idList).then(result => {
if (EngineError.Success !== result.code) {
// 删除消息失败
return;
}
// 删除消息成功
})
消息 ID 列表
删除结果
清空本地会话的消息
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
IMEngine.getInstance().deleteMessages(conId).then(result => {
if (EngineError.Success !== result.code) {
// 删除消息失败
return;
}
// 删除消息成功
});
会话标识
结果
删除本地会话特定时间前的所有消息
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let sentTime = Date.now();
IMEngine.getInstance().deleteHistoryMessagesByTime(conId, time).then(result => {
if (EngineError.Success !== result.code) {
// 删除消息失败
return;
}
// 删除消息成功
})
会话标识
毫秒时间戳。清除 <= sentTime 的所有历史消息,若为 0 则代表清除所有消息
结果
删除远端会话特定时间前的消息
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let sentTime = Date.now();
IMEngine.getInstance().cleanRemoteHistoryMessagesByTime(conId, time).then(result => {
if (EngineError.Success !== result.code) {
// 删除消息失败
return;
}
// 删除消息成功
});
会话标识
毫秒时间戳。清除 <= sentTime 的所有历史消息,若为 0 则代表清除所有消息
结果
批量删除远端消息,发送成功或者接收到的消息才可以从远端删除
msgList 里面 Message 下列属性是必须的
uid: 服务端生产的消息唯一 id
direction: 消息方向
sentTime: 发送时间,不能小于等于 0
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 ID";
let msgList = new List<Message>();
for (let i = 0; i < 10; i++) {
// msg 必须是发送成功的消息,此处进行简写
let msg : Message;
msgList.add(msg);
}
// 是否删除本地消息
let isDeleteLocal = true;
IMEngine.getInstance().deleteRemoteMessages(conId, msgList, isDeleteLocal).then(result => {
if (EngineError.Success !== result.code) {
// 删除远端消息失败
return;
}
// 删除远端消息成功
})
会话标识
消息列表,长度范围 [1, 100]
是否删除本地消息。只有远端消息被删除成功时设置 true 才会删除本地消息。
设置输入状态的监听
IMEngine.getInstance().setTypingStatusListener((conId: ConversationIdentifier, typingStatusList: List<TypingStatus>) => {
// conId 具体的会话标识
// typingStatusList 具体的输入状态
});
监听,conId 会话标识;typingStatusList 输入状态的列表
增加输入状态的监听
let typingListener: TypingStatusListener = {
onTypingStatusChange: (conId: ConversationIdentifier, typingStatusList: List<TypingStatus>): void => {
// conId 具体的会话标识
// typingStatusList 具体的输入状态
}
}
IMEngine.getInstance().addTypingStatusListener(typingListener);
监听
监听,对方调用 sendTypingStatus() 时本端会出发该监听
发送输入状态,仅支持单聊
常见的使用方式如下:
在聊天页面输入文本时,可以发送 TextMessageObjectName ,对方收到后可以展示"正在输入中"
在录音时,可以发送 HQVoiceMessageObjectName ,对方收到后可以展示"正在说话"
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 ID";
let objectName = TextMessageObjectName;
IMEngine.getInstance().sendTypingStatus(conId, objectName).then(result => {
if (EngineError.Success !== result.code) {
// 发送失败
return;
}
// 发送成功
});
会话标识
正在输入的消息 ObjectName
设置输入状态更新时间间隔
控制输入状态发送频率,在规定时间内多次调用发送输入状态方法,最终只会发送一次输入状态
例如输入状态时间间隔为 6000 毫秒,在这段时间多次调用输入状态方法,只会发出一次输入状态,对方也只会收到一次输入状态
let interval = 5000;
IMEngine.getInstance().setTypingStatusInterval(interval).then(result => {
if (EngineError.Success !== result.code) {
// 设置输入状态间隔失败
return;
}
// 设置成功
});
时间间隔,单位毫秒,默认为 6000 毫秒。有效值 [1000,60000] 毫秒;超过范围,则设置不成功
修改消息接收状态
目前该方法仅用于设置 isListened 来标记高清语音消息是否已被听过
let messageId = 123;
let receivedStatus = new ReceivedStatus();
receivedStatus.isRead = false;
receivedStatus.isListened = false;
IMEngine.getInstance().setMessageReceivedStatus(messageId, receivedStatus).then(result => {
if (EngineError.Success !== result.code) {
// 设置接收状态失败
return;
}
// 设置接收状态成功
})
消息 Id
接收状态
结果
设置消息扩展监听
let listener: MessageExpansionListener = {
onMessageExpansionUpdate: (expansion: Map<string, string>, message: Message): void => {
},
onMessageExpansionRemove: (keyArray: string[], message: Message): void => {
}
}
IMEngine.getInstance().setMessageExpansionListener(listener);
监听
增加消息扩展监听
let listener: MessageExpansionListener = {
onMessageExpansionUpdate: (expansion: Map<string, string>, message: Message): void => {
},
onMessageExpansionRemove: (keyArray: string[], message: Message): void => {
}
}
IMEngine.getInstance().addMessageExpansionListener(listener);
监听
监听
更新消息扩展信息
调用更新扩展的一方必须通过成功回调来处理本端的数据刷新。
仅被动接收扩展变更的用户(包含本用户的其他端)通过监听方法 MessageExpansionListener.onMessageExpansionUpdate 获取通知。
消息扩展信息是以字典形式存在。设置的时候从 expansion 中读取 key,如果原有的扩展信息中 key 不存在则添加新的 KV 对,如果 key 存在则替换成新的 value。
扩展信息字典中的 Key 支持大小写英文字母、数字、部分特殊符号 + = - _ 的组合方式,最大长度 32;Value 最长长度 4096,单次设置扩展数量最大为 20,消息的扩展总数不能超过 300
// 消息 UId 是固定格式的字符串,例如 : CH2C-A072-OGM5-E3HL
let msgUid = "消息 UId";
// 更新的消息扩展数据
let map = new Map<string,string>();
map.set("k1","v1");
map.set("k2","v2");
IMEngine.getInstance().updateMessageExpansion(map, msgUid).then(result => {
if (EngineError.Success !== result.code) {
// 消息扩展更新失败
return;
}
// 消息扩展更新成功
});
要更新的消息扩展信息键值对
消息 messageUId
结果
删除消息扩展信息中特定的键值对
调用删除扩展的一方必须通过成功回调来处理本端的数据刷新。
仅被动接收扩展变更的用户(包含本用户的其他端)通过监听方法 MessageExpansionListener.onMessageExpansionRemove 获取通知。
// 消息 UId 是固定格式的字符串,例如 : CH2C-A072-OGM5-E3HL
let msgUid = "消息 UId";
// 需要删除的 key 数组
let keyArray = new Array<string>();
keyArray.push("k1");
IMEngine.getInstance().removeMessageExpansion(keyArray, msgUid).then(result => {
if (EngineError.Success !== result.code) {
// 删除消息扩展失败
return;
}
// 删除消息扩展成功
});
消息扩展信息中待删除的 key 的列表
消息 messageUId
结果
增加消息阅后即焚监听,仅支持单聊,仅限阅后即焚消息的接收方调用
let destructListener: MessageDestructionListener = {
onMessageDestructing: (message: Message, leftDuration: number): void => {
},
onMessageDestructionStop: (message: Message): void => {
}
}
IMEngine.getInstance().addMessageDestructionListener(destructListener);
监听
移除消息阅后即焚监听,仅支持单聊,仅限阅后即焚消息的接收方调用
IMEngine.getInstance().removeMessageDestructionListener(destructListener);
监听
消息开始阅后即焚倒计时,仅支持单聊,仅限阅后即焚消息的接收方调用
// 必须使用有效的消息体,此处进行了简写
let msg: Message;
IMEngine.getInstance().messageBeginDestruct(msg).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
// 成功
});
消息体
消息停止阅后即焚倒计时,仅支持单聊,仅限阅后即焚消息的接收方调用
调用之后,该消息终止阅后即焚
阅后即焚倒计时停止,并触发 MessageDestructionListener.onMessageDestructionStop
可以调用 messageBeginDestruct() 重新进行倒计时
// 必须使用有效的消息体,此处进行了简写
let msg: Message;
IMEngine.getInstance().messageStopDestruct(msg).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
// 成功
});
消息体
设置显示推送详情
通知栏显示的消息推送默认显示的是消息内容,如果消息包含敏感信息,不希望在推送通知栏上显示消息内容,可以调用此方法设置 showStatus 为 false
注意:此功能需要从服务端开启用户设置功能。
let showStatus = true;
IMEngine.getInstance().setPushContentShowStatus(showStatus).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
// 成功
});
是否显示远程推送内容,true 显示,false 不显示
设置的结果
获取是否显示远程推送内容详情设置
IMEngine.getInstance().getPushContentShowStatus().then(result => {
if (EngineError.Success !== result.code) {
// 获取失败
return;
}
if (!result.data) {
// 数据为空
return;
}
let showStatus = result.data as boolean;
});
是否显示远程推送内容,true 显示,false 不显示
设置 Web 端在线时,手机端是否接收推送
注意:此功能需要从服务端开启用户设置功能。
let receiveStatus = true;
IMEngine.getInstance().setPushReceiveStatus(receiveStatus).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
// 成功
});
是否接收推送,true 接收,false 不接收
结果
获取是否接收远程推送的设置
前提: 移动端不在线,Web 、MAC/PC 终端在线,移动端是否接收远程推送。
IMEngine.getInstance().getPushReceiveStatus().then(result => {
if (EngineError.Success !== result.code) {
// 获取失败
return;
}
if (!result.data) {
// 数据为空
return;
}
let receiveStatus = result.data as boolean;
});
是否接收远程推送,true 接收,false 不接收
设置会话状态(置顶,消息免打扰)变化监听
IMEngine.getInstance().setConversationStatusListener((items: List<ConversationStatusInfo>) => {
});
监听
增加会话状态(置顶,消息免打扰)变化监听
let statusListener : ConversationStatusListener = {
onConversationStatusChange: (items: List<ConversationStatusInfo>): void => {
}
}
IMEngine.getInstance().addConversationStatusListener(statusListener);
监听
监听
获取单个会话
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
IMEngine.getInstance().getConversation(conId).then(result => {
if (EngineError.Success !== result.code) {
// 获取回话失败
return;
}
if (!result.data) {
// 会话为空
return;
}
let con = result.data as Conversation;
});
会话标识
会话数据
分页获取本地会话列表
let conTypeList = new List<ConversationType>();
conTypeList.add(ConversationType.Private);
conTypeList.add(ConversationType.Group);
let option: IGetConversationOption = {
time: Date.now(),
count: 10
}
IMEngine.getInstance().getConversationListByPage(conTypeList, option).then(result => {
if (EngineError.Success !== result.code) {
// 获取会话列表失败
return;
}
if (!result.data) {
// 会话列表为空
return;
}
let conList = result.data as List<Conversation>;
});
会话类型列表
配置
本地会话列表数据
分页获取本地置顶会话列表
let conTypeList = new List<ConversationType>();
conTypeList.add(ConversationType.Private);
conTypeList.add(ConversationType.Group);
let option: IGetConversationOption = {
time: Date.now(),
count: 10
}
IMEngine.getInstance().getTopConversationListByPage(conTypeList, option).then(result => {
if (EngineError.Success !== result.code) {
// 获取会话列表失败
return;
}
if (!result.data) {
// 会话列表为空
return;
}
let conList = result.data as List<Conversation>;
});
会话类型列表
配置
本地会话列表数据
分页获取本地免打扰会话列表
let conTypeList = new List<ConversationType>();
conTypeList.add(ConversationType.Private);
conTypeList.add(ConversationType.Group);
let option: IGetConversationOption = {
time: Date.now(),
count: 10
}
IMEngine.getInstance().getBlockedConversationListByPage(conTypeList, option).then(result => {
if (EngineError.Success !== result.code) {
// 获取会话列表失败
return;
}
if (!result.data) {
// 会话列表为空
return;
}
let conList = result.data as List<Conversation>;
});
会话类型列表
配置
本地会话列表数据
获取本地未读会话列表,该接口仅支持单聊、群聊、系统三种会话类型,不支持聊天室、超级群。
let conTypeList = new List<ConversationType>();
conTypeList.add(ConversationType.Private);
conTypeList.add(ConversationType.Group);
IMEngine.getInstance().getUnreadConversations(conTypeList).then(result => {
if (EngineError.Success !== result.code) {
// 获取未读会话列表失败
return;
}
if (!result.data) {
// 获取未读会话列表为空
return;
}
// 未读会话列表
let conList = result.data as List<Conversation>;
});
会话类型数组,长度范围 [1, 100]
会话数组
删除本地会话同时删除会话中的消息
let conTypeList = new List<ConversationType>();
conTypeList.add(ConversationType.Private);
IMEngine.getInstance().clearConversations(conTypeList).then(result => {
if (EngineError.Success !== result.code) {
// 删除会话失败
return;
}
});
会话类型列表
结果
批量删除本地会话,但是不会删除消息
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let list = new List<ConversationIdentifier>();
list.add(conId);
IMEngine.getInstance().removeConversations(conIdList).then(result => {
if (EngineError.Success !== result.code) {
// 删除会话失败
return;
}
});
会话标识数组
结果
批量 设置/取消 会话置顶
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let list = new List<ConversationIdentifier>();
list.add(conId);
let option: ISetConversationTopOption = {
isTop: true, // 是否置顶
isNeedCreate: true // 没有会话时是否创建该会话
}
IMEngine.getInstance().setConversationsToTop(conIdList, option).then(result => {
if (EngineError.Success !== result.code) {
// 设置置顶失败
return;
}
});
会话标识列表
配置
结果
获取会话置顶状态
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
IMEngine.getInstance().getConversationTopStatus(conId).then(result => {
if (EngineError.Success !== result.code) {
// 获取置顶状态失败
return;
}
if (!result.data) {
// 置顶状态为空
return;
}
let isTop = result.data as boolean;
});
会话标识
是否置顶
批量设置会话免打扰
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let list = new List<ConversationIdentifier>();
list.add(conId);
let level = PushNotificationLevel.Blocked;
IMEngine.getInstance().setConversationsNotificationLevel(conIdList, level).then(result => {
if (EngineError.Success !== result.code) {
// 设置免打扰失败
return;
}
});
会话标识列表
会话免打扰级别
结果
获取单个会话免打扰状态
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
IMEngine.getInstance().getConversationNotificationLevel(conId).then(result => {
if (EngineError.Success !== result.code) {
// 获取免打扰状态失败
return;
}
if (!result.data) {
// 免打扰状态为空
return;
}
let level = result.data as PushNotificationLevel;
});
会话标识
会话免打扰级别
保存/清空 会话草稿
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let draft = "draft From 鸿蒙";
IMEngine.getInstance().saveTextMessageDraft(conId, draft).then(result => {
if (EngineError.Success !== result.code) {
// 保存草稿失败
return;
}
});
会话标识
草稿:传入有效值代表保存草稿;传入空字符串代表清空草稿
结果
获取会话草稿
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
IMEngine.getInstance().getTextMessageDraft(conId).then(result => {
if (EngineError.Success !== result.code) {
// 获取草稿失败
return;
}
if (!result.data) {
// 草稿为空
return;
}
let draft = result.data as string;
})
会话标识
草稿
屏蔽某个时间段的消息提醒
let option: IQuietHoursOption = {
startTime: "00:30:00",
duration: 300,
level: PushNotificationLevel.Blocked
}
IMEngine.getInstance().setNotificationQuietHoursLevel(option).then(result => {
if (EngineError.Success !== result.code) {
// 设置免打扰失败
return;
}
})
配置,见 IQuietHoursOption
结果
查询已设置的时间段消息提醒屏蔽
IMEngine.getInstance().getNotificationQuietHoursLevel().then(result => {
if (EngineError.Success !== result.code) {
// 获取免打扰失败
return;
}
if (!result.data) {
// 免打扰数据为空
return;
}
let info = result.data as IQuietHoursOption;
})
具体的配置
删除已设置的全局时间段消息提醒屏蔽
IMEngine.getInstance().removeNotificationQuietHours().then(result => {
if (EngineError.Success !== result.code) {
// 移除免打扰失败
return;
}
// 移除免打扰成功
});
结果
获取本地会话的全部未读数
IMEngine.getInstance().getTotalUnreadCount().then(result => {
if (EngineError.Success !== result.code) {
// 获取未读数失败
return;
}
if (!result.data) {
// 未读数为 null
return;
}
let unreadCount = result.data as number;
})
未读数
获取本地批量会话的未读数之和
let conIdList = new List<ConversationIdentifier>();
let conId1 = new ConversationIdentifier();
conId1.conversationType = ConversationType.Private;
conId1.targetId = "会话 id";
conIdList.add(conId1)
let conId2 = new ConversationIdentifier();
conId2.conversationType = ConversationType.Private;
conId2.targetId = "会话 id";
conIdList.add(conId2)
IMEngine.getInstance().getTotalUnreadCountByIds(conIdList).then(result => {
if (EngineError.Success !== result.code) {
// 获取未读数失败
return;
}
if (!result.data) {
// 未读数为 null
return;
}
let unreadCount = result.data as number;
})
会话标识数组
未读数
获取单个会话的未读数
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
IMEngine.getInstance().getUnreadCount(conId).then(result => {
if (EngineError.Success !== result.code) {
// 获取未读数失败
return;
}
if (!result.data) {
// 未读数为 null
return;
}
let unreadCount = result.data as number;
});
会话标识
该会话的未读数
清空单个会话未读数
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
IMEngine.getInstance().clearMessagesUnreadStatus(conId).then(result => {
if (EngineError.Success !== result.code) {
// 清空未读数失败
return;
}
/ 清空未读数成功
})
会话标识
结果
清除单个会话的未读数:按照时间戳清除
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let time = Date.now();
IMEngine.getInstance().clearMessagesUnreadStatusByTime(conId, time).then(result => {
if (EngineError.Success !== result.code) {
// 清空未读数失败
return;
}
// 清空未读数成功
})
会话标识
时间,清理小于该时间戳的消息未读
结果
会话未读数,是否包含免打扰会话的未读数
let typeList = new List<ConversationType>();
typeList.add(ConversationType.Private);
typeList.add(ConversationType.Group);
let isContainBlocked = false;
IMEngine.getInstance().getUnreadCountByTypes(conTypeList, isContainBlocked).then(result => {
if (EngineError.Success !== result.code) {
// 获取未读数失败
return;
}
if (!result.data) {
// 未读数为 null
return;
}
let unreadCount = result.data as number;
});
会话类型数组
是否包含免打扰;true 代表获取所有会话未读数之和; false 代表获取不包含免打扰会话的正常会话未读数之和
未读数
同步会话已读状态
用于相同账号的多端已读同步
例如用户 A 同时登录鸿蒙和 Android,两端同时收到消息,同时未读数增加
Android 调用该方法将某个会话同步已读之后, 鸿蒙会触发 SyncConversationReadStatusListener
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 Id";
// 会话中已读的最后一条消息的发送时间戳,此处用了当前时间
let time = Date.now();
IMEngine.getInstance().syncConversationReadStatus(conId,time).then(result => {
if (EngineError.Success !== result.code) {
// 同步已读失败
return;
}
// 同步已读成功
});
会话标识
会话中已读的最后一条消息的发送时间戳
结果
设置会话已读状态监听
let listener : SyncConversationReadStatusListener = {
onSyncConversationReadStatus: (conId: ConversationIdentifier, timestamp: number): void => {
// 该会话的 timestamp 之前的消息未读已清空
}
}
IMEngine.getInstance().setSyncConversationReadStatusListener(listener);
监听
增加会话已读状态监听
let listener : SyncConversationReadStatusListener = {
onSyncConversationReadStatus: (conId: ConversationIdentifier, timestamp: number): void => {
// 该会话的 timestamp 之前的消息未读已清空
}
}
IMEngine.getInstance().addSyncConversationReadStatusListener(listener);
监听
增加消息已读回执监听
let listener: MessageReadReceiptListener = {
onMessageReadReceiptReceived: (message: Message): void => {
},
onMessageReceiptRequest: (conId: ConversationIdentifier, messageUid: string): void => {
},
onMessageReceiptResponse: (conId: ConversationIdentifier, messageUid: string, respondUserIdList: Map<string, number>): void => {
}
}
IMEngine.getInstance().addMessageReadReceiptListener(listener);
监听
监听
单聊,发送某个会话中的消息阅读回执,由原始消息的接收方调用
单聊调用该方法后,原始消息发送方会触发 MessageReadReceiptListener.onMessageReadReceiptReceived
原始消息发送方本地对应单聊会话的已读消息 sentStatus 均为 SentStatus.Read
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let time = Date.now();
IMEngine.getInstance().sendReadReceiptMessage(conId, time).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
// 成功
});
会话标识
会话中已读的最后一条消息的发送时间戳, Message.sentTime
群聊,发送某个会话的消息已读请求,由原始消息的发送方调用
群聊调用该方法后,原始消息的接收方会触发 MessageReadReceiptListener.onMessageReceiptRequest
原始消息接收方就知道需要对该消息做已读响应。调用 sendReadReceiptResponse
// 应该使用发送成功的消息,此处进行了简写
let msg : Message;
IMEngine.getInstance().sendReadReceiptRequest(msg).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
// 成功
});
消息体,messageUid 必须有效
消息已读请求的结果
群聊,发送某个会话已读响应,由原始消息的接收方调用
群聊调用该方法后,原始消息的发送方会触发 MessageReadReceiptListener.onMessageReceiptResponse
原始消息的发送方就知道自己该消息有哪些人已读了
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
// 需要具体的消息,此处进行了简写
let msgArray = new Array<Message>();
let msg : Message;
msgArray.push(msg);
IMEngine.getInstance().sendReadReceiptResponse(conId, msgArray).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
if (!result.data) {
// 成功的消息体列表为空
return;
}
// 发送响应成功的消息列表
let msgList = result.data as List<Message>;
});
会话标识
消息体数组,消息体必须存在有效的 senderId 和 messageUid
消息已读响应结果,返回的 Message 集合可以通过 Message.readReceiptInfo.hasRespond 确认该消息是否已经发送了响应
根据关键字搜索本地会话。
let conTypeList = new List<ConversationType>();
conTypeList.add(ConversationType.Private);
conTypeList.add(ConversationType.Group);
let keyword = "需要搜索的关键字";
let objNameList = new List<string>();
// 例如文本消息传入文本消息的 objectName: RC:TxtMsg
objNameList.add(TextMessageObjectName);
IMEngine.getInstance().searchConversations(conTypeList, keyword, objNameList).then(result => {
if (EngineError.Success !== result.code) {
// 搜索会话失败
return;
}
if (!result.data) {
// 搜索的会话为空
return;
}
// 搜索到的会话列表
let conList = result.data as List<Conversation>;
});
搜索的关键字,长度范围 [1, 256]
消息类型数组。用于搜索指定类型的消息;为空代表所有所有类型消息
搜索到的会话列表
根据关键字搜索本地会话。
let conTypeList = new List<ConversationType>();
conTypeList.add(ConversationType.Private);
conTypeList.add(ConversationType.Group);
let keyword = "关键字";
IMEngine.getInstance().searchConversationsWithResult(conTypeList, keyword, null).then(result => {
if (EngineError.Success !== result.code) {
// 搜索会话失败
return;
}
if (!result.data) {
// 搜索的会话内容为空
return;
}
// 搜索的结果
let searchResultList = result.data as List<SearchConversationResult>;
});
搜索的关键字,长度范围 [1, 256]
消息类型数组。用于搜索指定类型的消息;为空代表所有所有类型消息
搜索到的会话列表
根据关键字搜索指定消息类型的本地消息。
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 ID";
let keyword = "需要搜索的关键字";
let objNameList = new List<string>();
objNameList.add(TextMessageObjectName);
let startTime = Date.now();
let count = 10;
IMEngine.getInstance().searchMessages(conId, keyword, objNameList, startTime, count).then(result => {
if (EngineError.Success !== result.code) {
// 搜索消息失败
return;
}
if (!result.data) {
// 搜索消息为空
return;
}
// 搜索到的消息
let msgList = result.data as List<Message>;
});
会话标识
关键字,长度范围 [1, 256]
消息类型数组。用于搜索指定类型的消息;为空代表搜索所有类型消息
查询的起始发送时间,返回小于该时间的消息,毫秒时间戳;如果为 0,则查询全部。当分页时,可以传入上一批消息的最小发送时间,取值范围 [0, INT64_MAX]
消息个数,传 0 时会返回所有搜索到的消息,非 0 时根据 startTime 逐页返回,取值范围 [0, 100]
消息列表
根据关键字和指定时间段搜索指定会话中的消息。
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 ID";
let keyword = "需要搜索的关键字";
// 查找当前时间 24 小时内的消息
let option: ISearchMessageInTimeRangeOption = {
startTime: Date.now() - 24 * 60 * 60 * 1000,
endTime: Date.now(),
offset: 0,
limit: 10
}
IMEngine.getInstance().searchMessagesInTimeRange(conId, keyword, option).then(result => {
if (EngineError.Success !== result.code) {
// 搜索消息失败
result;
}
if (!result.data) {
// 搜素消息为空
return;
}
// 搜索的消息列表
let msgList = result.data as List<Message>;
});
会话标识
关键字,长度范围 [1, 256]
在时间区间内搜索消息的参数配置
消息列表
根据用户 id 搜索指定会话中的本地消息。
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "会话 ID";
let userId = "用户 ID";
let startTime = Date.now();
let count = 10;
IMEngine.getInstance().searchMessagesByUser(conId, userId, startTime, count).then(result => {
if (EngineError.Success !== result.code) {
// 搜索消息失败
return;
}
if (!result.data) {
// 搜素消息为空
return;
}
// 搜索的消息列表
let msgList = result.data as List<Message>;
});
会话标识
用户 id
查询的起始发送时间,返回小于该时间的消息,毫秒时间戳;如果为 0,则查询全部。当分页时,可以传入上一批消息的最小发送时间,取值范围 [0, INT64_MAX]
消息个数,传 0 时会返回所有搜索到的消息;非 0 时根据 startTime 逐页返回,取值范围 [0, 100]
消息列表
在指定的一批会话中搜索消息
let conTypeArray = new Array<ConversationType>();
conTypeArray.push(ConversationType.Private);
let targetIdArray: Array<string> | null = null;
let channelIdArray: Array<string> | null = null;
let objNameArray: Array<string> | null = null;
let keyword = "关键字";
let startTime = Date.now();
let count = 10;
let order = Order.Ascending;
IMEngine.getInstance().searchMessagesByConversations(
conTypeArray,
targetIdArray,
channelIdArray,
objNameArray,
keyword,
startTime,
count, order
).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
if (!result.data) {
// 数据为空
return;
}
let msgList = result.data as List<Message>;
})
会话类型数组,非空
会话 Id 数组,为空代表所有会话
频道 Id 数组,为空代表所有频道
消息类型数组。用于搜索指定类型的消息;为空代表搜索所有类型消息
关键字,长度范围 [1, 256]
查询的起始发送时间,返回小于该时间的消息,毫秒时间戳;如果为 0,则查询全部。当分页时,可以传入上一批消息的最小发送时间,取值范围 [0, INT64_MAX]
消息个数,传 0 时会返回所有搜索到的消息;非 0 时根据 startTime 逐页返回,取值范围 [0, 100]
返回排序。Ascending 升序,返回比 startTime 时间戳大的消息。Descending 降序,返回比 startTime 时间戳消的消息
在本地指定会话中搜索多个成员指定的消息类型
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.Private;
conId.targetId = "TestTargetId"; // 按需填写实际的会话 id
let userIdArray = ["UserId1","UserId2"];
let objNameArray: Array<string> | null = null;
let startTime = Date.now();
let count = 10;
let order = Order.Ascending;
IMEngine.getInstance().searchMessagesByUsers(conId, userIdArray, objNameArray, startTime, count, order).then(result => {
if (EngineError.Success !== result.code) {
// 失败
return;
}
if (!result.data) {
// 数据为空
return;
}
// 搜索到的消息列表
let msgList = result.data as List<Message>;
})
会话标识
消息发送者 Id 数组,搜索由这些用户发送的消息
消息类型数组。用于搜索指定类型的消息;为空代表搜索所有类型消息
查询的起始发送时间,返回小于该时间的消息,毫秒时间戳;如果为 0,则查询全部。当分页时,可以传入上一批消息的最小发送时间,取值范围 [0, INT64_MAX]
消息个数;非 0 时根据 startTime 逐页返回,传 0 默认取值为 100,取值范围 [0, 100]
返回排序。Ascending 升序,返回比 startTime 时间戳大的消息。Descending 降序,返回比 startTime 时间戳消的消息
消息列表
获取本地订阅的所有公众号(仅支持私有云)
IMEngine.getInstance().getPublicServiceList().then(result => {
if (EngineError.Success !== result.code) {
// 获取公众号失败
return;
}
if (!result.data) {
// 公众号为空
return;
}
// 公众号列表
let list = result.data as List<PublicServiceInfo>;
});
获取本地订阅的指定公众号
let conId = new ConversationIdentifier();
conId.conversationType = ConversationType.AppPublicService;
conId.targetId = this.targetId;
IMEngine.getInstance().getPublicService(conId).then(result => {
if (EngineError.Success !== result.code) {
// 获取公众号失败
return;
}
if (!result.data) {
// 公众号为空
return;
}
// 公众号信息
let info = result.data as PublicServiceInfo;
});
会话标识,会话类型不管为何值,SDK 均会按照 AppPublicService 处理
设置聊天室状态监听
let listener: ChatroomStatusListener = {
onChatroomJoining(roomId: string): void {
},
onChatroomJoined(roomId: string, info: ChatroomJoinedInfo): void {
},
onChatroomJoinFailed(roomId: string, code: EngineError): void {
},
onChatroomQuited(roomId: string): void {
},
onChatroomDestroyed(roomId: string, type: ChatroomDestroyType): void {
},
}
IMEngine.getInstance().setChatroomStatusListener(listener);
监听
增加聊天室状态监听
let listener: ChatroomStatusListener = {
onChatroomJoining(roomId: string): void {
hilog.info(0x0000, 'IM-App', 'onChatroomJoining roomId:%{public}s', roomId);
},
onChatroomJoined(roomId: string, info: ChatroomJoinedInfo): void {
hilog.info(0x0000, 'IM-App', 'onChatroomJoined roomId:%{public}s info:%{public}s', roomId, JSON.stringify(info));
},
onChatroomJoinFailed(roomId: string, code: EngineError): void {
hilog.info(0x0000, 'IM-App', 'onChatroomJoined roomId:%{public}s code:%{public}d', roomId, code);
},
onChatroomQuited(roomId: string): void {
hilog.info(0x0000, 'IM-App', 'onChatroomQuited roomId:%{public}s', roomId);
},
onChatroomDestroyed(roomId: string, type: ChatroomDestroyType): void {
hilog.info(0x0000, 'IM-App', 'onChatroomDestroyed roomId:%{public}s type:%{public}d', roomId, type);
},
}
IMEngine.getInstance().addChatroomStatusListener(listener);
监听
监听
加入聊天室,如果聊天室不存在则创建聊天室
let roomId = "TestChatroomId"; // 按需填写实际的聊天室 id
let msgCount = 5;
IMEngine.getInstance().joinChatroom(roomId, msgCount).then(result => {
if (EngineError.Success !== result.code) {
// 加入聊天室失败
return;
}
if (!result.data) {
// 聊天室加入信息失败
return;
}
let joinedInfo = result.data as ChatroomJoinedInfo;
});
roomId 聊天室 ID
msgCount 消息个数,-1 时不拉取任何消息,0 时拉取 10 条消息,最多只能拉取 50
结果
加入已经存在的聊天室
let roomId = "TestChatroomId"; // 按需填写实际的聊天室 id
let msgCount = 5;
IMEngine.getInstance().joinExistingChatroom(roomId, msgCount).then(result => {
if (EngineError.Success !== result.code) {
// 加入聊天室失败
return;
}
if (!result.data) {
// 聊天室加入信息失败
return;
}
let joinedInfo = result.data as ChatroomJoinedInfo;
});
聊天室 ID
消息个数,-1 时不拉取任何消息,0 时拉取 10 条消息,最多只能拉取 50
结果
退出聊天室
let roomId = "TestChatroomId"; // 按需填写实际的聊天室 id
IMEngine.getInstance().quitChatroom(roomId).then(result => {
if (EngineError.Success !== result.code) {
// 退出聊天室失败
return;
}
});
聊天室 ID
结果
获取聊天室信息
let roomId = "TestChatroomId"; // 按需填写实际的聊天室 id
let option: ICountOption = {
count: 10,
order: Order.Descending
}
IMEngine.getInstance().getChatroomInfo(roomId, option).then(result => {
if (EngineError.Success !== result.code) {
// 获取聊天室信息失败
return;
}
if (!result.data) {
// 聊天室信息为空
return;
}
let chatroomInfo = result.data as ChatroomInfo;
});
聊天室 ID
配置
聊天室信息
设置聊天室自定义属性
entries 最大限制为 10
key : 聊天室属性名称,长度范围 [1~128],支持大小写英文字母、数字、部分特殊符号 + = - _ 的组合方式
value : 聊天室属性对应的值,长度范围 [1~4096]
let roomId = "聊天室 ID";
let map = new Map<string, string>();
map.set("key1","value1");
map.set("key2","value2");
let autoDelete = true;
let overWrite = true;
IMEngine.getInstance().setChatroomEntries(roomId, map, autoDelete, overWrite).then(result => {
if (EngineError.Success !== result.code) {
// 设置 KV 失败
return;
}
if (!result.data) {
// 所有 KV 都设置成功
return;
}
// 设置失败的 key 和对应的失败错误码,视情况决定是否重新设置失败的 KV
let errorMap = result.data as Map<string, EngineError>;
});
聊天室 ID
key-value 字典,长度范围 [1 ~ 10]
用户掉线或退出时,是否自动删除该 Key、Value 值;自动删除时不会发送通知
是否强制覆盖
返回的具体结果,会明确特定 key 的具体错误
删除聊天室自定义属性
let roomId = "聊天室 ID";
let list = new List<string>();
list.add("key1");
list.add("key2");
let isForce = true;
IMEngine.getInstance().deleteChatroomEntries(roomId, list, isForce).then(result => {
if (EngineError.Success !== result.code) {
// 删除 KV 失败
return;
}
if (!result.data) {
// 删除 KV 成功
return;
}
// 删除失败的 K 和对应的错误,视情况决定是否重新删除失败的 KV
let errorMap = result.data as Map<string,EngineError>;
});
聊天室 ID
key 数组,长度范围 [1,10]
是否强制删除
返回的具体结果,会明确特定 key 的具体错误
获取本地指定一批聊天室自定义属性
let roomId = "聊天室 ID";
let list = new List<string>();
list.add("key1");
list.add("key2");
IMEngine.getInstance().getChatroomEntries(roomId, list).then(result => {
if (EngineError.Success !== result.code) {
// 获取 KV 失败
return;
}
if (!result.data) {
// KV 为空
return;
}
// KV map
let kvMap = result.data as Map<string,string>;
});
聊天室 ID
key 数组,长度范围 [1,100]
对应的 kv 信息
获取本地聊天室全部自定义属性
let roomId = "聊天室 ID";
IMEngine.getInstance().getAllChatroomEntries(roomId).then(result => {
if (EngineError.Success !== result.code) {
// 获取 KV 失败
return;
}
if (!result.data) {
// KV 为空
return;
}
// KV map
let kvMap = result.data as Map<string,string>;
});
聊天室 ID
对应的 kv 信息
设置聊天室 KV 状态变化的监听
let listener: ChatroomKVStatusListener = {
onChatroomKVSync: (roomId: string): void => {
},
onChatroomKVUpdate: (roomId: string, entries: Map<string, string>): void => {
},
onChatroomKVRemove: (roomId: string, entries: Map<string, string>): void => {
}
}
IMEngine.getInstance().setChatroomKVStatusListener(listener);
聊天室 KV 状态变化的监听
增加聊天室 KV 状态变化的监听
let listener: ChatroomKVStatusListener = {
onChatroomKVSync: (roomId: string): void => {
},
onChatroomKVUpdate: (roomId: string, entries: Map<string, string>): void => {
},
onChatroomKVRemove: (roomId: string, entries: Map<string, string>): void => {
}
}
IMEngine.getInstance().addChatroomKVStatusListener(listener);
监听
监听
设置聊天室成员变化监听
let listener: ChatroomMemberActionListener = {
onMemberChange: (actionModel: ChatRoomMemberActionModel): void => {
}
}
IMEngine.getInstance().setChatroomMemberListener(listener);
成员变化监听
增加聊天室成员变化监听
let listener: ChatroomMemberActionListener = {
onMemberChange: (actionModel: ChatRoomMemberActionModel): void => {
}
}
IMEngine.getInstance().addChatroomMemberListener(listener);
成员变化监听
成员变化监听
设置聊天室事件通知监听器
let listener: ChatroomNotifyEventListener = {
onChatroomNotifyMultiLoginSync: (syncEvent: ChatroomSyncEvent): void => {
},
onChatroomNotifyBlock: (blockEvent: ChatroomMemberBlockEvent): void => {
},
onChatRoomNotifyBan: (banEvent: ChatroomMemberBanEvent): void => {
}
}
IMEngine.getInstance().setChatroomNotifyEventListener(listener);
监听
增加聊天室事件通知监听器
let listener: ChatroomNotifyEventListener = {
onChatroomNotifyMultiLoginSync: (syncEvent: ChatroomSyncEvent): void => {
},
onChatroomNotifyBlock: (blockEvent: ChatroomMemberBlockEvent): void => {
},
onChatRoomNotifyBan: (banEvent: ChatroomMemberBanEvent): void => {
}
}
IMEngine.getInstance().addChatroomNotifyEventListener(listener);
监听
监听
IM SDK 核心类
Version
1.0.0