Starting from Flutter IM SDK version 5.2.4, you’ll need to upgrade to the new SDK (rongcloud_im_wrapper_plugin).
This guide explains how to manage features from the legacy SDK that cannot be directly replaced.
How to support legacy custom messages
The new SDK (rongcloud_im_wrapper_plugin) has redesigned the implementation of custom message types.
If you’ve upgraded to rongcloud_im_wrapper_plugin
but need to maintain compatibility with legacy custom messages, handle this in the Dart, Android, and iOS layers.
Note: You’ll need to write native layer code. Handling only the Dart layer won’t support custom messages!
Refer to the example for detailed code.
Dart layer handling
-
Define the Dart layer message content based on your custom message. Refer to
example/lib/custom_message/poke_message.dart
.Import headers:
import 'package:rongcloud_im_wrapper_plugin/rongcloud_im_wrapper_plugin.dart'; import 'dart:convert' as json_lib show json;
Define the message class:
-
Your custom message class must extend
RCIMIWUserCustomMessage
. -
Define a
fromJson
constructor and callsuper.fromJson
.RCIMDPokeMessage.fromJson(Map<String, dynamic> json) : super.fromJson(json);
-
Define your own constructor and call the parent class
RCIMIWUserCustomMessage(RCIMIWConversationType type, String targetId)
.RCIMDPokeMessage(RCIMIWConversationType type, String targetId, this.pokeMessage) : super(type, targetId);
-
Implement the parent class’s
decode
andencode
methods.@override void decode(String jsonStr) { Map map = json_lib.json.decode(jsonStr.toString()); // Ensure the key matches the native layer’s key pokeMessage = map['content']; } @override String encode() { Map map = {}; // Ensure the key matches the native layer’s key map['content'] = pokeMessage; return json_lib.json.encode(map); }
-
Implement the parent class’s
messageObjectName
to return theobjectName
. Ensure theobjectName
matches the native layer exactly.@override String messageObjectName() { return "ST:PokeMsg"; }
-
Implement the parent class’s
toJson
method, create aMap
object, and set the'content'
value to the return value of theencode
method.final Map<String, dynamic> json = super.toJson(); // Do not modify 'content' json['content'] = encode(); return json;
-
-
Register the custom message:
Call the engine’s
registerCustomMessage
method to register. Modify only theobjectName
and custom message class.e.registerCustomMessage('ST:PokeMsg', (json){ RCIMDPokeMessage pokeMsg = RCIMDPokeMessage.fromJson(json); // Do not modify 'content' pokeMsg.decode(json['content']); return pokeMsg; });
Android layer handling
-
Add the RC native SDK to your project, ensuring the version matches the one in the Flutter SDK. Check the version in
android/build.gradle
. -
Place the native custom message file in your project and register it in
MainActivity
before initializing the Dart layer.import cn.rongcloud.im.wrapper.flutter.RCIMWrapperEngine;
List<Class<? extends MessageContent>> list = new ArrayList<>(); list.add(PokeMessage.class); RCIMWrapperEngine.getInstance().messageContentClassList = list;
iOS layer handling
-
Import the header file:
#import <rongcloud_im_wrapper_plugin/RCIMWrapperEngine.h>
-
Add the native custom message to your iOS project and register it in
AppDelegate
before initializing the Dart layer.NSMutableArray *marr = [NSMutableArray arrayWithObject:[RCDPokeMessage class]]; [RCIMWrapperEngine sharedInstance].messageContentClassList = marr.copy;
How to implement the legacy conversationDigest feature
With the new custom message optimizations, developers no longer need to handle this in the native layer. To better extend custom message functionality, developers must define their own conversationDigest
logic.
Example:
String conversationDigest(RCIMIWMessage message) {
switch (message.messageType) {
case RCIMIWMessageType.text:
return "text";
case RCIMIWMessageType.voice:
return "[Voice]";
case RCIMIWMessageType.userCustom:
return "[Custom message]";
case RCIMIWMessageType.command:
return "[System message]";
}
}
How to implement the legacy onDataReceived feature
Since onDataReceived
isn’t a standard SDK feature, the new SDK no longer supports it. If you need this functionality, refer to the legacy SDK implementation:
-
Define the
onDataReceived
method in the Dart plugin layer:/// Callback for receiving native data /// /// [data] The data content /// /// For push content, use this in main.dart static Function(Map? data)? onDataReceived;
-
Handle the channel callback in
setMethodCallHandler
: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; } }
-
Call the method in the iOS/Android layer.
Android:
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); } }); }
iOS:
- (void)sendDataToFlutter:(NSDictionary *)userInfo { NSString *LOG_TAG = @"sendDataToFlutter"; [RCLog i:[NSString stringWithFormat:@"%@,start param:%@",LOG_TAG,userInfo]]; [self.channel invokeMethod:@"SendDataToFlutterCallBack" arguments:userInfo]; }