一、配置
1. 导入第三方
rongcloud_im_plugin: ^5.1.3
2. 初始化融云
token为融云唯一识别标志,用shared_preferences存到本地
initRongIM() async {
RongIMClient.init(rongIMKey);
SharedPreferences prefs = await SharedPreferences.getInstance();
///融云初登录-""传token
RongIMClient.connect(prefs.getString("token")!, (int? code, String? userId) {
if (code == 0) {
print("融云登录ID" + userId!);
// 连接成功后打开数据库
// _initUserInfoCache();
} else if(code == 31004) {
toastShow("需要重新从 APP 服务获取新 token 并连接,请联系管理员");
}
});
}
3. 消息回调
这里使用eventBus(存放在全局变量中)进行广播,状态管理框架为GETx
根据当前是否是聊天页面来判断是否需要刷新聊天页面
/// 初始化融云消息回调
initRongIMReceive() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if(prefs.getString("token") != null){
initRongIM();
}
/// 融云接收到消息时操作
RongIMClient.onMessageReceived = (Message? msg,int? left) {
if(Get.currentRoute == "/() => BalloonChatPage"){ /// BalloonChatPage为聊天页面路由
Get.find<GlobalConfigService>().eventBus.fire(UpdateNowChat(msg!.targetId!));
} else {
Get.find<GlobalConfigService>().eventBus.fire(UpdateChatList(1));
}
};
}
/// 融云接收消息通知后刷新聊天列表
class UpdateChatList{
int status;
UpdateChatList(this.status);
}
/// 融云接收消息通知后刷新聊天页面
class UpdateNowChat{
String targetId;
UpdateNowChat(this.targetId);
}
有个坑:如果没有初始化融云就监听消息回调,会失败。我的处理方式是将消息回调写在main文件中,当程序运行时执行一次,当用户登录时,也执行一次。
二、使用
1. 发送消息
支持文本消息+表情消息
onRongSendMessage(content, memberId) async{
RongIMClient.onConnectionStatusChange = (int? connectionStatus) {
if(RCConnectionStatus.KickedByOtherClient == connectionStatus ||
RCConnectionStatus.TokenIncorrect == connectionStatus ||
RCConnectionStatus.UserBlocked == connectionStatus){
print("失效了");
initRongIM();
}
};
TextMessage txtMessage = new TextMessage();
txtMessage.content = content;
await RongIMClient.sendMessage(RCConversationType.Private, memberId, txtMessage);
}
- RCConversationType.Private:单聊时固定
- memberId:发送者ID
- txtMessage:TextMessage格式文本
2. 获取本地历史消息
暂时只处理TextMessage格式消息,有时候能正确解析,有时候不能正确解析,所以我处理的返回值,只返回我需要的参数
Future<List<Map<dynamic, dynamic>>> onGetHistoryMessages(memberId, {count}) async {
RongIMClient.onConnectionStatusChange = (int? connectionStatus) {
if(RCConnectionStatus.KickedByOtherClient == connectionStatus ||
RCConnectionStatus.TokenIncorrect == connectionStatus ||
RCConnectionStatus.UserBlocked == connectionStatus){
initRongIM();
}
};
List msgs = (await RongIMClient.getHistoryMessage(RCConversationType.Private, memberId, -1, count ?? 10))!;
List<Map<dynamic, dynamic>> messages = [];
if(msgs.length > 0){
msgs.asMap().forEach((index, m)
{
var content = (msgs[index].content != null && msgs[index].content is TextMessage) ? msgs[index].content.content : "❕此版本暂不支持该类型消息";
if(msgs[index].originContentMap?['content'] != null){
content = msgs[index].originContentMap?['content'];
}
messages.add({"messageDirection": (msgs[index] as Message).messageDirection,"sentTime": (msgs[index] as Message).sentTime, "content": content});
}
);
}
return messages;
}
(1)Param
- memberId:对方的ID
- count:单次获取的数量
(2)Response
消息实体 Message 对象列表
- int? conversationType; //会话类型 参见 RCConversationType
- int? conversationType; //会话类型 参见 RCConversationType
- String? targetId; //会话 id
- int? messageId; //messageId ,本地数据库的自增 id
- int? messageDirection; //消息方向 参见 RCMessageDirection
- String? senderUserId; //发送者 id
- int? receivedStatus; //消息接收状态 参见 RCReceivedStatus
- int? sentStatus; //消息发送状态 参见 RCSentStatus
- int? sentTime; //发送时间,unix 时间戳,单位毫秒
- String? objectName; //消息 objName
- MessageContent? content; //消息内容
- String? messageUId; //消息 UID,全网唯一 Id
- String? extra; // 扩展信息
- bool? canIncludeExpansion; // 消息是否可以包含扩展信息
- Map? expansionDic; // 消息扩展信息列表
- ReadReceiptInfo? readReceiptInfo; //阅读回执状态
- MessageConfig? messageConfig; // 消息配置
- MessagePushConfig? messagePushConfig; // 推送配置
- Map? originContentMap;//如果 content 为 null ,说明消息内容本身未被 flutter 层正确解析,则消息内容会保存到该 map 中
3. 获取单个聊天未读数量
这里有个巨坑,融云方获取未读数量有个延迟,所以有时候获取的值为0,所以修改源码即可,不过有个问题就是每次换电脑拉取都要修改
Future<int> onGetUnSeeMessages(memberId) async {
RongIMClient.onConnectionStatusChange = (int? connectionStatus) {
if(RCConnectionStatus.KickedByOtherClient == connectionStatus ||
RCConnectionStatus.TokenIncorrect == connectionStatus ||
RCConnectionStatus.UserBlocked == connectionStatus){
initRongIM();
}
};
var countNow = 0;
await RongIMClient.getUnreadCount(RCConversationType.Private, memberId, (int? count,int? code) {
if(0 == code) {
countNow = count!;
return count;
}
});
return countNow;
}
(1)Param
- memberId:对方ID
(2)Response
- count:总数
解决未读消息获取延迟BUG
/// 原来代码
static void getUnreadCount(int conversationType, String targetId,
Function(int? count, int? code)? finished) async {
Map map = {"conversationType": conversationType, "targetId": targetId};
Map? unreadMap =
await _channel.invokeMethod(RCMethodKey.GetUnreadCountTargetId, map);
if (finished != null) {
finished(unreadMap!["count"], unreadMap["code"]);
}
}
/// 修改后
static Future<int> getUnreadCount(int conversationType, String targetId,
Function(int? count, int? code)? finished) async {
Map map = {"conversationType": conversationType, "targetId": targetId};
Map? unreadMap =
await _channel.invokeMethod(RCMethodKey.GetUnreadCountTargetId, map);
if (finished != null) {
finished(unreadMap!["count"], unreadMap["code"]);
}
return 1;
}