zh_native_channel
zh_native_channel 是一个面向 Flutter 的跨端 MethodChannel 消息框架。它把一次平台调用抽象成“消息对象 + 处理器”,让 Dart、iOS、Android、Web 之间用同一套 channel name、序列化规则和注册入口通信。
配套的 zh_native_channel_generator 负责扫描 Dart 消息定义和平台 handler 标记,生成 Dart 注册代码、Swift/Kotlin/TypeScript 消息模型和平台注册代码。运行时能力由本库提供,代码生成能力由 generator 提供。
这个库能做什么
- 在 Dart 侧通过
ZHNativeChannel.instance.invoke(msg)发送业务消息到平台侧。 - 在平台侧通过
MethodChannelMsgManager接收 MethodChannel 调用、解析消息、查找 handler,并返回消息对象。 - 支持平台侧主动调用 Dart,并把返回值解析为对应的
ChannelBaseMsg。 - 通过
@ChannelMsg标记 Dart 消息类型,通过@ChannelHandlerFor标记 Dart handler。 - 通过原生注释
// PlatformChannelHandler("MessageName")标记 Swift/Kotlin/Web handler。 - 通过配置文件生成 Dart/iOS/Android/Web 的注册代码和平台消息模型。
当前生成器支持的字段类型包括 String、int、double、num、bool、Map<String, dynamic>、List<...>。复杂自定义 model 的递归嵌套生成还不是当前版本的完整能力。
使用它的好处
直接写 MethodChannel 时,Flutter 和原生两边通常要重复维护 method name、Map 字段、注册表和类型转换。zh_native_channel 把这些约定集中到消息类和 handler 上,再由生成器产出重复代码,带来的好处是:
- 降低手写 MethodChannel 字符串和 Map 字段不一致的风险。
- 新增一个业务通道时,只需要新增消息类和对应 handler。
- Dart、Swift、Kotlin、Web 使用同一套消息命名和注册入口。
- 生成文件集中管理,业务代码更聚焦在 handler 逻辑。
快速上手
在 Flutter 项目中添加运行时库和生成器:
dependencies:
zh_native_channel:
path: ../
dev_dependencies:
build_runner: ^2.10.4
zh_native_channel_generator: ^0.0.1
创建消息类:
import 'package:zh_native_channel/zh_native_channel.dart';
@ChannelMsg()
class PingMsg extends ChannelBaseMsg {
final String text;
PingMsg({required this.text});
static PingMsg fromMap(Map<String, dynamic> map) {
return PingMsg(text: map['text'] as String? ?? '');
}
@override
Map<String, dynamic> toMap() {
return {'text': text};
}
}
创建 Dart handler。如果当前消息由 Dart 处理,可以使用 @ChannelHandlerFor 注册:
@ChannelHandlerFor('PingMsg')
class PingHandler extends ChannelBaseHandler {
@override
Future<ChannelBaseMsg> handle(ChannelBaseMsg msg) async {
final ping = msg as PingMsg;
return PingMsg(text: 'dart:${ping.text}');
}
}
创建原生 handler。iOS 示例:
import zh_native_channel
// PlatformChannelHandler("PingMsg")
final class PingMsgHandler: ChannelBaseHandler {
func handle(
_ message: ChannelBaseMsg,
completion: @escaping (Result<ChannelBaseMsg, Error>) -> Void
) {
guard let ping = message as? PingMsg else {
completion(.failure(ChannelMsgError.typeMismatch(expected: "PingMsg")))
return
}
completion(.success(PingMsg(text: "ios:\(ping.text)")))
}
}
Android 示例:
import com.example.zh_native_channel.ChannelBaseHandler
import com.example.zh_native_channel.ChannelBaseMsg
// PlatformChannelHandler("PingMsg")
class PingMsgHandler : ChannelBaseHandler {
override fun handle(message: ChannelBaseMsg): ChannelBaseMsg {
val ping = message as PingMsg
return PingMsg(text = "android:${ping.text}")
}
}
生成代码后,在 Dart 侧使用生成入口:
initializeGeneratedChannels();
final channel = ZHNativeChannel.instance;
final response = await channel.invoke(PingMsg(text: 'hello'));
iOS/Android 启动阶段需要调用生成的平台注册入口,把消息和 handler 注册进原生 manager:
GeneratedChannelRegistrations.registerAll()
GeneratedChannelRegistrations.registerAll()
完整示例见 example/README.md。
脚本命令
生成器会在项目 Makefile 中维护一段命令块。默认入口是:
ZH_NATIVE_CHANNEL_GENERATOR ?= dart run zh_native_channel_generator:generate_native_channel
ZH_NATIVE_CHANNEL_CONFIG ?= zh_native_channel_config.json
常用命令:
make gen
完整生成流程。它会依次执行 clean-generated、build-runner-build、create-platformcode-all,适合新增或修改消息后重新生成所有产物。
make clean-generated
按配置删除生成产物,不删除手写 handler。底层执行 --clean-generated-only。
make build-runner-sync-config
只根据 zh_native_channel_config.json 同步 build.yaml,不执行 build_runner。底层执行 --sync-build-config-only。
make build-runner-build
先同步 build.yaml,再执行 dart run build_runner build,生成 Dart 侧注册文件,例如 ChannelGeneratedRegister.g.dart。
make create-platformcode-all
根据配置文件中声明的平台生成平台代码。配置里有 iOS 和 Android,就生成 Swift 和 Kotlin;如果只配置某个平台,就只生成那个平台。
make create-platformcode-ios
make create-platformcode-android
make create-platformcode-web
只生成指定平台。执行单个平台命令时,对应的 platforms.<platform> 配置必须存在。
也可以直接调用生成器:
dart run zh_native_channel_generator:generate_native_channel zh_native_channel_config.json --platform all
仓库 example 里还有一个测试脚本:
./tool/run_generation_tests.sh
它会清理示例生成产物、执行 flutter pub get、同步 build 配置、运行 build_runner、重新生成 iOS/Android 平台代码,并执行 flutter analyze 和 flutter test。
zh_native_channel_config.json
配置文件描述“扫描哪里”和“生成到哪里”。默认文件名是 zh_native_channel_config.json,也可以在命令里传入其他 JSON 文件路径。
example 当前配置如下:
{
"dart": {
"defaultOutputDirectory": "lib/base/zHNativeChannel",
"messageScanPath": [
"lib/base/zHNativeChannel/msgs"
],
"handlerScanPath": [
"lib/base/zHNativeChannel/handlers"
],
"generatedChannelRegisterOutputPath": "lib/base/zHNativeChannel/ChannelGeneratedRegister.g.dart"
},
"platforms": {
"ios": {
"defaultOutputDirectory": "ios/Runner/zHNativeChannel",
"scanHandlerPath": [
"ios/Runner/zHNativeChannel/handler_ios"
],
"msgsOutputPath": "ios/Runner/zHNativeChannel/msgs",
"generatedChannelRegistrationsOutputPath": "ios/Runner/zHNativeChannel",
"xcodeProjectPath": "ios/Runner.xcodeproj/project.pbxproj"
},
"android": {
"defaultOutputDirectory": "android/app/src/main/kotlin/com/example/zh_native_channel_example/zHNativeChannel",
"scanHandlerPath": [
"android/app/src/main/kotlin/com/example/zh_native_channel_example/zHNativeChannel/handlers"
],
"msgsOutputPath": "android/app/src/main/kotlin/com/example/zh_native_channel_example/zHNativeChannel/msgs",
"generatedChannelRegistrationsOutputPath": "android/app/src/main/kotlin/com/example/zh_native_channel_example/zHNativeChannel",
"packageName": "com.example.zh_native_channel_example.zHNativeChannel"
}
}
}
字段说明:
dart.defaultOutputDirectory:Dart 生成代码默认目录,默认是lib/base/zHNativeChannel。dart.messageScanPath:扫描 Dart@ChannelMsg消息类的位置。原生生成脚本用它生成 Swift/Kotlin/TypeScript 的 msg 类型,同步build.yaml时也会加入 build_runner 扫描范围。dart.handlerScanPath:扫描 Dart@ChannelHandlerForhandler 的位置,用于生成 Dart 侧 handler 注册代码。dart.generatedChannelRegisterOutputPath:Dart 侧注册文件输出路径,例如ChannelGeneratedRegister.g.dart。platforms.<platform>.defaultOutputDirectory:某个平台生成代码的默认根目录。platforms.<platform>.scanHandlerPath:扫描原生 handler 的目录。没有配置时会扫描配置文件所在项目,项目较大时建议显式配置。platforms.<platform>.msgsOutputPath:平台 msg 文件输出目录,例如 iOS 的PingMsg.g.swift、Android 的PingMsg.g.kt。platforms.<platform>.generatedChannelRegistrationsOutputPath:平台总注册文件输出目录,例如GeneratedChannelRegistrations.g.swift或GeneratedChannelRegistrations.g.kt。platforms.android.packageName:Android 生成 Kotlin 文件使用的 package,真实业务工程建议显式配置。platforms.ios.xcodeProjectPath:iOS Xcode 工程文件路径,用于把生成的 Swift 文件加入 Runner target;不配置时会尝试从输出目录向上查找。platforms.web.globalName:Web 端挂到globalThis上的全局对象名,默认是ZHNativeChannel。
所有字段都可以使用默认值,但业务项目建议至少明确配置扫描目录、平台输出目录和 Android packageName。