rongcloud_im_plugin 4.0.4
rongcloud_im_plugin: ^4.0.4

Flutter Android iOS

RongCloud IM Flutter Plugin.

融云 IM Flutter plugin #

本文档讲解了如何使用 IM 的 Flutter Plugin,基于融云 iOS/Android 平台的 IMLib SDK

Flutter 官网

融云 iOS 文档集成

融云 Android 文档集成

源码地址 Github,任何问题可以通过 Github Issues 提问

前期准备 #

融云官网 申请开发者账号

通过管理后台的 "基本信息"->"App Key" 获取 AppKey

通过管理后台的 "IM 服务"—>"API 调用"->"用户服务"->"获取 Token",通过用户 id 获取 IMToken

依赖 IM Flutter plugin #

在项目的 pubspec.yaml 中写如下依赖

dependencies:
  flutter:
    sdk: flutter

rongcloud_im_plugin: ^4.0.4

然后在项目路径执行 flutter packages get 来下载 Flutter Plugin

从 2.0.0 开始废弃核心类 RongcloudImPlugin,新的核心类名为 RongIMClient

从 1.1.0 开始为方便排查 Android 问题将 IM Flutter SDK Android 的包名改为 io.rong.flutter.imlib

集成步骤 #

1.初始化 SDK #

RongIMClient.init(RongAppKey);

2.连接 IM #

RongIMClient.connect(RongIMToken, (int code, String userId) {
  print('connect result ' + code.toString());
  EventBus.instance.commit(EventKeys.UpdateNotificationQuietStatus, {});
if (code == 31004 || code == 12) {
  Navigator.of(context).pushAndRemoveUntil(new MaterialPageRoute(builder: (context) => new LoginPage()), (route) => route == null);
} else if (code == 0) {
  print("connect userId" + userId);
  // 连接成功后打开数据库
  // _initUserInfoCache();
}

API 调用 #

断开 IM 连接 #

//needPush 断开连接之后是否需要远程推送
RongIMClient.disconnect(bool needPush)

发送消息 #

发送文本消息

onSendMessage() async{
      TextMessage txtMessage = new TextMessage();
      txtMessage.content = "这条消息来自 Flutter";
      Message msg = await RongIMClient.sendMessage(RCConversationType.Private, privateUserId, txtMessage);
      print("send message start senderUserId = "+msg.senderUserId);
  }

发送图片消息

onSendImageMessage() async {
    ImageMessage imgMessage = new ImageMessage();
    imgMessage.localPath = "image/local/path.jpg";
    Message msg = await RongIMClient.sendMessage(RCConversationType.Private, privateUserId, imgMessage);
    print("send image message start senderUserId = "+msg.senderUserId);
  }

发送 Gif 消息

onSendGifMessage() async {
    GIFMessage gifMessage = GifMessage.obtain("gif/local/path.jpg");
    Message msg = await RongIMClient.sendMessage(RCConversationType.Private, privateUserId, gifMessage);
    print("send gif message start senderUserId = "+msg.senderUserId);
  }

发送小视频消息

详细参见小视频消息文档

发送文件消息

onSendFileMessage() async {
    // localPath 为文件本地路径,注意 Android 必须以 file:// 开头
    FileMessage fileMessage = FileMessage.obtain(localPaht);
    // 文件后缀如 "png" "txt"
    fileMessage.mType = "XXX";
    Message msg = await RongIMClient.sendMessage(
              conversationType, targetId, fileMessage);
  }

发送结果回调

//消息发送结果回调
    RongIMClient.onMessageSend = (int messageId,int status,int code) {
      print("send message messsageId:"+messageId.toString()+" status:"+status.toString()+" code:"+code.toString());
    };

媒体消息媒体文件上传进度

//媒体消息(图片/语音消息)上传媒体进度的回调
    RongIMClient.onUploadMediaProgress = (int messageId,int progress) {
      print("upload media messsageId:"+messageId.toString()+" progress:"+progress.toString());
    };

接收消息 #

注:以下两个接收消息的回调只能实现一个,否则会出现重复收到消息的情况

如果离线消息量不大,可以使用下面这个回调;

//消息接收回调
    RongIMClient.onMessageReceived = (Message msg,int left) {
      print("receive message messsageId:"+msg.messageId.toString()+" left:"+left.toString());
    };

下面这个回调是 SDK 分批拉取离线消息,当离线消息量巨大的时候,建议当 left == 0 且 hasPackage == false 时刷新会话列表:

//消息接收回调
    RongIMClient.onMessageReceivedWrapper = (Message msg, int left, bool hasPackage, bool offline) {
      print("receive message messsageId:"+msg.messageId.toString()+" left:"+left.toString());
    };

历史消息 #

获取本地历史消息

onGetHistoryMessages() async {
    List msgs = await RongIMClient.getHistoryMessage(RCConversationType.Private, privateUserId, 0, 10);
    print("get history message");
    for(Message m in msgs) {
      print("sentTime = "+m.sentTime.toString());
    }
  }

获取远端历史消息

RongIMClient.getRemoteHistoryMessages(1, "1001", 0, 20,(List<Message> msgList,int code) {
      if(code == 0) {
        for(Message msg in msgList) {
          print("getRemoteHistoryMessages  success "+ msg.messageId.toString());
        }
      }else {
        print("getRemoteHistoryMessages error "+code.toString());
      }
    });

插入发出的消息

RongIMClient.insertOutgoingMessage(RCConversationType.Private, "1001", 10, msgT, 0, (msg,code){
      print("insertOutgoingMessage " + msg.content.encode() + " code " + code.toString());

    });

插入收到的消息

RongIMClient.insertIncomingMessage(RCConversationType.Private, "1002", "1002", 1, msgT , 0, (msg,code){
      print("insertIncomingMessage " + msg.content.encode() + " code " + code.toString());
    });

删除特定会话消息

RongIMClient.deleteMessages(RCConversationType.Private, "2002", (int code) {

});

批量删除消息

List<int> mids =  new List();
mids.add(1);
RongIMClient.deleteMessageByIds(mids, (int code) {

});

未读数 #

获取特定会话的未读数

RongIMClient.getUnreadCount(RCConversationType.Private, "targetId", (int count,int code) {
      if( 0 == code) {
        print("未读数为"+count.toString());
      }
    });

获取特定会话类型的未读数

RongIMClient.getUnreadCountConversationTypeList([RCConversationType.Private,RCConversationType.Group], true, (int count, int code) {
      if( 0 == code) {
        print("未读数为"+count.toString());
      }
    });

获取所有未读数

RongIMClient.getTotalUnreadCount((int count, int code) {
      if( 0 == code) {
        print("未读数为"+count.toString());
      }
    });

会话列表 #

获取会话列表

onGetConversationList() async {
    List conversationList = await RongIMClient.getConversationList([RCConversationType.Private,RCConversationType.Group,RCConversationType.System]);

    for(Conversation con in cons) {
      print("conversation latestMessageId " + con.latestMessageId.toString());
    }
  }

删除指定会话

RongIMClient.removeConversation(RCConversationType.Private, "1001", (success) {
      if(success) {
        print("删除会话成功");
      }
    });

黑名单 #

把用户加入黑名单

RongIMClient.addToBlackList(blackUserId, (int code) {
      print("_addBlackList:" + blackUserId + " code:" + code.toString());
    });

把用户移除黑名单

RongIMClient.removeFromBlackList(blackUserId, (int code) {
      print("_removeBalckList:" + blackUserId + " code:" + code.toString());
    });

查询特定用户的黑名单状态

RongIMClient.getBlackListStatus(blackUserId,
        (int blackStatus, int code) {
      if (0 == code) {
        if (RCBlackListStatus.In == blackStatus) {
          print("用户:" + blackUserId + " 在黑名单中");
        } else {
          print("用户:" + blackUserId + " 不在黑名单中");
        }
      } else {
        print("用户:" + blackUserId + " 黑名单状态查询失败" + code.toString());
      }
    });

查询已经设置的黑名单列表

RongIMClient.getBlackList((List/*<String>*/ userIdList, int code) {
      print("_getBlackList:" + userIdList.toString() + " code:" + code.toString());
      userIdList.forEach((userId) {
        print("userId:"+userId);
      });
    });

加入聊天室 #

onJoinChatRoom() {
    RongIMClient.joinChatRoom("testchatroomId", 10);
  }

加入聊天室回调

//加入聊天室结果回调
    RongIMClient.onJoinChatRoom = (String targetId,int status) {
      print("join chatroom:"+targetId+" status:"+status.toString());
    };

退出聊天室 #

onQuitChatRoom() {
    RongIMClient.quitChatRoom("testchatroomId");
  }

退出聊天室回调

//退出聊天室结果回调
    RongIMClient.onQuitChatRoom = (String targetId,int status) {
      print("quit chatroom:"+targetId+" status:"+status.toString());
    };

获取聊天室信息 #

onGetChatRoomInfo() async {
    ChatRoomInfo chatRoomInfo = await RongIMClient.getChatRoomInfo("testchatroomId", 10, RCChatRoomMemberOrder.Desc);
    print("onGetChatRoomInfo targetId ="+chatRoomInfo.targetId);
  }

Native 向 Flutter 传递数据 #

iOS 端传递数据:

[[RCIMFlutterWrapper sharedWrapper] sendDataToFlutter:@{@"key":@"ios"}];

Android 端传递数据:

Map map = new HashMap();
map.put("key","android");
RCIMFlutterWrapper.getInstance().sendDataToFlutter(map);

Flutter 端接收数据:

RongIMClient.onDataReceived = (Map map) {
  print("object onDataReceived " + map.toString());
};

单聊已读回执 #

发送已读回执:

RongIMClient.sendReadReceiptMessage(conversationType, targetId, timestamp, (int code){
  if (code == 0) {
    print('sendReadReceiptMessageSuccess');
  } else {
    print('sendReadReceiptMessageFailed:code = + $code');
  }
});

接收已读回执:

RongIMClient.onReceiveReadReceipt = (Map map) {
  print("object onReceiveReadReceipt " + map.toString());
};

群组已读回执 #

如何实现群组已读回执

消息撤回 #

撤回消息调用如下接口会返回 RecallNotificationMessage 类型的消息体,需要把原有消息的内容替换,刷新 ui 显示为此类型消息的展示 #

void _recallMessage(Message message) async {
    RecallNotificationMessage recallNotifiMessage =
        await RongIMClient.recallMessage(message, "");
    if (recallNotifiMessage != null) {
      message.content = recallNotifiMessage;
      _insertOrReplaceMessage(message);
    } else {
      showShortToast("撤回失败");
    }
  }

草稿 #

输入状态监听 #

聊天室属性自定义 #

详细参见聊天室存储相关接口

多端阅读消息数同步 #

详细参见多端阅读消息数同步

消息搜索 #

1.搜索关键词相关的会话信息 #

static void searchConversations(
      String keyword,
      List conversationTypes,
      List objectNames,
      Function(int code, List searchConversationResult) finished)

2.在根据搜索会话返回的信息,针对某个会话搜索相应会话的消息 #

static void searchMessages(
      int conversationType,
      String targetId,
      String keyword,
      int count,
      int beginTime,
      Function(List/*<Message>*/ msgList, int code) finished) 

全局消息提醒 #

全局屏蔽某个时间段的消息提醒

void _setNotificationQuietHours() {
    RongIMClient.setNotificationQuietHours("09:00:00", 600,
        (int code) {
      String toast = "设置全局屏蔽某个时间段的消息提醒:\n" +
          (code == 0 ? "设置成功" : "设置失败, code:" + code.toString());
      print(toast);
    });
  }

查询已设置的全局时间段消息提醒屏蔽

  void _getNotificationQuietHours() {
    RongIMClient.getNotificationQuietHours(
        (int code, String startTime, int spansMin) {
      String toast = "查询已设置的全局时间段消息提醒屏蔽\n: startTime:" +
          startTime +
          " spansMin:" +
          spansMin.toString() +
          (code == 0 ? "" : "\n设置失败, code:" + code.toString());
      print(toast);
    });
  }

删除已设置的全局时间段消息提醒屏蔽

  void _removeNotificationQuietHours() {
    RongIMClient.removeNotificationQuietHours((int code) {
      String toast = "删除已设置的全局时间段消息提醒屏蔽:\n" +
          (code == 0 ? "删除成功" : "删除失败, code:" + code.toString());
      print(toast);
    });
  }

获取会话中@提醒自己的消息 #

getUnreadMentionedMessages(int conversationType, String targetId) {
  Future<List> messages = RongIMClient.getUnreadMentionedMessages(conversationType, targetId);
  print("get unread mentioned messages = " + messages.toString());
}

发送群定向消息 #

  1. 此方法用于在群组中发送消息给其中的部分用户,其它用户不会收到这条消息。
  2. 此方法目前仅支持群组。
  3. 群定向消息不存储到云端,通过“单群聊消息云存储”服务无法获取到定向消息。
onSendDirectionalMessage() async {
    TextMessage txtMessage = new TextMessage();
    txtMessage.content = "这条消息来自 Flutter 的群定向消息";
    Message message = await RongIMClient.sendDirectionalMessage(
        RCConversationType.Group, targetId, ['UserId1', 'UserId2'], txtMessage);
    print("send directional message start senderUserId = " + msg.senderUserId);
  }

设置断线重连时是否踢出当前正在重连的设备 #

设置 enable 为 YES 时,SDK 重连的时候发现此时已有别的设备连接成功,不再强行踢出已有设备,而是踢出重连设备。

RongIMClient.setReconnectKickEnable(true);

获取当前 SDK 的连接状态 #

void getConnectionStatus() async {
  int status = await RongIMClient.getConnectionStatus();
  print('getConnectionStatus: $status');
}

取消下载中的媒体文件 #

RongIMClient.cancelDownloadMediaMessage(100);

从服务器端获取聊天室的历史消息 #

void _getChatRoomHistoryMessage() {
  RongIMClient.getRemoteChatroomHistoryMessages(
      targetId, 0, 20, RCTimestampOrder.RC_Timestamp_Desc,
      (List/*<Message>*/ msgList, int syncTime, int code) {
    DialogUtil.showAlertDiaLog(
        context,
        "获取聊天室历史消息:code:" +
            CodeUtil.codeString(code) +
            ",msgListCount:${msgList.length} 条消息\n" +
            ",msgList:$msgList" +
            ",syncTime:$syncTime");
  });
}

通过 messageUId(发送 message 成功后,服务器会给每个 message 分配一个唯一 messageUId)获取消息实体 #

Message msg = await RongIMClient.getMessageByUId(message.messageUId);

删除指定的一条或者一组消息。会同时删除本地和远端消息(会话类型不支持聊天室) #

RongIMClient.deleteRemoteMessages(conversationType, targetId, messageList, (code){
    print("result: $code");
    });

清空指定会话类型,targetId 的某一会话所有聊天消息记录 #

RongIMClient.clearMessages(con.conversationType, con.targetId, (code) {
    print("result:$code");
    });

设置本地消息的附加信息(message.extra) #

RongIMClient.setMessageExtra(int messageId, value, (code) {
    print("result:$code");
    });

根据 messageId 设置接收到的消息状态。用于UI标记消息为已读,已下载等状态 #

RongIMClient.setMessageReceivedStatus(message.messageId, 1, (code) async{
    print("setMessageReceivedStatus result:$code");
    });

根据 messageId 设置消息的发送状态。用于UI标记消息为正在发送,对方已接收等状态。 #

RongIMClient.setMessageSentStatus(message.messageId, 1, (code) async{
    print("setMessageReceivedStatus result:$code");
    });

清空会话类型列表中的所有会话及会话信息 #

RongIMClient.clearConversations(conversations, (code) async{
    print("clearConversations result:$code");
    });

获取本地时间与服务器时间的差值。 消息发送成功后,sdk 会与服务器同步时间,消息所在数据库中存储的时间就是服务器时间。 #

int deltaTime = await RongIMClient.getDeltaTime()

设置当前用户离线消息补偿时间 #

RongIMClient.setOfflineMessageDuration(3, (code, result){
    print("setOfflineMessageDuration code:$code result:$result");
    });

获取当前用户离线消息的存储时间,取值范围为int值1~7天 #

int duration = await RongIMClient.getOfflineMessageDuration();

更多接口请参考

常见问题