diff --git a/CHANGELOG.md b/CHANGELOG.md
index e787504..080a103 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,19 @@
 ## 2.3.5+1
 
 - Add birthTime for UserInfo
+- Add setMessageKvInfoListener method for MessageManager
+- Add setMessageReactionExtensions method for MessageManager
+- Add deleteMessageReactionExtensions method for MessageManager
+- Add getMessageListReactionExtensions method for MessageManager
+- Add onRecvMessageExtensionsChanged method for OnAdvancedMsgListener
+- Add onRecvMessageExtensionsDeleted method for OnAdvancedMsgListener
+- Add OnMessageKvInfoListener listener
+- Add class KeyValue
+- Add class UserExInfo
+- Add class SingleTypeKeyInfoSum
+- Add class MessageKv
+- Add class TypeKeySetResult
+- Add class MessageTypeKeyMapping
 
 ## 2.3.5
 
diff --git a/android/build.gradle b/android/build.gradle
index 8060f3e..27736d3 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -34,5 +34,5 @@ android {
     }
 }
 dependencies {
-    api 'io.openim:core-sdk:2.3.5-t04@aar'
+    api 'io.openim:core-sdk:2.3.5-t08@aar'
 }
\ No newline at end of file
diff --git a/android/src/main/java/io/openim/flutter_openim_sdk/listener/OnAdvancedMsgListener.java b/android/src/main/java/io/openim/flutter_openim_sdk/listener/OnAdvancedMsgListener.java
index 19618c3..a8c6aa4 100644
--- a/android/src/main/java/io/openim/flutter_openim_sdk/listener/OnAdvancedMsgListener.java
+++ b/android/src/main/java/io/openim/flutter_openim_sdk/listener/OnAdvancedMsgListener.java
@@ -37,6 +37,24 @@ public class OnAdvancedMsgListener implements open_im_sdk_callback.OnAdvancedMsg
         CommonUtil.emitEvent("advancedMsgListener", "onRecvGroupReadReceipt", values);
     }
 
+    @Override
+    public void onRecvMessageExtensionsChanged(String s, String s1) {
+        final Map<String, String> values = new ArrayMap<>();
+        values.put("id", id);
+        values.put("msgID", s);
+        values.put("list", s1);
+        CommonUtil.emitEvent("advancedMsgListener", "onRecvMessageExtensionsChanged", values);
+    }
+
+    @Override
+    public void onRecvMessageExtensionsDeleted(String s, String s1) {
+        final Map<String, String> values = new ArrayMap<>();
+        values.put("id", id);
+        values.put("msgID", s);
+        values.put("list", s1);
+        CommonUtil.emitEvent("advancedMsgListener", "onRecvMessageExtensionsDeleted", values);
+    }
+
     @Override
     public void onRecvMessageRevoked(String s) {
         final Map<String, String> values = new ArrayMap<>();
diff --git a/android/src/main/java/io/openim/flutter_openim_sdk/listener/OnMessageKvInfoListener.java b/android/src/main/java/io/openim/flutter_openim_sdk/listener/OnMessageKvInfoListener.java
new file mode 100644
index 0000000..5786c59
--- /dev/null
+++ b/android/src/main/java/io/openim/flutter_openim_sdk/listener/OnMessageKvInfoListener.java
@@ -0,0 +1,12 @@
+package io.openim.flutter_openim_sdk.listener;
+
+import io.openim.flutter_openim_sdk.util.CommonUtil;
+
+public class OnMessageKvInfoListener implements open_im_sdk_callback.OnMessageKvInfoListener {
+
+    // 经过聚合后的kv,计算了总数,判断了是否包含自己
+    @Override
+    public void onMessageKvInfoChanged(String s) {
+        CommonUtil.emitEvent("messageKvInfoListener", "onMessageKvInfoChanged", s);
+    }
+}
diff --git a/android/src/main/java/io/openim/flutter_openim_sdk/manager/MessageManager.java b/android/src/main/java/io/openim/flutter_openim_sdk/manager/MessageManager.java
index 2ce6ce6..ba9d0ea 100644
--- a/android/src/main/java/io/openim/flutter_openim_sdk/manager/MessageManager.java
+++ b/android/src/main/java/io/openim/flutter_openim_sdk/manager/MessageManager.java
@@ -5,6 +5,7 @@ import io.flutter.plugin.common.MethodChannel;
 import io.openim.flutter_openim_sdk.listener.OnAdvancedMsgListener;
 import io.openim.flutter_openim_sdk.listener.OnBaseListener;
 import io.openim.flutter_openim_sdk.listener.OnCustomBusinessListener;
+import io.openim.flutter_openim_sdk.listener.OnMessageKvInfoListener;
 import io.openim.flutter_openim_sdk.listener.OnMsgSendListener;
 import io.openim.flutter_openim_sdk.util.CommonUtil;
 import open_im_sdk.Open_im_sdk;
@@ -484,4 +485,36 @@ public class MessageManager extends BaseManager {
 
         result.success(null);
     }
+
+    public void setMessageKvInfoListener(MethodCall methodCall, MethodChannel.Result result) {
+        Open_im_sdk.setMessageKvInfoListener(new OnMessageKvInfoListener());
+
+        result.success(null);
+    }
+
+    public void setMessageReactionExtensions(MethodCall methodCall, MethodChannel.Result result) {
+        Open_im_sdk.setMessageReactionExtensions(
+                new OnBaseListener(result, methodCall),
+                value(methodCall, "operationID"),
+                jsonValue(methodCall, "message"),
+                jsonValue(methodCall, "list")
+        );
+    }
+
+    public void deleteMessageReactionExtensions(MethodCall methodCall, MethodChannel.Result result) {
+        Open_im_sdk.deleteMessageReactionExtensions(
+                new OnBaseListener(result, methodCall),
+                value(methodCall, "operationID"),
+                jsonValue(methodCall, "message"),
+                jsonValue(methodCall, "list")
+        );
+    }
+
+    public void getMessageListReactionExtensions(MethodCall methodCall, MethodChannel.Result result) {
+        Open_im_sdk.getMessageListReactionExtensions(
+                new OnBaseListener(result, methodCall),
+                value(methodCall, "operationID"),
+                jsonValue(methodCall, "messageList")
+        );
+    }
 }
diff --git a/lib/flutter_openim_sdk.dart b/lib/flutter_openim_sdk.dart
index a96351a..cbbe50a 100644
--- a/lib/flutter_openim_sdk.dart
+++ b/lib/flutter_openim_sdk.dart
@@ -16,6 +16,7 @@ export 'src/listener/conversation_listener.dart';
 export 'src/listener/custom_business_listener.dart';
 export 'src/listener/friendship_listener.dart';
 export 'src/listener/group_listener.dart';
+export 'src/listener/message_kv_info_listener.dart';
 export 'src/listener/msg_send_progress_listener.dart';
 export 'src/listener/organization_listener.dart';
 export 'src/listener/signaling_listener.dart';
diff --git a/lib/src/enum/listener_type.dart b/lib/src/enum/listener_type.dart
index 327e41c..90d7968 100644
--- a/lib/src/enum/listener_type.dart
+++ b/lib/src/enum/listener_type.dart
@@ -12,4 +12,5 @@ class ListenerType {
   static final workMomentsListener = "workMomentsListener";
   static final organizationListener = "organizationListener";
   static final customBusinessListener = "customBusinessListener";
+  static final messageKvInfoListener = "messageKvInfoListener";
 }
diff --git a/lib/src/listener/advanced_msg_listener.dart b/lib/src/listener/advanced_msg_listener.dart
index ab769c8..49c0a2a 100644
--- a/lib/src/listener/advanced_msg_listener.dart
+++ b/lib/src/listener/advanced_msg_listener.dart
@@ -7,6 +7,8 @@ class OnAdvancedMsgListener {
   Function(String msgId)? onRecvMessageRevoked;
   Function(Message msg)? onRecvNewMessage;
   Function(RevokedInfo info)? onRecvMessageRevokedV2;
+  Function(String msgID, List<KeyValue> list)? onRecvMessageExtensionsChanged;
+  Function(String msgID, List<String> list)? onRecvMessageExtensionsDeleted;
 
   /// Uniquely identifies
   String id;
@@ -17,6 +19,8 @@ class OnAdvancedMsgListener {
     @deprecated this.onRecvMessageRevoked,
     this.onRecvNewMessage,
     this.onRecvMessageRevokedV2,
+    this.onRecvMessageExtensionsChanged,
+    this.onRecvMessageExtensionsDeleted,
   }) : id = "id_${DateTime.now().microsecondsSinceEpoch}";
 
   /// C2C消息已读回执
@@ -43,4 +47,15 @@ class OnAdvancedMsgListener {
   void recvMessageRevokedV2(RevokedInfo info) {
     onRecvMessageRevokedV2?.call(info);
   }
+
+  /// 收到拓展消息kv改变
+  void recvMessageExtensionsChanged(String msgID, List<KeyValue> list) {
+    onRecvMessageExtensionsChanged?.call(msgID, list);
+  }
+
+  /// 收到扩展消息被删除
+  /// [list] 被删除的TypeKey
+  void recvMessageExtensionsDeleted(String msgID, List<String> list) {
+    onRecvMessageExtensionsDeleted?.call(msgID, list);
+  }
 }
diff --git a/lib/src/listener/message_kv_info_listener.dart b/lib/src/listener/message_kv_info_listener.dart
new file mode 100644
index 0000000..275c2ad
--- /dev/null
+++ b/lib/src/listener/message_kv_info_listener.dart
@@ -0,0 +1,11 @@
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+class OnMessageKvInfoListener {
+  Function(List<MessageKv> list)? onMessageKvInfoChanged;
+
+  OnMessageKvInfoListener({this.onMessageKvInfoChanged});
+
+  void messageKvInfoChanged(List<MessageKv> list) {
+    onMessageKvInfoChanged?.call(list);
+  }
+}
diff --git a/lib/src/manager/im_manager.dart b/lib/src/manager/im_manager.dart
index b03e296..a285b3a 100644
--- a/lib/src/manager/im_manager.dart
+++ b/lib/src/manager/im_manager.dart
@@ -152,6 +152,20 @@ class IMManager {
               var info = Utils.toObj(value, (map) => RevokedInfo.fromJson(map));
               messageManager.msgListener.recvMessageRevokedV2(info);
               break;
+            case 'onRecvMessageExtensionsChanged':
+              var msgID = call.arguments['data']['msgID'];
+              var value = call.arguments['data']['list'];
+              var list = Utils.toList(value, (map) => KeyValue.fromJson(map));
+              messageManager.msgListener
+                  .recvMessageExtensionsChanged(msgID, list);
+              break;
+            case 'onRecvMessageExtensionsDeleted':
+              var msgID = call.arguments['data']['msgID'];
+              var value = call.arguments['data']['list'];
+              var list = Utils.toList(value, (map) => '$map');
+              messageManager.msgListener
+                  .recvMessageExtensionsDeleted(msgID, list);
+              break;
           }
         } else if (call.method == ListenerType.msgSendProgressListener) {
           String type = call.arguments['type'];
@@ -318,8 +332,18 @@ class IMManager {
           String data = call.arguments['data'];
           switch (type) {
             case 'onRecvCustomBusinessMessage':
-              messageManager.customBusinessListener?.onRecvCustomBusinessMessage
-                  ?.call(data);
+              messageManager.customBusinessListener
+                  ?.recvCustomBusinessMessage(data);
+              break;
+          }
+        } else if (call.method == ListenerType.messageKvInfoListener) {
+          String type = call.arguments['type'];
+          String data = call.arguments['data'];
+          switch (type) {
+            case 'onMessageKvInfoChanged':
+              final list =
+                  Utils.toList(data, (map) => MessageKv.fromJson(map)).toList();
+              messageManager.messageKvInfoListener?.messageKvInfoChanged(list);
               break;
           }
         }
diff --git a/lib/src/manager/im_message_manager.dart b/lib/src/manager/im_message_manager.dart
index 1f306e7..cfee7ca 100644
--- a/lib/src/manager/im_message_manager.dart
+++ b/lib/src/manager/im_message_manager.dart
@@ -8,6 +8,7 @@ class MessageManager {
   OnMsgSendProgressListener? msgSendProgressListener;
   late OnAdvancedMsgListener msgListener;
   OnCustomBusinessListener? customBusinessListener;
+  OnMessageKvInfoListener? messageKvInfoListener;
 
   MessageManager(this._channel);
 
@@ -881,6 +882,58 @@ class MessageManager {
     return _channel.invokeMethod('setCustomBusinessListener', _buildParam({}));
   }
 
+  ///
+  Future setMessageKvInfoListener(OnMessageKvInfoListener listener) {
+    this.messageKvInfoListener = listener;
+    return _channel.invokeMethod('setMessageKvInfoListener', _buildParam({}));
+  }
+
+  Future<List<TypeKeySetResult>> setMessageReactionExtensions({
+    required Message message,
+    List<KeyValue> list = const [],
+    String? operationID,
+  }) =>
+      _channel
+          .invokeMethod(
+              'setMessageReactionExtensions',
+              _buildParam({
+                'message': message.toJson(),
+                'list': list.map((e) => e.toJson()).toList(),
+                "operationID": Utils.checkOperationID(operationID),
+              }))
+          .then((value) =>
+              Utils.toList(value, (map) => TypeKeySetResult.fromJson(map)));
+
+  Future<List<TypeKeySetResult>> deleteMessageReactionExtensions({
+    required Message message,
+    List<String> list = const [],
+    String? operationID,
+  }) =>
+      _channel
+          .invokeMethod(
+              'deleteMessageReactionExtensions',
+              _buildParam({
+                'message': message.toJson(),
+                'list': list,
+                "operationID": Utils.checkOperationID(operationID),
+              }))
+          .then((value) =>
+              Utils.toList(value, (map) => TypeKeySetResult.fromJson(map)));
+
+  Future<List<MessageTypeKeyMapping>> getMessageListReactionExtensions({
+    List<Message> messageList = const [],
+    String? operationID,
+  }) =>
+      _channel
+          .invokeMethod(
+              'getMessageListReactionExtensions',
+              _buildParam({
+                'messageList': messageList.map((e) => e.toJson()).toList(),
+                "operationID": Utils.checkOperationID(operationID),
+              }))
+          .then((value) => Utils.toList(
+              value, (map) => MessageTypeKeyMapping.fromJson(map)));
+
   static Map _buildParam(Map param) {
     param["ManagerName"] = "messageManager";
     return param;
diff --git a/lib/src/models/message.dart b/lib/src/models/message.dart
index f178627..123ef7a 100644
--- a/lib/src/models/message.dart
+++ b/lib/src/models/message.dart
@@ -1113,3 +1113,173 @@ class RichMessageInfo {
     return data;
   }
 }
+
+///////////////////// 消息修改相关/////////////////////
+////////////////////////////////////////////////////
+
+class KeyValue {
+  String? typeKey;
+  String? value;
+  int? latestUpdateTime;
+
+  KeyValue({this.typeKey, this.value, this.latestUpdateTime});
+
+  KeyValue.fromJson(Map<String, dynamic> json) {
+    typeKey = json['typeKey'];
+    value = json['value'];
+    latestUpdateTime = json['latestUpdateTime'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final data = Map<String, dynamic>();
+    data['typeKey'] = this.typeKey;
+    data['value'] = this.value;
+    data['latestUpdateTime'] = this.latestUpdateTime;
+    return data;
+  }
+}
+
+class UserExInfo {
+  String? userID;
+  String? ex;
+
+  UserExInfo({this.userID, this.ex});
+
+  UserExInfo.fromJson(Map<String, dynamic> json) {
+    userID = json['userID'];
+    ex = json['ex'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final data = Map<String, dynamic>();
+    data['userID'] = this.userID;
+    data['ex'] = this.ex;
+    return data;
+  }
+}
+
+class SingleTypeKeyInfoSum {
+  String? typeKey;
+  int? counter;
+  List<UserExInfo>? infoList;
+  bool? isContainSelf;
+
+  SingleTypeKeyInfoSum({
+    this.typeKey,
+    this.counter,
+    this.infoList,
+    this.isContainSelf,
+  });
+
+  SingleTypeKeyInfoSum.fromJson(Map<String, dynamic> json) {
+    typeKey = json['typeKey'];
+    counter = json['counter'];
+    infoList = json['infoList'] == null
+        ? null
+        : (json['infoList'] as List)
+            .map((e) => UserExInfo.fromJson(e))
+            .toList();
+    isContainSelf = json['isContainSelf'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final data = Map<String, dynamic>();
+    data['typeKey'] = this.typeKey;
+    data['counter'] = this.counter;
+    data['infoList'] = this.infoList?.map((e) => e.toJson()).toList();
+    data['isContainSelf'] = this.isContainSelf;
+    return data;
+  }
+}
+
+class MessageKv {
+  String? clientMsgID;
+  List<SingleTypeKeyInfoSum>? changedKvList;
+
+  MessageKv({this.clientMsgID, this.changedKvList});
+
+  MessageKv.fromJson(Map<String, dynamic> json) {
+    clientMsgID = json['clientMsgID'];
+    changedKvList = json['changedKvList'] == null
+        ? null
+        : (json['changedKvList'] as List)
+            .map((e) => SingleTypeKeyInfoSum.fromJson(e))
+            .toList();
+  }
+
+  Map<String, dynamic> toJson() {
+    final data = Map<String, dynamic>();
+    data['clientMsgID'] = this.clientMsgID;
+    data['changedKvList'] = this.changedKvList?.map((e) => e.toJson()).toList();
+    return data;
+  }
+}
+
+class TypeKeySetResult {
+  int? errCode;
+  String? errMsg;
+  String? typeKey;
+  int? latestUpdateTime;
+  String? value;
+
+  TypeKeySetResult(
+      {this.errCode,
+      this.errMsg,
+      this.typeKey,
+      this.latestUpdateTime,
+      this.value});
+
+  TypeKeySetResult.fromJson(Map<String, dynamic> json) {
+    errCode = json['errCode'];
+    errMsg = json['errMsg'];
+    typeKey = json['typeKey'];
+    latestUpdateTime = json['latestUpdateTime'];
+    value = json['value'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['errCode'] = this.errCode;
+    data['errMsg'] = this.errMsg;
+    data['typeKey'] = this.typeKey;
+    data['latestUpdateTime'] = this.latestUpdateTime;
+    data['value'] = this.value;
+    return data;
+  }
+}
+
+class MessageTypeKeyMapping {
+  int? errCode;
+  String? errMsg;
+  Map<String, KeyValue>? reactionExtensionList;
+  String? clientMsgID;
+
+  MessageTypeKeyMapping(
+      {this.errCode,
+      this.errMsg,
+      this.reactionExtensionList,
+      this.clientMsgID});
+
+  MessageTypeKeyMapping.fromJson(Map<String, dynamic> json) {
+    errCode = json['errCode'];
+    errMsg = json['errMsg'];
+    reactionExtensionList = json['reactionExtensionList'] != null
+        ? (json['reactionExtensionList'] as Map)
+            .map((key, value) => MapEntry(key, KeyValue.fromJson(value)))
+        : null;
+    clientMsgID = json['clientMsgID'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['errCode'] = this.errCode;
+    data['errMsg'] = this.errMsg;
+    if (this.reactionExtensionList != null) {
+      data['reactionExtensionList'] = this
+          .reactionExtensionList!
+          .map((key, value) => MapEntry(key, value.toJson()));
+    }
+    data['clientMsgID'] = this.clientMsgID;
+    return data;
+  }
+}