diff --git a/lib/src/enum/listener_type.dart b/lib/src/enum/listener_type.dart
new file mode 100644
index 0000000..a184055
--- /dev/null
+++ b/lib/src/enum/listener_type.dart
@@ -0,0 +1,33 @@
+
+class ListenerType {
+  ///
+  ///
+  static const String simpleMsgListener = 'simpleMsgListener';
+
+  ///
+  ///
+  static const String initSDKListener = 'initSDKListener';
+
+  ///
+  ///
+  static const String groupListener = 'groupListener';
+
+  ///
+  ///
+  static const String advancedMsgListener = 'advancedMsgListener';
+
+  ///
+  ///
+  static const String conversationListener = 'conversationListener';
+
+  ///
+  ///
+  static const String friendListener = 'friendListener';
+
+  ///
+  ///
+  static const String signalingListener = 'signalingListener';
+
+  ///
+  static const String msgSendProgressListener = "msgSendProgressListener";
+}
diff --git a/lib/src/enum/message_type.dart b/lib/src/enum/message_type.dart
new file mode 100644
index 0000000..6a10a75
--- /dev/null
+++ b/lib/src/enum/message_type.dart
@@ -0,0 +1,18 @@
+class MessageType {
+  ///
+  static const text = 101;
+
+  ///
+  static const picture = 102;
+
+  ///
+  static const voice = 103;
+
+  ///
+  static const video = 104;
+
+  ///
+  static const file = 105;
+
+  static const accept_friend = 201;
+}
diff --git a/lib/src/listener/advanced_msg_listener.dart b/lib/src/listener/advanced_msg_listener.dart
new file mode 100644
index 0000000..796e7e1
--- /dev/null
+++ b/lib/src/listener/advanced_msg_listener.dart
@@ -0,0 +1,15 @@
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+
+class AdvancedMsgListener {
+  /// listener uniquely identifies
+  final String id;
+
+  AdvancedMsgListener({required this.id});
+
+  void onRecvNewMessage(Message msg) {}
+
+  void onRecvC2CReadReceipt(Message msg) {}
+
+  void onRecvMessageRevoked(Message msg) {}
+}
diff --git a/lib/src/listener/conversation_listener.dart b/lib/src/listener/conversation_listener.dart
new file mode 100644
index 0000000..42b399e
--- /dev/null
+++ b/lib/src/listener/conversation_listener.dart
@@ -0,0 +1,15 @@
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+class ConversationListener {
+  void onConversationChanged(List<ConversationInfo> list) {}
+
+  void onNewConversation(List<ConversationInfo> list) {}
+
+  void onSyncServerFailed() {}
+
+  void onSyncServerFinish() {}
+
+  void onSyncServerStart() {}
+
+  void onTotalUnreadMessageCountChanged(int i) {}
+}
diff --git a/lib/src/listener/friendship_listener.dart b/lib/src/listener/friendship_listener.dart
new file mode 100644
index 0000000..3baad76
--- /dev/null
+++ b/lib/src/listener/friendship_listener.dart
@@ -0,0 +1,19 @@
+class FriendshipListener {
+  void onBlackListAdd(dynamic u) {}
+
+  void onBlackListDeleted(dynamic u) {}
+
+  void onFriendApplicationListAccept(dynamic u) {}
+
+  void onFriendApplicationListAdded(dynamic u) {}
+
+  void onFriendApplicationListDeleted(dynamic u) {}
+
+  void onFriendApplicationListReject(dynamic u) {}
+
+  void onFriendInfoChanged(dynamic u) {}
+
+  void onFriendListAdded(dynamic u) {}
+
+  void onFriendListDeleted(dynamic u) {}
+}
diff --git a/lib/src/listener/init_sdk_listener.dart b/lib/src/listener/init_sdk_listener.dart
new file mode 100644
index 0000000..3711817
--- /dev/null
+++ b/lib/src/listener/init_sdk_listener.dart
@@ -0,0 +1,21 @@
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+class InitSDKListener {
+  /// SDK 正在连接到服务器
+  void onConnecting() {}
+
+  /// SDK 已经成功连接到服务器
+  void onConnectSuccess() {}
+
+  /// SDK 连接服务器失败
+  void onConnectFailed(int? int, String? errorMsg) {}
+
+  /// 当前用户被踢下线,此时可以 UI 提示用户,并再次调用 IMManager 的 login() 函数重新登录。
+  void onKickedOffline() {}
+
+  ///  在线时票据过期:此时您需要生成新的 userSig 并再次调用 IMManager 的 login() 函数重新登录
+  void onUserSigExpired() {}
+
+  /// 登录用户的资料发生了更新
+  void onSelfInfoUpdated(UserInfo info) {}
+}
diff --git a/lib/src/listener/msg_send_progress_listener.dart b/lib/src/listener/msg_send_progress_listener.dart
new file mode 100644
index 0000000..10fd4e4
--- /dev/null
+++ b/lib/src/listener/msg_send_progress_listener.dart
@@ -0,0 +1,3 @@
+class MsgSendProgressListener {
+  void onProgress(String msgID, int progress) {}
+}
diff --git a/lib/src/manager/im_conversation_manager.dart b/lib/src/manager/im_conversation_manager.dart
new file mode 100644
index 0000000..2354abb
--- /dev/null
+++ b/lib/src/manager/im_conversation_manager.dart
@@ -0,0 +1,94 @@
+import 'dart:convert';
+
+import 'package:flutter/services.dart';
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+class ConversationManager {
+  MethodChannel _channel;
+  late ConversationListener conversationListener;
+
+  ConversationManager(this._channel);
+
+  void setConversationListener(ConversationListener listener) {
+    this.conversationListener = listener;
+    _channel.invokeMethod('setConversationListener', _buildParam({}));
+  }
+
+  Future<List<ConversationInfo>> getAllConversationList() {
+    return _channel
+        .invokeMethod('getAllConversationList', _buildParam({}))
+        .then((value) => _toList(value));
+  }
+
+  /// sourceID 若为单聊则为userID,若为群聊则为groupID
+  /// sessionType 若为单聊则为1,若为群聊则为2
+  Future<ConversationInfo> getSingleConversation(
+      {required String sourceID, required String sessionType}) {
+    return _channel
+        .invokeMethod('getOneConversation',
+            _buildParam({"sourceID": sourceID, "sessionType": sessionType}))
+        .then((value) => _toObj(value));
+  }
+
+  /// ["single_1234","group_3434"]
+  Future<List<ConversationInfo>> getMultipleConversation(
+      {required List<String> conversationIDList}) {
+    return _channel
+        .invokeMethod('getMultipleConversation',
+            _buildParam({"conversationIDList": conversationIDList}))
+        .then((value) => _toList(value));
+  }
+
+  void deleteConversation({required String conversationID}) {
+    _channel
+        .invokeMethod('deleteConversation',
+            _buildParam({"conversationID": conversationID}))
+        .then((value) => _printValue(value));
+  }
+
+  void setConversationDraft(
+      {required String conversationID, required String draftText}) {
+    _channel
+        .invokeMethod(
+            'setConversationDraft',
+            _buildParam(
+                {"conversationID": conversationID, "draftText": draftText}))
+        .then((value) => _printValue(value));
+  }
+
+  void pinConversation(
+      {required String conversationID, required bool isPinned}) {
+    _channel
+        .invokeMethod(
+            'pinConversation',
+            _buildParam(
+                {"conversationID": conversationID, "isPinned": isPinned}))
+        .then((value) => _printValue(value));
+  }
+
+  Future<dynamic> getTotalUnreadMsgCount() {
+    return _channel.invokeMethod('getTotalUnreadMsgCount', _buildParam({}));
+  }
+
+  static Map _buildParam(Map param) {
+    param["ManagerName"] = "conversationManager";
+    return param;
+  }
+
+  static List<ConversationInfo> _toList(String? value) {
+    var list = _formatJson(value);
+    if (null == list) return <ConversationInfo>[];
+    return (list as List).map((e) => ConversationInfo.fromJson(e)).toList();
+  }
+
+  static ConversationInfo _toObj(String value) =>
+      ConversationInfo.fromJson(_formatJson(value));
+
+  static dynamic _formatJson(value) {
+    return jsonDecode(_printValue(value));
+  }
+
+  static String _printValue(value) {
+    return value;
+  }
+}
diff --git a/lib/src/manager/im_friendship_manager.dart b/lib/src/manager/im_friendship_manager.dart
new file mode 100644
index 0000000..6f61d2c
--- /dev/null
+++ b/lib/src/manager/im_friendship_manager.dart
@@ -0,0 +1,112 @@
+import 'dart:convert';
+
+import 'package:flutter/services.dart';
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+class FriendshipManager {
+  MethodChannel _channel;
+  late FriendshipListener friendshipListener;
+
+  FriendshipManager(this._channel);
+
+  void setFriendshipListener(FriendshipListener listener) {
+    this.friendshipListener = listener;
+    _channel.invokeMethod('setFriendListener', _buildParam({}));
+  }
+
+  Future<List<UserInfo>> getFriendsInfo({required List<String> uidList}) {
+    return _channel
+        .invokeMethod('getFriendsInfo', _buildParam({"uidList": uidList}))
+        .then((value) => _toList(value));
+  }
+
+  Future<dynamic> addFriend({required String uid, required String reason}) {
+    return _channel.invokeMethod(
+        'addFriend', _buildParam({"uid": uid, "reqMessage": reason}));
+  }
+
+  Future<List<UserInfo>> getFriendApplicationList() {
+    return _channel
+        .invokeMethod('getFriendApplicationList', _buildParam({}))
+        .then((value) => _toList(value));
+  }
+
+  Future<List<UserInfo>> getFriendList() {
+    return _channel
+        .invokeMethod('getFriendList', _buildParam({}))
+        .then((value) => _toList(value));
+  }
+
+  Future<dynamic> setFriendInfo({required UserInfo info}) {
+    return _channel.invokeMethod('setFriendInfo', _buildParam(info.toJson()));
+  }
+
+  Future<dynamic> addToBlackList({required String uid}) {
+    return _channel.invokeMethod('addToBlackList', _buildParam({"uid": uid}));
+  }
+
+  Future<List<UserInfo>> getBlackList() {
+    return _channel
+        .invokeMethod('getBlackList', _buildParam({}))
+        .then((value) => _toList(value));
+  }
+
+  Future<dynamic> deleteFromBlackList({required String uid}) {
+    return _channel.invokeMethod(
+        'deleteFromBlackList', _buildParam({"uid": uid}));
+  }
+
+  Future<List<UserInfo>> checkFriend(List<String> uidList) {
+    return _channel
+        .invokeMethod('checkFriend', _buildParam({'uidList': uidList}))
+        .then((value) => _toList(value));
+  }
+
+  Future<dynamic> deleteFromFriendList({required String uid}) {
+    return _channel.invokeMethod(
+        'deleteFromFriendList', _buildParam({"uid": uid}));
+  }
+
+  Future<dynamic> acceptFriendApplication({required String uid}) {
+    return _channel.invokeMethod(
+        'acceptFriendApplication', _buildParam({"uid": uid}));
+  }
+
+  Future<dynamic> refuseFriendApplication({required String uid}) {
+    return _channel.invokeMethod(
+        'refuseFriendApplication', _buildParam({"uid": uid}));
+  }
+
+  Future<dynamic> forceSyncFriendApplication() {
+    return _channel.invokeMethod('forceSyncFriendApplication', _buildParam({}));
+  }
+
+  Future<dynamic> forceSyncFriend() {
+    return _channel.invokeMethod('forceSyncFriend', _buildParam({}));
+  }
+
+  Future<dynamic> forceSyncBlackList() {
+    return _channel.invokeMethod('forceSyncBlackList', _buildParam({}));
+  }
+
+  static Map _buildParam(Map param) {
+    param["ManagerName"] = "friendshipManager";
+    return param;
+  }
+
+  static List<UserInfo> _toList(String? value) {
+    var list = _formatJson(value);
+    if (null == list) return <UserInfo>[];
+    return (list as List).map((e) => UserInfo.fromJson(e)).toList();
+  }
+
+  static UserInfo _toObj(String value) => UserInfo.fromJson(_formatJson(value));
+
+  static dynamic _formatJson(value) {
+    return jsonDecode(_printValue(value));
+  }
+
+  static String _printValue(value) {
+    return value;
+  }
+}
diff --git a/lib/src/manager/im_group_manager.dart b/lib/src/manager/im_group_manager.dart
new file mode 100644
index 0000000..c077212
--- /dev/null
+++ b/lib/src/manager/im_group_manager.dart
@@ -0,0 +1,7 @@
+import 'package:flutter/services.dart';
+
+class GroupManager{
+  MethodChannel _channel;
+
+  GroupManager(this._channel);
+}
\ No newline at end of file
diff --git a/lib/src/manager/im_manager.dart b/lib/src/manager/im_manager.dart
new file mode 100644
index 0000000..24e6056
--- /dev/null
+++ b/lib/src/manager/im_manager.dart
@@ -0,0 +1,317 @@
+import 'dart:convert';
+
+import 'package:flutter/services.dart';
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+class IMManager {
+  MethodChannel _channel;
+  late ConversationManager conversationManager;
+  late FriendshipManager friendshipManager;
+  late MessageManager messageManager;
+  late GroupManager groupManager;
+  late OfflinePushManager offlinePushManager;
+  late SignalingManager signalingManager;
+  late InitSDKListener _initSDKListener;
+
+  IMManager(this._channel) {
+    conversationManager = ConversationManager(_channel);
+    friendshipManager = FriendshipManager(_channel);
+    messageManager = MessageManager(_channel);
+    groupManager = GroupManager(_channel);
+    offlinePushManager = OfflinePushManager(_channel);
+    signalingManager = SignalingManager(_channel);
+    addNativeCallback(_channel);
+  }
+
+  void addNativeCallback(MethodChannel _channel) {
+    _channel.setMethodCallHandler((call) {
+      try {
+        if (call.method == ListenerType.initSDKListener) {
+          String type = call.arguments['type'];
+          dynamic data = call.arguments['data'];
+          switch (type) {
+            case 'onSelfInfoUpdated':
+              var u = UserInfo.fromJson(_formatJson(data));
+              _initSDKListener.onSelfInfoUpdated(u);
+              break;
+            case 'onConnectFailed':
+              int? errCode = call.arguments['errCode'];
+              String? errMsg = call.arguments['errMsg'];
+              _initSDKListener.onConnectFailed(errCode, errMsg);
+              break;
+            case 'onConnecting':
+              _initSDKListener.onConnecting();
+              break;
+            case 'onConnectSuccess':
+              _initSDKListener.onConnectSuccess();
+              break;
+            case 'onKickedOffline':
+              _initSDKListener.onKickedOffline();
+              break;
+            case 'onUserSigExpired':
+              _initSDKListener.onUserSigExpired();
+              break;
+          }
+        } else if (call.method == ListenerType.groupListener) {
+          var args = call.arguments;
+          String type = args['type'];
+          Map<String, dynamic> params = args['data'] == null
+              ? new Map<String, dynamic>()
+              : new Map<String, dynamic>.from(args['data']);
+
+          String groupID = params['groupID'] == null ? '' : params['groupID'];
+          String opReason =
+              params['opReason'] == null ? '' : params['opReason'];
+          bool isAgreeJoin =
+              params['isAgreeJoin'] == null ? false : params['isAgreeJoin'];
+          String customData =
+              params['customData'] == null ? '' : params['customData'];
+
+          Map<String, String> groupAttributeMap =
+              params['groupAttributeMap'] == null
+                  ? new Map<String, String>()
+                  : new Map<String, String>.from(params['groupAttributeMap']);
+
+          List<Map<String, dynamic>> memberListMap =
+              params['memberList'] == null
+                  ? List.empty(growable: true)
+                  : List.from(params['memberList']);
+
+          List<Map<String, dynamic>> groupMemberChangeInfoListMap =
+              params['groupMemberChangeInfoList'] == null
+                  ? List.empty(growable: true)
+                  : List.from(params['groupMemberChangeInfoList']);
+
+          List<Map<String, dynamic>> groupChangeInfoListMap =
+              params['groupChangeInfoList'] == null
+                  ? List.empty(growable: true)
+                  : List.from(params['groupChangeInfoList']);
+
+          switch (type) {
+            case 'onMemberEnter':
+              break;
+            case 'onMemberLeave':
+              break;
+            case 'onMemberInvited':
+              break;
+            case 'onMemberKicked':
+              break;
+            case 'onMemberInfoChanged':
+              break;
+            case 'onGroupCreated':
+              break;
+            case 'onGroupDismissed':
+              break;
+            case 'onGroupRecycled':
+              break;
+            case 'onGroupInfoChanged':
+              break;
+            case 'onReceiveJoinApplication':
+              break;
+            case 'onApplicationProcessed':
+              break;
+            case 'onGrantAdministrator':
+              break;
+            case 'onRevokeAdministrator':
+              break;
+            case 'onQuitFromGroup':
+              break;
+            case 'onReceiveRESTCustomData':
+              break;
+            case 'onGroupAttributeChanged':
+              break;
+          }
+        } else if (call.method == ListenerType.advancedMsgListener) {
+          var type = call.arguments['type'];
+          var id = call.arguments['data']['id'];
+          var msg =
+              Message.fromJson(_formatJson(call.arguments['data']['message']));
+          switch (type) {
+            case 'onRecvNewMessage':
+              for (var listener in messageManager.advancedMsgListeners) {
+                if (listener.id == id) {
+                  listener.onRecvNewMessage(msg);
+                }
+              }
+              break;
+            case 'onRecvMessageRevoked':
+              for (var listener in messageManager.advancedMsgListeners) {
+                if (listener.id == id) {
+                  listener.onRecvMessageRevoked(msg);
+                }
+              }
+              break;
+            case 'onRecvC2CReadReceipt':
+              for (var listener in messageManager.advancedMsgListeners) {
+                if (listener.id == id) {
+                  listener.onRecvC2CReadReceipt(msg);
+                }
+              }
+              break;
+          }
+        } else if (call.method == ListenerType.msgSendProgressListener) {
+          String type = call.arguments['type'];
+          dynamic data = call.arguments['data'];
+          String msgID = data['clientMsgID'] ?? '';
+          int progress = data['progress'] ?? 100;
+          switch (type) {
+            case 'onProgress':
+              messageManager.msgSendProgressListener?.onProgress(
+                msgID,
+                progress,
+              );
+              break;
+          }
+        } else if (call.method == ListenerType.conversationListener) {
+          String type = call.arguments['type'];
+          dynamic data = call.arguments['data'];
+          switch (type) {
+            case 'onSyncServerStart':
+              conversationManager.conversationListener.onSyncServerStart();
+              break;
+            case 'onSyncServerFinish':
+              conversationManager.conversationListener.onSyncServerFinish();
+              break;
+
+            case 'onSyncServerFailed':
+              conversationManager.conversationListener.onSyncServerFailed();
+              break;
+            case 'onNewConversation':
+              List<ConversationInfo> list = List.empty(growable: true);
+              if (null != data) {
+                list = (_formatJson(data) as List)
+                    .map((e) => ConversationInfo.fromJson(e))
+                    .toList();
+              }
+              conversationManager.conversationListener.onNewConversation(list);
+              break;
+            case 'onConversationChanged':
+              List<ConversationInfo> list = List.empty(growable: true);
+              if (null != data) {
+                list = (_formatJson(data) as List)
+                    .map((e) => ConversationInfo.fromJson(e))
+                    .toList();
+              }
+              conversationManager.conversationListener
+                  .onConversationChanged(list);
+              break;
+            case 'onTotalUnreadMessageCountChanged':
+              conversationManager.conversationListener
+                  .onTotalUnreadMessageCountChanged(data ?? 0);
+              break;
+          }
+        } else if (call.method == ListenerType.friendListener) {
+          String type = call.arguments['type'];
+          dynamic data = call.arguments['data'];
+          switch (type) {
+            case 'onBlackListAdd':
+              friendshipManager.friendshipListener.onBlackListAdd(data);
+              break;
+            case 'onBlackListDeleted':
+              friendshipManager.friendshipListener.onBlackListDeleted(data);
+              break;
+            case 'onFriendApplicationListAccept':
+              friendshipManager.friendshipListener
+                  .onFriendApplicationListAccept(data);
+              break;
+            case 'onFriendApplicationListAdded':
+              friendshipManager.friendshipListener
+                  .onFriendApplicationListAdded(data);
+              break;
+            case 'onFriendApplicationListDeleted':
+              friendshipManager.friendshipListener
+                  .onFriendApplicationListDeleted(data);
+              break;
+            case 'onFriendApplicationListReject':
+              friendshipManager.friendshipListener
+                  .onFriendApplicationListReject(data);
+              break;
+            case 'onFriendInfoChanged':
+              friendshipManager.friendshipListener.onFriendInfoChanged(data);
+              break;
+            case 'onFriendListAdded':
+              friendshipManager.friendshipListener.onFriendListAdded(data);
+              break;
+            case 'onFriendListDeleted':
+              friendshipManager.friendshipListener.onFriendListDeleted(data);
+              break;
+          }
+        }
+      } catch (err) {
+        print(
+            "回调失败了,数据类型异常。$err ${call.method} ${call.arguments['type']} ${call.arguments['data']}");
+      }
+      return Future.value(null);
+    });
+  }
+
+  Future<dynamic> initSDK({
+    required int platform,
+    required String ipApi,
+    required String ipWs,
+    required String dbPath,
+    required InitSDKListener listener,
+  }) {
+    _initSDKListener = listener;
+    return _channel.invokeMethod(
+      'initSDK',
+      _buildParam(
+        {"platform": platform, "ipApi": ipApi, "ipWs": ipWs, "dbDir": dbPath},
+      ),
+    );
+  }
+
+  Future<dynamic> unInitSDK() {
+    return _channel.invokeMethod('unInitSDK', _buildParam({}));
+  }
+
+  Future<dynamic> login({required String uid, required String token}) {
+    return _channel.invokeMethod(
+      'login',
+      _buildParam({'uid': uid, 'token': token}),
+    );
+  }
+
+  Future<dynamic> logout() {
+    return _channel.invokeMethod('logout', _buildParam({}));
+  }
+
+  Future<int?> getLoginStatus() {
+    return _channel.invokeMethod<int>('getLoginStatus', _buildParam({}));
+  }
+
+  Future<String?> getLoginUid() {
+    return _channel.invokeMethod<String>('getLoginUid', _buildParam({}));
+  }
+
+  Future<String?> setSelfInfo(UserInfo info) {
+    return _channel.invokeMethod('setSelfInfo', _buildParam(info.toJson()));
+    // .then((value) => UserInfo.fromJson(value));
+  }
+
+  Future<List<UserInfo>> getUsersInfo(List<String> uidList) {
+    return _channel
+        .invokeMethod('getUsersInfo', _buildParam({'uidList': uidList}))
+        .then((value) => _toList(value));
+  }
+
+  Future<dynamic> forceSyncLoginUerInfo(List<String> uidList) {
+    return _channel.invokeMethod('forceSyncLoginUerInfo', _buildParam({}));
+  }
+
+  static Map _buildParam(Map param) {
+    param["ManagerName"] = "imManager";
+    return param;
+  }
+
+  static List<UserInfo> _toList(String value) =>
+      (_formatJson(value) as List).map((e) => UserInfo.fromJson(e)).toList();
+
+  static dynamic _formatJson(value) {
+    return jsonDecode(_printValue(value));
+  }
+
+  static String _printValue(value) {
+    return value;
+  }
+}
diff --git a/lib/src/manager/im_message_manager.dart b/lib/src/manager/im_message_manager.dart
new file mode 100644
index 0000000..72bab02
--- /dev/null
+++ b/lib/src/manager/im_message_manager.dart
@@ -0,0 +1,213 @@
+import 'dart:convert';
+
+import 'package:flutter/services.dart';
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+class MessageManager {
+  MethodChannel _channel;
+  List<AdvancedMsgListener> advancedMsgListeners = List.empty(growable: true);
+  MsgSendProgressListener? msgSendProgressListener;
+
+  MessageManager(this._channel);
+
+  void addAdvancedMsgListener(AdvancedMsgListener listener) {
+    advancedMsgListeners.add(listener);
+    _channel.invokeMethod(
+        'addAdvancedMsgListener', _buildParam({'id': listener.id}));
+  }
+
+  void removeAdvancedMsgListener(AdvancedMsgListener listener) {
+    advancedMsgListeners.remove(listener);
+    _channel.invokeMethod(
+        'removeAdvancedMsgListener', _buildParam({'id': listener.id}));
+  }
+
+  void setMsgSendProgressListener(MsgSendProgressListener listener) {
+    msgSendProgressListener = listener;
+  }
+
+  /*Future<Message> */
+  Future<dynamic> sendMessage({
+    required Message message,
+    String? receiver,
+    String? groupID,
+    required bool onlineUserOnly,
+  }) {
+    return _channel.invokeMethod(
+            'sendMessage',
+            _buildParam({
+              'message': message.toJson(),
+              'receiver': receiver ?? '',
+              'groupID': groupID ?? '',
+              'onlineUserOnly': onlineUserOnly,
+            }))
+        /*.then((value) => _toObj(value))*/;
+  }
+
+  Future<List<Message>> getHistoryMessageList({
+    String? userID,
+    Message? startMsg,
+    String? groupID,
+    int? count,
+  }) {
+    return _channel
+        .invokeMethod(
+            'getHistoryMessageList',
+            _buildParam({
+              'userID': userID ?? '',
+              'startMsg': startMsg?.toJson() /*?? {}*/,
+              'groupID': groupID ?? '',
+              'count': count ?? 10,
+            }))
+        .then((value) => _toList(value));
+  }
+
+  void revokeMessage({required Message message}) {
+    _channel.invokeMethod('revokeMessage', _buildParam(message.toJson()));
+  }
+
+  Future deleteMessageFromLocalStorage({required Message message}) {
+    return _channel.invokeMethod(
+        'deleteMessageFromLocalStorage', _buildParam(message.toJson()));
+  }
+
+  void deleteMessages({required List<Message> msgList}) {
+    _channel.invokeMethod('deleteMessages',
+        _buildParam({"msgList": msgList.map((e) => e.toJson()).toList()}));
+  }
+
+  void insertSingleMessageToLocalStorage({
+    String? userID,
+    Message? message,
+    String? sender,
+  }) {
+    _channel.invokeMethod(
+        'insertSingleMessageToLocalStorage',
+        _buildParam({
+          "userID": userID,
+          "message": message?.toJson(),
+          "sender": sender,
+        }));
+  }
+
+  void findMessages({required List<String> messageIDList}) {
+    _channel.invokeMethod(
+        'findMessages',
+        _buildParam({
+          "messageIDList": messageIDList,
+        }));
+  }
+
+  Future<dynamic> markSingleMessageHasRead({required String userID}) {
+    return _channel.invokeMethod(
+        'markSingleMessageHasRead', _buildParam({'userID': userID}));
+  }
+
+  Future<Message> createTextMessage({required String text}) {
+    return _channel
+        .invokeMethod('createTextMessage', _buildParam({'text': text}))
+        .then((value) => _toObj(value));
+  }
+
+  Future<Message> createTextAtMessage({
+    required String text,
+    required List<String> atUserList,
+  }) {
+    return _channel
+        .invokeMethod(
+          'createTextAtMessage',
+          _buildParam({
+            'text': text,
+            'atUserList': atUserList,
+          }),
+        )
+        .then((value) => _toObj(value));
+  }
+
+  Future<Message> createImageMessage({required String imagePath}) {
+    return _channel
+        .invokeMethod(
+          'createImageMessage',
+          _buildParam({'imagePath': imagePath}),
+        )
+        .then((value) => _toObj(value));
+  }
+
+  Future<Message> createSoundMessage(
+      {required String soundPath, required int duration}) {
+    return _channel
+        .invokeMethod(
+          'createSoundMessage',
+          _buildParam({'soundPath': soundPath, "duration": duration}),
+        )
+        .then((value) => _toObj(value));
+  }
+
+  Future<Message> createVideoMessage({
+    required String videoPath,
+    required String videoType,
+    required int duration,
+    required String snapshotPath,
+  }) {
+    return _channel
+        .invokeMethod(
+            'createVideoMessage',
+            _buildParam({
+              'videoPath': videoPath,
+              'videoType': videoType,
+              'duration': duration,
+              'snapshotPath': snapshotPath,
+            }))
+        .then((value) => _toObj(value));
+  }
+
+  Future<Message> createFileMessage(
+      {required String filePath, required String fileName}) {
+    return _channel
+        .invokeMethod('createFileMessage',
+            _buildParam({'filePath': filePath, 'fileName': fileName}))
+        .then((value) => _toObj(value));
+  }
+
+  Future<Message> createMergerMessage(
+      {required List<Message> messageList,
+      required String title,
+      required List<String> summaryList}) {
+    return _channel
+        .invokeMethod(
+            'createMergerMessage',
+            _buildParam({
+              'messageList': messageList.map((e) => e.toJson()).toList(),
+              'title': title,
+              'summaryList': summaryList,
+            }))
+        .then((value) => _toObj(value));
+  }
+
+  Future<Message> createForwardMessage({required List<Message> messageList}) {
+    return _channel
+        .invokeMethod(
+            'createForwardMessage',
+            _buildParam(
+                {'message': messageList.map((e) => e.toJson()).toList()}))
+        .then((value) => _toObj(value));
+  }
+
+  static Map _buildParam(Map param) {
+    param["ManagerName"] = "messageManager";
+    return param;
+  }
+
+  static List<Message> _toList(String value) =>
+      (_formatJson(value) as List).map((e) => Message.fromJson(e)).toList();
+
+  static Message _toObj(String value) => Message.fromJson(_formatJson(value));
+
+  static dynamic _formatJson(value) {
+    return jsonDecode(_printValue(value));
+  }
+
+  static String _printValue(value) {
+    return value;
+  }
+}
diff --git a/lib/src/manager/im_offline_push_manager.dart b/lib/src/manager/im_offline_push_manager.dart
new file mode 100644
index 0000000..c6c8256
--- /dev/null
+++ b/lib/src/manager/im_offline_push_manager.dart
@@ -0,0 +1,7 @@
+import 'package:flutter/services.dart';
+
+class OfflinePushManager{
+  MethodChannel _channel;
+
+  OfflinePushManager(this._channel);
+}
\ No newline at end of file
diff --git a/lib/src/manager/im_signaling_manager.dart b/lib/src/manager/im_signaling_manager.dart
new file mode 100644
index 0000000..adaa4c0
--- /dev/null
+++ b/lib/src/manager/im_signaling_manager.dart
@@ -0,0 +1,7 @@
+import 'package:flutter/services.dart';
+
+class SignalingManager {
+  MethodChannel _channel;
+
+  SignalingManager(this._channel);
+}
diff --git a/lib/src/models/conversation_info.dart b/lib/src/models/conversation_info.dart
new file mode 100644
index 0000000..fe125fa
--- /dev/null
+++ b/lib/src/models/conversation_info.dart
@@ -0,0 +1,77 @@
+import 'dart:convert';
+
+import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
+
+class ConversationInfo {
+  String conversationID;
+  int? conversationType;
+  String? userID;
+  String? groupID;
+  String? showName;
+  String? faceUrl;
+  int? recvMsgOpt;
+  int? unreadCount;
+  Message? latestMsg;
+  int? latestMsgSendTime;
+  String? draftText;
+  int? draftTimestamp;
+  dynamic isPinned;
+
+  ConversationInfo(
+      {required this.conversationID,
+      this.conversationType,
+      this.userID,
+      this.groupID,
+      this.showName,
+      this.faceUrl,
+      this.recvMsgOpt,
+      this.unreadCount,
+      this.latestMsg,
+      this.latestMsgSendTime,
+      this.draftText,
+      this.draftTimestamp,
+      this.isPinned});
+
+  ConversationInfo.fromJson(Map<String, dynamic> json)
+      : conversationID = json['conversationID'] {
+    // conversationID = json['conversationID'];
+    conversationType = json['conversationType'];
+    userID = json['userID'];
+    groupID = json['groupID'];
+    showName = json['showName'];
+    faceUrl = json['faceUrl'];
+    recvMsgOpt = json['recvMsgOpt'];
+    unreadCount = json['unreadCount'];
+    // latestMsg = json['latestMsg'];
+    // if (null != json['latestMsg']) {
+    if (json['latestMsg'] is String) {
+      latestMsg = Message.fromJson(jsonDecode(json['latestMsg']));
+    } else if (json['latestMsg'] is Map) {
+      latestMsg = Message.fromJson(json['latestMsg']);
+    }
+    // }
+
+    latestMsgSendTime = json['latestMsgSendTime'];
+    draftText = json['draftText'];
+    draftTimestamp = json['draftTimestamp'];
+    isPinned = json['isPinned'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['conversationID'] = this.conversationID;
+    data['conversationType'] = this.conversationType;
+    data['userID'] = this.userID;
+    data['groupID'] = this.groupID;
+    data['showName'] = this.showName;
+    data['faceUrl'] = this.faceUrl;
+    data['recvMsgOpt'] = this.recvMsgOpt;
+    data['unreadCount'] = this.unreadCount;
+    data['latestMsg'] = this.latestMsg?.toJson();
+    data['latestMsgSendTime'] = this.latestMsgSendTime;
+    data['draftText'] = this.draftText;
+    data['draftTimestamp'] = this.draftTimestamp;
+    data['isPinned'] = this.isPinned;
+    return data;
+  }
+}
diff --git a/lib/src/models/message.dart b/lib/src/models/message.dart
new file mode 100644
index 0000000..d99fa1c
--- /dev/null
+++ b/lib/src/models/message.dart
@@ -0,0 +1,337 @@
+class Message {
+  String? clientMsgID;
+  String? serverMsgID;
+  int? createTime;
+  int? sendTime;
+  String? sendID;
+  String? recvID;
+  int? msgFrom;
+  int? contentType;
+  int? platformID;
+  List<String>? forceList;
+  String? senderNickName;
+  String? senderFaceUrl;
+  String? groupID;
+  String? content;
+  int? seq;
+  bool? isRead;
+  int? status;
+  String? remark;
+  dynamic ext;
+  int? sessionType;
+  PictureElem? pictureElem;
+  SoundElem? soundElem;
+  VideoElem? videoElem;
+  FileElem? fileElem;
+
+  Message(
+      {this.clientMsgID,
+      this.serverMsgID,
+      this.createTime,
+      this.sendTime,
+      this.sendID,
+      this.recvID,
+      this.msgFrom,
+      this.contentType,
+      this.platformID,
+      this.forceList,
+      this.senderNickName,
+      this.senderFaceUrl,
+      this.groupID,
+      this.content,
+      this.seq,
+      this.isRead,
+      this.status,
+      this.remark,
+      this.ext,
+      this.sessionType,
+      this.pictureElem,
+      this.soundElem,
+      this.videoElem,
+      this.fileElem});
+
+  Message.fromJson(Map<String, dynamic> json)
+  /*  : clientMsgID = json['clientMsgID']*/ {
+    clientMsgID = json['clientMsgID'];
+    serverMsgID = json['serverMsgID'];
+    createTime = json['createTime'];
+    sendTime = json['sendTime'];
+    sendID = json['sendID'];
+    recvID = json['RecvID'];
+    msgFrom = json['msgFrom'];
+    contentType = json['contentType'];
+    platformID = json['platformID'];
+    forceList = json['forceList'];
+    senderNickName = json['senderNickName'];
+    senderFaceUrl = json['senderFaceUrl'];
+    groupID = json['groupID'];
+    content = json['content'];
+    seq = json['seq'];
+    isRead = json['isRead'];
+    status = json['status'];
+    remark = json['remark'];
+    ext = json['ext'];
+    sessionType = json['sessionType'];
+    pictureElem = json['pictureElem'] != null
+        ? new PictureElem.fromJson(json['pictureElem'])
+        : null;
+    soundElem = json['soundElem'] != null
+        ? new SoundElem.fromJson(json['soundElem'])
+        : null;
+    videoElem = json['videoElem'] != null
+        ? new VideoElem.fromJson(json['videoElem'])
+        : null;
+    fileElem = json['fileElem'] != null
+        ? new FileElem.fromJson(json['fileElem'])
+        : null;
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['clientMsgID'] = this.clientMsgID;
+    data['serverMsgID'] = this.serverMsgID;
+    data['createTime'] = this.createTime;
+    data['sendTime'] = this.sendTime;
+    data['sendID'] = this.sendID;
+    data['RecvID'] = this.recvID;
+    data['msgFrom'] = this.msgFrom;
+    data['contentType'] = this.contentType;
+    data['platformID'] = this.platformID;
+    data['forceList'] = this.forceList;
+    data['senderNickName'] = this.senderNickName;
+    data['senderFaceUrl'] = this.senderFaceUrl;
+    data['groupID'] = this.groupID;
+    data['content'] = this.content;
+    data['seq'] = this.seq;
+    data['isRead'] = this.isRead;
+    data['status'] = this.status;
+    data['remark'] = this.remark;
+    data['ext'] = this.ext;
+    data['sessionType'] = this.sessionType;
+    if (this.pictureElem != null) {
+      data['pictureElem'] = this.pictureElem!.toJson();
+    }
+    if (this.soundElem != null) {
+      data['soundElem'] = this.soundElem!.toJson();
+    }
+    if (this.videoElem != null) {
+      data['videoElem'] = this.videoElem!.toJson();
+    }
+    if (this.fileElem != null) {
+      data['fileElem'] = this.fileElem!.toJson();
+    }
+    return data;
+  }
+
+  @override
+  bool operator ==(Object other) {
+    // TODO: implement ==
+    if (other is Message) {
+      return other._id == _id;
+    }
+    return super == other;
+  }
+
+  @override
+  // TODO: implement hashCode
+  int get hashCode => super.hashCode;
+
+  String? get _id =>
+      clientMsgID == null || clientMsgID!.isEmpty ? serverMsgID : clientMsgID;
+}
+
+class PictureElem {
+  String? sourcePath;
+  PictureInfo? sourcePicture;
+  PictureInfo? bigPicture;
+  PictureInfo? snapshotPicture;
+
+  PictureElem(
+      {this.sourcePath,
+      this.sourcePicture,
+      this.bigPicture,
+      this.snapshotPicture});
+
+  PictureElem.fromJson(Map<String, dynamic> json) {
+    sourcePath = json['sourcePath'];
+    sourcePicture = json['sourcePicture'] != null
+        ? new PictureInfo.fromJson(json['sourcePicture'])
+        : null;
+    bigPicture = json['bigPicture'] != null
+        ? new PictureInfo.fromJson(json['bigPicture'])
+        : null;
+    snapshotPicture = json['snapshotPicture'] != null
+        ? new PictureInfo.fromJson(json['snapshotPicture'])
+        : null;
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['sourcePath'] = this.sourcePath;
+    if (this.sourcePicture != null) {
+      data['sourcePicture'] = this.sourcePicture?.toJson();
+    }
+    if (this.bigPicture != null) {
+      data['bigPicture'] = this.bigPicture?.toJson();
+    }
+    if (this.snapshotPicture != null) {
+      data['snapshotPicture'] = this.snapshotPicture?.toJson();
+    }
+    return data;
+  }
+}
+
+class PictureInfo {
+  String? uuID;
+  String? type;
+  int? size;
+  int? width;
+  int? height;
+  String? url;
+
+  PictureInfo(
+      {this.uuID, this.type, this.size, this.width, this.height, this.url});
+
+  PictureInfo.fromJson(Map<String, dynamic> json) {
+    uuID = json['uuID'];
+    type = json['type'];
+    size = json['size'];
+    width = json['width'];
+    height = json['height'];
+    url = json['url'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['uuID'] = this.uuID;
+    data['type'] = this.type;
+    data['size'] = this.size;
+    data['width'] = this.width;
+    data['height'] = this.height;
+    data['url'] = this.url;
+    return data;
+  }
+}
+
+class SoundElem {
+  String? uuID;
+  String? soundPath;
+  String? sourceUrl;
+  int? dataSize;
+  int? duration;
+
+  SoundElem(
+      {this.uuID,
+      this.soundPath,
+      this.sourceUrl,
+      this.dataSize,
+      this.duration});
+
+  SoundElem.fromJson(Map<String, dynamic> json) {
+    uuID = json['uuID'];
+    soundPath = json['soundPath'];
+    sourceUrl = json['sourceUrl'];
+    dataSize = json['dataSize'];
+    duration = json['duration'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['uuID'] = this.uuID;
+    data['soundPath'] = this.soundPath;
+    data['sourceUrl'] = this.sourceUrl;
+    data['dataSize'] = this.dataSize;
+    data['duration'] = this.duration;
+    return data;
+  }
+}
+
+class VideoElem {
+  String? videoPath;
+  String? videoUUID;
+  String? videoUrl;
+  String? videoType;
+  int? videoSize;
+  int? duration;
+  String? snapshotPath;
+  String? snapshotUUID;
+  int? snapshotSize;
+  String? snapshotUrl;
+  int? snapshotWidth;
+  int? snapshotHeight;
+
+  VideoElem(
+      {this.videoPath,
+      this.videoUUID,
+      this.videoUrl,
+      this.videoType,
+      this.videoSize,
+      this.duration,
+      this.snapshotPath,
+      this.snapshotUUID,
+      this.snapshotSize,
+      this.snapshotUrl,
+      this.snapshotWidth,
+      this.snapshotHeight});
+
+  VideoElem.fromJson(Map<String, dynamic> json) {
+    videoPath = json['videoPath'];
+    videoUUID = json['videoUUID'];
+    videoUrl = json['videoUrl'];
+    videoType = json['videoType'];
+    videoSize = json['videoSize'];
+    duration = json['duration'];
+    snapshotPath = json['snapshotPath'];
+    snapshotUUID = json['snapshotUUID'];
+    snapshotSize = json['snapshotSize'];
+    snapshotUrl = json['snapshotUrl'];
+    snapshotWidth = json['snapshotWidth'];
+    snapshotHeight = json['snapshotHeight'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['videoPath'] = this.videoPath;
+    data['videoUUID'] = this.videoUUID;
+    data['videoUrl'] = this.videoUrl;
+    data['videoType'] = this.videoType;
+    data['videoSize'] = this.videoSize;
+    data['duration'] = this.duration;
+    data['snapshotPath'] = this.snapshotPath;
+    data['snapshotUUID'] = this.snapshotUUID;
+    data['snapshotSize'] = this.snapshotSize;
+    data['snapshotUrl'] = this.snapshotUrl;
+    data['snapshotWidth'] = this.snapshotWidth;
+    data['snapshotHeight'] = this.snapshotHeight;
+    return data;
+  }
+}
+
+class FileElem {
+  String? filePath;
+  String? uuID;
+  String? sourceUrl;
+  String? fileName;
+  int? fileSize;
+
+  FileElem(
+      {this.filePath, this.uuID, this.sourceUrl, this.fileName, this.fileSize});
+
+  FileElem.fromJson(Map<String, dynamic> json) {
+    filePath = json['filePath'];
+    uuID = json['uuID'];
+    sourceUrl = json['sourceUrl'];
+    fileName = json['fileName'];
+    fileSize = json['fileSize'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['filePath'] = this.filePath;
+    data['uuID'] = this.uuID;
+    data['sourceUrl'] = this.sourceUrl;
+    data['fileName'] = this.fileName;
+    data['fileSize'] = this.fileSize;
+    return data;
+  }
+}
diff --git a/lib/src/models/user_info.dart b/lib/src/models/user_info.dart
new file mode 100644
index 0000000..f87b953
--- /dev/null
+++ b/lib/src/models/user_info.dart
@@ -0,0 +1,65 @@
+class UserInfo {
+  String uid;
+  String? name;
+  String? icon;
+  int? gender; // 0 未知,1 男,2 女
+  String? mobile;
+  String? birth;
+  String? email;
+  String? ex;
+  String? comment;
+  int? isInBlackList; // 0 不在黑名单,1 在黑名单
+  String? reqMessage;
+  String? applyTime;
+  int? flag; // //0请求添加好友,1同意添加好友,-1拒绝添加好友
+
+  UserInfo(
+      {required this.uid,
+      this.name,
+      this.icon,
+      this.gender,
+      this.mobile,
+      this.birth,
+      this.email,
+      this.ex,
+      this.comment,
+      this.isInBlackList,
+      this.reqMessage,
+      this.applyTime,
+      this.flag});
+
+  UserInfo.fromJson(Map<String, dynamic> json) : uid = json['uid'] {
+    name = json['name'];
+    icon = json['icon'];
+    gender = json['gender'];
+    mobile = json['mobile'];
+    birth = json['birth'];
+    email = json['email'];
+    ex = json['ex'];
+    comment = json['comment'];
+    isInBlackList = json['isInBlackList'];
+    reqMessage = json['reqMessage'];
+    applyTime = json['applyTime'];
+    flag = json['flag'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['uid'] = this.uid;
+    data['name'] = this.name;
+    data['icon'] = this.icon;
+    data['gender'] = this.gender;
+    data['mobile'] = this.mobile;
+    data['birth'] = this.birth;
+    data['email'] = this.email;
+    data['ex'] = this.ex;
+    data['comment'] = this.comment;
+    data['isInBlackList'] = this.isInBlackList;
+    data['reqMessage'] = this.reqMessage;
+    data['applyTime'] = this.applyTime;
+    data['flag'] = this.flag;
+    return data;
+  }
+
+  String get nickname => comment ?? name ?? uid;
+}