鸿蒙多种能力并存时,目录、命名和通道协议该怎么统一

适合谁看
-
项目里已经接了多个鸿蒙能力的人
-
想给团队补统一约定的人
-
不想让平台层越来越乱的人
问题背景
多能力项目最容易出现的混乱:
|
混乱 |
示例 |
后果 |
|---|---|---|
|
文件命名风格不一致 |
有的叫 |
找文件困难 |
|
通道名没有统一前缀 |
|
调试混乱 |
|
参数有的传 Map,有的传字符串 |
不同能力参数格式不同 |
维护困难 |
|
页面层直接和原生细节纠缠 |
页面知道原生 API 细节 |
耦合度高 |
项目中的真实场景
食界探味当前的 4 个能力已经形成了一套模式:
|
能力 |
Flutter 文件 |
ArkTS 文件 |
channel 名 |
|---|---|---|---|
|
语音识别 |
|
|
|
|
TTS |
|
|
|
|
Intent 导航 |
|
|
|
|
防窥保护 |
|
|
|
核心实现
一、目录先按"平台边界层"集中
Flutter 侧:
app/lib/core/platform/
├── speech_recognition_channel.dart
├── text_to_speech_channel.dart
├── intent_navigation_channel.dart
└── anti_peep_protection_channel.dart
鸿蒙侧:
app/ohos/entry/src/main/ets/plugins/
├── SpeechRecognitionPlugin.ets
├── TextToSpeechPlugin.ets
├── IntentNavigationPlugin.ets
└── AntiPeepProtectionPlugin.ets
为什么这样组织:
|
好处 |
说明 |
|---|---|
|
新同事一眼知道去哪找 |
平台能力都在 |
|
排错时快速缩小范围 |
先看目录就知道涉及哪些能力 |
|
新增能力不用重新发明规则 |
照着现有文件加一个就行 |
|
Flutter 和鸿蒙两边对应关系清楚 |
文件名一一对应 |
不要这样做:
❌ 把能力分散到各个页面目录
features/search/speech_service.dart
features/ai_assistant/tts_bridge.dart
features/dish_detail/navigation_helper.dart
✅ 统一收在平台边界层
core/platform/speech_recognition_channel.dart
core/platform/text_to_speech_channel.dart
二、命名先按"能力本身"统一
当前项目已经形成了很稳的命名模式:
|
层 |
命名模式 |
示例 |
|---|---|---|
|
Flutter 侧 |
|
|
|
ArkTS 侧 |
|
|
|
channel 名 |
|
|
|
方法名 |
动词 + 名词 |
|
命名规范表格:
|
规范 |
说明 |
示例 |
|---|---|---|
|
Flutter 文件 |
|
|
|
ArkTS 文件 |
|
|
|
channel 名 |
|
|
|
类名 |
|
|
|
方法名 |
|
|
如果命名不统一,会怎样:
❌ 命名混乱:
speech_service.dart / TtsBridge.ets / com.xxx.tts
→ 找文件困难,channel 名对不上
✅ 命名统一:
text_to_speech_channel.dart / TextToSpeechPlugin.ets / com.foodvoyage.text_to_speech
→ 一看就知道对应关系
三、通道协议要先统一"什么是命令,什么是事件"
当前项目的 4 个能力分属 3 种通道模型:
|
通道模型 |
特点 |
示例 |
|---|---|---|
|
命令型 |
发起一次命令,等待一次结果 |
语音识别、TTS |
|
事件型 |
开启后持续接收状态事件 |
防窥保护 |
|
混合型 |
原生主动推送 + Flutter 主动消费 |
Intent 导航 |
命令型通道模式:
// Flutter 侧
static Future<String> startListening() async {
return await _channel.invokeMethod<String>('startListening');
}
static Future<void> stop() async {
await _channel.invokeMethod<void>('stop');
}
// ArkTS 侧
onMethodCall(call: MethodCall, result: MethodResult): void {
switch (call.method) {
case 'startListening': this.handleStart(result); break;
case 'stopListening': this.handleStop(result); break;
}
}
事件型通道模式:
// Flutter 侧
static void initialize() {
_channel.setMethodCallHandler((call) async {
if (call.method == 'onEvent') {
final event = call.arguments['event'] as String?;
state.value = event == 'ACTIVE' ? EventState.active : EventState.idle;
}
});
}
static Future<void> activate() async {
await _channel.invokeMethod<void>('activate');
}
// ArkTS 侧
private onStatusChange(status: string): void {
this.channel?.invokeMethod('onEvent', { event: status });
}
混合型通道模式:
// Flutter 侧
static void init(GoRouter router) {
_channel.setMethodCallHandler((call) async {
if (call.method == 'onIntentNavigation') {
// 实时推送
}
});
_consumePending(); // 主动消费 pending
}
统一协议不是要求所有能力都只剩一个 invokeMethod,而是要求:
-
同类能力用相近语义
-
不同类能力的差异是有意识的
四、参数风格也应该尽量统一
命令型参数:结构化 Map
// 语音识别
await _channel.invokeMethod('startListening', {'language': 'zh-CN'});
// TTS
await _channel.invokeMethod('speak', {'text': '你好'});
// Intent 导航
await _channel.invokeMethod('navigateToPage', {'pageId': 'search', 'dishId': 'xxx'});
事件型参数:固定字段
// 防窥事件
{
'event': 'HIDE', // 事件名
'detail': 'anti-peek' // 事件详情
}
错误码:统一格式
// 成功
result.success(null);
// 参数错误
result.error('INVALID_ARGUMENT', '参数为空', null);
// 业务错误
result.error('TTS_ERROR', '播报失败', null);
// 权限错误
result.error('PERMISSION_DENIED', '权限被拒绝', null);
参数风格统一的好处:
|
好处 |
说明 |
|---|---|
|
页面层消费方式一致 |
不需要为每个能力写不同的解析逻辑 |
|
调试时日志格式一致 |
更容易定位问题 |
|
新增能力时有模板 |
照着现有模式写就行 |
|
错误处理可以复用 |
统一的错误码可以统一处理 |
关键代码位置
|
文件 |
作用 |
|---|---|
|
|
Flutter 通道层(统一目录) |
|
|
鸿蒙插件层(统一目录) |
|
|
插件注册(统一入口) |
统一规则总结
目录统一
├─ Flutter:app/lib/core/platform/
└─ 鸿蒙:app/ohos/entry/src/main/ets/plugins/
命名统一
├─ Flutter 文件:xxx_channel.dart
├─ ArkTS 文件:XxxPlugin.ets
└─ channel 名:com.foodvoyage.xxx
通道模型统一
├─ 命令型:invokeMethod → 等待返回
├─ 事件型:invokeMethod 启动 + onEvent 回推
└─ 混合型:invokeMethod + pending 消费
参数风格统一
├─ 命令型:结构化 Map
├─ 事件型:{ event, detail }
└─ 错误:{ code, message }
常见坑
-
每加一种能力就重新发明一套命名 — 应该照着现有模式
-
文件既有
service、又有bridge、又有channel— 统一用channel -
通道协议没有统一事件和错误字段 — 事件用
{ event, detail },错误用{ code, message } -
参数风格完全靠临时习惯决定 — 应该有统一规范
-
Flutter 和 ArkTS 两边各自命名一套 — 文件名应该一一对应
-
新能力一来就复制旧代码,但没有同步复制命名和字段规范 — 复制时也要复制规范
可复用模板
新增能力命名模板
新增能力:[能力名]
Flutter 文件:app/lib/core/platform/[能力名]_channel.dart
ArkTS 文件:app/ohos/entry/src/main/ets/plugins/[能力名]Plugin.ets
channel 名:com.foodvoyage.[能力名]
类名:
Flutter:[能力名]Channel
ArkTS:[能力名]Plugin
通道协议模板
命令型:
Flutter: static Future<T> method(Map<String, dynamic> args)
ArkTS: onMethodCall → result.success(result)
事件型:
Flutter: initialize() + setMethodCallHandler
ArkTS: systemApi.on → channel.invokeMethod('onEvent', { event, detail })
混合型:
Flutter: init() + consumePending
ArkTS: navigateToPage() + setPendingNavigation()
参数风格模板
命令型参数:{ 'key': 'value' }
事件型参数:{ 'event': 'EVENT_NAME', 'detail': 'optional detail' }
错误格式:result.error('ERROR_CODE', '错误描述', null)
新增能力检查清单
目录:
□ Flutter 文件在 core/platform/ 下?
□ ArkTS 文件在 plugins/ 下?
命名:
□ Flutter 文件名是 xxx_channel.dart?
□ ArkTS 文件名是 XxxPlugin.ets?
□ channel 名是 com.foodvoyage.xxx?
□ 类名和文件名对应?
通道模型:
□ 是命令型、事件型还是混合型?
□ 同类能力用相近语义?
参数风格:
□ 命令型传结构化 Map?
□ 事件型用 { event, detail }?
□ 错误用 { code, message }?
本篇总结
多能力并存之后,工程约定本身就会变成开发效率问题。目录、命名和协议越早统一,后面继续扩展越不容易乱:
-
目录统一 — Flutter 在
core/platform/,鸿蒙在plugins/ -
命名统一 —
xxx_channel.dart/XxxPlugin.ets/com.foodvoyage.xxx -
通道模型统一 — 命令型 / 事件型 / 混合型,同类能力用相近语义
-
参数风格统一 — 结构化 Map、固定事件字段、统一错误格式
当前项目已经有一套不错的雏形,后面最重要的是继续保持一致。
更多推荐

所有评论(0)