This project is the EaseMob IM Flutter SDK, adopting a Federated Plugin architecture and including multiple sub-packages. The following are the conventions and specifications that AI Agents must follow when working on this project.
im_flutter_sdk/ → Main SDK package (public APIs, models, managers)
im_flutter_sdk_interface/ → Platform interface layer (MethodChannel abstraction)
im_flutter_sdk_android/ → Android platform implementation
im_flutter_sdk_ios/ → iOS platform implementation
Call chain: Dart API → MethodChannel (interface) → Native Wrapper → HyphenateChat SDK
- All Dart files use snake_case:
chat_manager.dart,em_message.dart - Model files uniformly use the
em_prefix:em_error.dart,em_group.dart,em_options.dart - Manager files use business name +
_managersuffix:chat_manager.dart,group_manager.dart - Android native classes use the
*Wrappersuffix:ClientWrapper.java,ChatManagerWrapper.java - iOS native classes use the
*Wrappersuffix (.m/.h):ClientWrapper.m,ChatManagerWrapper.m - iOS Helper classes use the
*Helpersuffix:MessageHelper.m,OptionsHelper.h
- All public Dart classes use the EM prefix:
EMClient,EMMessage,EMError,EMOptions - Manager classes:
EM+ business name +Manager, e.g.,EMChatManager,EMGroupManager - Event handlers:
EM+ business name +EventHandler, e.g.,EMConnectionEventHandler,EMChatEventHandler - Platform implementation classes use platform name as suffix:
ClientIOS,ClientAndroid,ChatManagerIOS
- Unified prefix
com.chat.im - Format:
com.chat.im/{manager_name}, e.g.,com.chat.im/chat_manager,com.chat.im/chat_client
import 'dart:xxx'; // 1. Dart standard library
import 'package:flutter/xxx'; // 2. Flutter framework
import 'package:im_flutter_sdk/xxx'; // 3. This SDK package
import 'package:im_flutter_sdk_interface/xxx'; // 4. Interface packageManager classes are obtained via EMClient.getInstance, not instantiated directly:
EMClient.getInstance.chatManager
EMClient.getInstance.groupManager- Deserialization uses factory constructor:
EMMessage.fromJson(Map map) - Serialization uses instance method:
toJson() - Data format is JSON Map for MethodChannel transmission
- Event handlers are stored in
Map<String, Handler>with unique ID as key - Registration:
addEventHandler(String id, Handler handler) - Unregistration:
removeEventHandler(String id) - Native events are distributed via
updateNativeHandler((MethodCall call) => ...)
- All method names for MethodChannel calls are defined in
ChatMethodKeys - All native callback event names are defined in
em_event_keys.dart - Hardcoding method name strings in code is prohibited
All public APIs must use bilingual comment format (English + Chinese):
/// ~english
/// The message class.
///
/// For example:
/// ```dart
/// EMMessage msg = EMMessage.createTxtSendMessage(
/// targetId: 'targetId',
/// content: 'content',
/// );
/// ```
/// ~end
///
/// ~chinese
/// 消息对象类。
///
/// 示例:
/// ```dart
/// EMMessage msg = EMMessage.createTxtSendMessage(
/// targetId: 'targetId',
/// content: 'content',
/// );
/// ```
/// ~end~englishand~endmark the English documentation block~chineseand~endmark the Chinese documentation block- Separate the two blocks with a blank line
- Both languages must be maintained when adding or modifying public APIs
- Create
em_xxx.dartfile underim_flutter_sdk/lib/src/models/ - Class name uses
EMprefix - Implement
fromJson()factory constructor andtoJson()method - Export in
im_flutter_sdk.dartbarrel file - Write bilingual documentation comments
- Add method in the corresponding Manager class
- Add method name to
ChatMethodKeys - Define platform interface in
im_flutter_sdk_interface - Implement native bridging in
im_flutter_sdk_androidandim_flutter_sdk_ios - Android: Handle in the corresponding
*Wrapper.java - iOS: Handle in the corresponding
*Wrapper.m
When adding a new API, implement it step by step according to the following "Dart to cross-platform native" chain, no skipping steps:
-
Dart Manager Implementation (Entry)
- File:
im_flutter_sdk/lib/src/managers/chat_manager.dart(or corresponding business manager) - Add public method, clarify parameter default values, nullable parameters and return types
- Add corresponding API documentation comments according to the new method name, parameters and return values
- Assemble request
Map req, useputIfNotNullfor nullable parameters - Call
Client.instance.xxxManager.callNativeMethod(methodKey, req) - Uniformly call
EMError.hasErrorFromResult(result)to handle errors - Convert returned
Map/Listto strongly typed objects and return
- File:
-
Dart Method Name Constants
- File:
im_flutter_sdk/lib/src/internal/chat_method_keys.dart - Add
static const Stringmethod name constant with exactly the same value as native - Hardcoding strings in manager methods is prohibited
- File:
-
Android Method Name Constants
- File:
im_flutter_sdk_android/android/src/main/java/com/easemob/im_flutter_sdk/MethodKey.java - Add corresponding
static final Stringconstant with the same name and value as Dart/iOS
- File:
-
Android Routing Distribution + Specific Implementation
- File:
im_flutter_sdk_android/android/src/main/java/com/easemob/im_flutter_sdk/ChatManagerWrapper.java(or corresponding business ManagerWrapper) - Register new branch in
onMethodCall'selse ifchain - Add private processing method (e.g.,
private void xxx(JSONObject params, String channelName, Result result)) - Parse parameters (null check/type conversion/enum conversion)
- Call corresponding asynchronous API of Hyphenate Android SDK
- Convert results to serializable structures (
Map/List/basic types) in callback and return viaupdateObject
- File:
-
iOS Method Name Constants
- File:
im_flutter_sdk_ios/ios/Classes/MethodKeys.h - Add
static NSString *constconstant with exactly the same string value as Dart/Android
- File:
-
iOS Routing Distribution + Specific Implementation
- File:
im_flutter_sdk_ios/ios/Classes/ChatManagerWrapper.m(or corresponding business ManagerWrapper) - Register new API in
handleMethodCallbranch - Add instance method
- (void)xxx:(NSDictionary *)param channelName:(NSString *)aChannelName result:(FlutterResult)result - Complete parameter null check, type and enum conversion
- Call corresponding API of Hyphenate iOS SDK
- Return result object via
wrapperCallBackin completion
- File:
-
Version Comments and Change Records
- Add version comments near the new code following existing style (e.g.,
// 4.15.2,#pragma mark 4.15.2) - Update
CHANGELOG.mdof the following packages to add "Added xxx API" entry:im_flutter_sdk/CHANGELOG.mdim_flutter_sdk_android/CHANGELOG.mdim_flutter_sdk_ios/CHANGELOG.md
- Add version comments near the new code following existing style (e.g.,
-
Joint Debugging Self-Checklist (Before Submission)
- Method names are consistent in 4 constant files: Dart/Android/iOS (including calling side)
- Dart request parameter keys are exactly the same as cross-platform native reading keys
- Enum indexes are consistent with cross-platform enum mappings
- Return structure can be correctly deserialized by Dart side (especially generics like
Map<String, List<String>>) - Routing distribution branches are added for both Android and iOS
- CHANGELOG of three sub-packages are updated synchronously (
im_flutter_sdk_ios/CHANGELOG.mddoes not need to be updated)
- Define new EventHandler class in
manager_event_handler.dart - Class name format:
EM{Business}EventHandler - Implement
addEventHandler/removeEventHandlerin the corresponding Manager - Add native event key to
em_event_keys.dart
- Version numbers of each sub-package are kept in sync
- CHANGELOG.md is written in Chinese
- Format:
## Version Numbertitle +- Fixed.../- Added.../- Optimized...entries
| Platform | Minimum Version |
|---|---|
| Android | minSdk 21 |
| iOS | 12.0+ |
| Dart | >=3.3.0 <4.0.0 |
| Flutter | >=3.3.0 |
- Prohibited to hardcode MethodChannel method names in Dart code; must use
ChatMethodKeysconstants - Prohibited to directly instantiate Manager classes; must obtain via
EMClient.getInstance - Prohibited to omit documentation comments in public APIs
- Prohibited to modify the version number of a single sub-package without synchronizing other sub-packages
- Prohibited to omit
fromJson/toJsonserialization methods in model classes
- Create a new text file (e.g.,
AGENTS_EN.md) - Copy all the above content into the file
- Save the file (ensure the encoding is UTF-8 to avoid garbled characters)