Flutter接入融云IM

一、配置

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;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾云鹤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值