升级 rongcloud_im_wrapper_plugin 的说明:如何兼容旧版自定义消息、onDataReceived、conversationDigest

Flutter IM SDK 从 5.2.4 版本开始,需要替换升级为新版 SDK(rongcloud_im_wrapper_plugin)。已集成旧版 SDK 的客户应遵照开发者文档 SDK 变更说明尽快迁移到新版 SDK。

针对旧版 SDK 无法直接替换的部分功能,在本知识库中进行了说明。

如何支持旧版本自定义消息

新版 SDK(rongcloud_im_wrapper_plugin)重新设计了自定义消息类型的实现方式

如果您已经升级为 rongcloud_im_wrapper_plugin,但需要兼容旧版自定义消息,您需要在项目的 Dart 层、Android 层、iOS 层分别进行处理。

:warning: 注意:需要编写原生层代码, 仅处理 Dart 层是无法支持自定义消息的!

详细代码可参考 example

Dart 层处理

  1. 首先需要开发者根据自己的自定义消息定义 Dart 层消息内容,代码参考 example/lib/custom_message/poke_message.dart

    导入头文件

    import 'package:rongcloud_im_wrapper_plugin/rongcloud_im_wrapper_plugin.dart';
    
    import 'dart:convert' as json_lib show json;
    

    定义消息类

    • 开发者的自定义消息类需要继承 RCIMIWUserCustomMessage

    • 开发者需要定义 fromJson 的构造函数,并调用 suer.fromJson

      RCIMDPokeMessage.fromJson(Map<String, dynamic> json) : super.fromJson(json);
      
    • 开发者定义自己的构造方法, 需要调用父类的 RCIMIWUserCustomMessage(RCIMIWConversationType type, String targetId)

      RCIMDPokeMessage(RCIMIWConversationType type, String targetId, this.pokeMessage) : super(type, targetId);
      
    • 开发者需要实现父类的 decode/encode 方法

      
      @override
      
      void decode(String jsonStr) {
      
      Map map = json_lib.json.decode(jsonStr.toString());
      
      // 获取的 key 值要与原生传递的 key 值一样
      
      pokeMessage = map['content'];
      
      }
      
      
      
      @override
      
      String encode() {
      
      Map map = {};
      
      // 传递的 key 值要与原生传递的 key 值一样
      
      map['content'] = pokeMessage;
      
      return json_lib.json.encode(map);
      
      }
      
      
    • 开发者需要实现父类的 messageObjectName 来返回 objectName。注意:objectName 值要与原生完全一致

      
      @override
      
      String messageObjectName() {
      
      return "ST:PokeMsg";
      
      }
      
      
    • 开发者需要实现父类的 toJson 方法,创建一个 Map 对象,并给设置 ‘content’ 的 value 值为 encode 方法的返回值。

      
      final Map<String, dynamic> json = super.toJson();
      
      // 此处 'content' 不可修改
      
      json['content'] = encode();
      
      return json;
      
      
  2. 注册自定义消息

    调用引擎的 registerCustomMessage 方法进行注册,注册参考下面代码,只需要修改 objectName 和自定义消息类即可。

    
    e.registerCustomMessage('ST:PokeMsg', (json){
    
    RCIMDPokeMessage pokeMsg = RCIMDPokeMessage.fromJson(json);
    
    // 此处 'content' 不可修改
    
    pokeMsg.decode(json['content']);
    
    return pokeMsg;
    
    });
    
    

Android 层处理

  1. 开发者需要在项目工程中引入融云原生 SDK,且 SDK 版本需要和Flutter SDK中引入的版本号一致。具体版本号可以在 android/build.gradle 中进行查看。

  2. 将原生的自定义消息文件放入工程中,并在 MainActivity 进行注册,确保注册放在 dart 层 init 之前。

    
    import cn.rongcloud.im.wrapper.flutter.RCIMWrapperEngine;
    
    
    List<Class<? extends MessageContent>> list = new ArrayList<>();
    
    list.add(PokeMessage.class);
    
    RCIMWrapperEngine.getInstance().messageContentClassList = list;
    
    

iOS 层处理

  1. 引入头文件

    #import <rongcloud_im_wrapper_plugin/RCIMWrapperEngine.h>
    
  2. 将原生的自定义消息导入到 iOS 工程中,并在 AppDelegate 中进行注册,确保注册放在 dart 层 init 之前。

    NSMutableArray *marr = [NSMutableArray arrayWithObject:[RCDPokeMessage class]];
    
    [RCIMWrapperEngine sharedInstance].messageContentClassList = marr.copy;
    
    

如何实现旧版的 conversationDigest 功能

因为新版本自定义消息优化后,不再需要开发者在原生层进行处理,为避免开发者在自定义消息上更好的进行扩展功能,所以 conversationDigest 功能需要开发者自己来进行定义处理。 逻辑参考如下:

开发者封装一个 conversationDigest 的方法,根据传入的message来返回不同情况下的摘要内容

示例代码如下

String conversationDigest(RCIMIWMessage message) {

 switch (message.messageType) {

 case RCIMIWMessageType.text:

 return "text";

 case RCIMIWMessageType.voice:

 return "[语音]";

 case RCIMIWMessageType.userCustom:

 return "[自定义消息]";

 case RCIMIWMessageType.command:

 return "[系统消息]";

 break;

 }

}

如何实现旧版的 onDataReceived

因为 onDataReceived 不属于 SDK 标准功能,所以新版本 SDK 不再提供此功能,开发者如需要使用可以参考旧版本 SDK 实现, 步骤如下:

  1. 在 Dart 插件层定义 onDataReceived 方法

    
    ///收到原生数据的回调
    
    ///
    
    ///[data] 传递的数据内容
    
    ///
    
    /// 如果传送的是push内容 建议在 main.dart 使用
    
    static Function(Map? data)? onDataReceived;
    
    
  2. 在 setMethodCallHandler 中处理channel回调

    static void _addNativeMethodCallHandler() {
    
    _channel.setMethodCallHandler(_methodCallHandler);
    
    }
    
    
    
    static Future<dynamic> _methodCallHandler(MethodCall call) async {
    
    switch (call.method) {
    
    case "SendDataToFlutterCallBack":
    
    if (onDataReceived != null) {
    
    Map? map = call.arguments;
    
    onDataReceived!(map);
    
    }
    
    break;
    
    }
    
    }
    
    
  3. ios/android 层调用方法。

    // 可通过该接口向Flutter传递数据
    
    public void sendDataToFlutter(final Map map) {
    
    if (map == null) {
    
    return;
    
    }
    
    RCLog.i("sendDataToFlutter start param:" + map.toString());
    
    mMainHandler.post(new Runnable() {
    
    @Override
    
    public void run() {
    
    mChannel.invokeMethod("SendDataToFlutterCallBack", map);
    
    }
    
    });
    
    }
    
    
    
    
    - (void)sendDataToFlutter:(NSDictionary *)userInfo {
    
    NSString *LOG_TAG = @"sendDataToFlutter";
    
    [RCLog i:[NSString stringWithFormat:@"%@,start param:%@",LOG_TAG,userInfo]];
    
    [self.channel invokeMethod:@"SendDataToFlutterCallBack" arguments:userInfo];
    
    }