随着鸿蒙生态的逐步发展和完善,越来越多的 Flutter 开发者开始将自己的应用移植到鸿蒙平台。然而,Flutter 生态中的大量第三方插件并不原生支持鸿蒙。在实际开发中,我们需要对这些插件进行鸿蒙化适配。
本文将系统性地总结 Flutter 三方插件鸿蒙化的四种适配思路,并针对每种思路给出真实案例加以说明,重点阐述每种思路的架构思想和决策逻辑。
前置知识:Flutter 插件的消息路由机制
在讨论适配之前,先理解一个核心机制。
一个 Flutter 插件的本质是 Dart 层与原生层的通信通道,这套通信通过 MethodChannel 来实现。Dart 端通过一个字符串名称(channel name)发起调用,引擎将其路由到当前平台注册的处理器:
Flutter App (Dart)
│
└─ MethodChannel('channel_name')
│
▼
原生平台层 ─┬─ Android (Java/Kotlin)
├─ iOS (Objective-C/Swift)
└─ OHOS (HarmonyOS 还需要实现)
Channel name 是路由的唯一凭据。无论使用哪个平台,只要 channel name 一致,Dart 端发起的调用就能到达正确的原生处理器。HarmonyOS 的 Flutter SDK(flutter_ohos)完全兼容这套机制,只是原生层使用 ArkTS 语言。
四种适配思路概览
| 适配思路 |
本质策略 |
维护成本 |
典型案例 |
| 思路一:独立仓库 |
完全重写,与原插件无关系或没有原插件 |
高 |
holding |
| 思路二:Fork 修改 |
在原仓库中新增 ohos 目录 |
中 |
flutter_packages |
| 思路三:联合插件 |
原已是联合架构,新增平台实现包 |
低 |
已整合:screen_brightness_ohos 未整合:wakelock_plus_ohos |
| 思路四:联合插件理念 |
普通插件按联合思路拆出 ohos 包 |
低 |
app_set_id_ohos |
思路一:独立仓库
架构思想
完全脱离原插件,创建一个全新 Flutter 插件工程。Dart API 由自己定义,MethodChannel 由自己创建,ArkTS 原生代码自己实现,与原插件没有任何依赖关系。
典型案例:holding
holding 是一个 Flutter 握持手感知插件,支持 HarmonyOS/OpenHarmony,用于订阅握持手状态变化(未握持 / 左手 / 右手 / 双手 / 未识别)。
该插件为鸿蒙场景从零构建,没有参考或依赖任何现有的 Flutter 社区插件。其 pubspec.yaml 中只声明了 ohos 平台:
flutter:
plugin:
platforms:
ohos:
pluginClass: HoldingPlugin
这意味着它没有任何 Android、iOS、Web 等平台的实现 —— 这是一个只服务于鸿蒙设备的专有插件。
适用场景
- 原插件已废弃或不存在(鸿蒙独有功能,社区没有对应的 Flutter 插件)
- 插件功能是鸿蒙/OpenHarmony 特有的(如握持手感知、分布式能力等)
决策逻辑
业务功能在 Flutter 社区是否有对应插件?
├─ 否(鸿蒙独有功能)→ 思路一
└─ 是 → 继续看其他思路
开发者视角
现有项目(Android+iOS)要加鸿蒙支持,这个方案意味着什么?
代码侵入度:高 🔴
// 必须在业务代码中加入平台判断
if (Platform.isAndroid) {
final result = await OldPlugin.doSomething();
} else if (Platform.isOHOS) {
final result = await NewPlugin.doSomething();
}
新插件的 Dart API 与原插件不同。项目中每一个调用原插件的地方都要修改 import 和调用方式,插件越多,改造量越大。
跨平台兼容性:低 🔴
Android/iOS 依赖原插件(pub.dev 标准依赖),HarmonyOS 依赖新插件。同一份代码无法一套 API 跑三端,需要条件编译或运行时判断。
开发者友好度:极低 🔴
每个开发者需同时了解两套 API,条件分支越多代码可读性越差。新功能需要改两套调用,新成员入职成本高。
结论: 不推荐用于已有应用的鸿蒙适配。此方案仅适合鸿蒙独有的新功能(如握持手感知),不需要考虑三端统一。
思路二:Fork 原仓库,添加 ohos 目录
架构思想
Fork 原插件的仓库,在仓库中新增 ohos/ 目录并编写 ArkTS 代码,同时在 pubspec.yaml 中添加 ohos 平台声明。Dart 层代码不修改。
原仓库 (Fork)
├─ lib/ ← 不动,完全保留原插件的 Dart API
├─ android/ ← 不动
├─ ios/ ← 不动
└─ ohos/ ← 新增,写 ArkTS 原生代码
关键在于 Dart 层中原有的 MethodChannel 名称保持不变。引擎在 ohos 平台运行时会自动路由到新增的 ArkTS 处理器,用户代码零修改。
典型案例:OpenHarmony-tpc/flutter_packages
OpenHarmony 社区维护了一系列 Flutter 社区插件的 Fork 适配。该项目基于 Flutter 社区插件库进行 OpenHarmony 兼容适配,采用的就是在原仓库中添加 ohos 目录的模式。
使用者通过 git 依赖引入:
dependencies:
shared_preferences:
git:
url: https://gitcode.com/openharmony-tpc/flutter_packages.git
path: packages/shared_preferences
这种模式的优势是一次性 Fork 整个 flutter/packages 仓库,可以同时对多个社区插件做适配,形成"一站式"的鸿蒙插件解决方案。
适用场景
- 乐于接受通过 git 依赖引入(而非 pub.dev)
核心局限
Fork 分支与上游存在长期同步压力。原插件发布新版本时,Fork 分支需要手动合并,期间可能产生冲突,维护成本随时间递增。
优化方案:壳工程模式
纯 Fork 的思路面临一个实际问题:你的主项目既要在 Android/iOS 上使用原插件(pub.dev),又要在 HarmonyOS 上使用 Fork 版插件(git 依赖),pubspec.yaml 中的依赖管理会变得混乱。
一种成熟的优化方案是壳工程模式,即把鸿蒙适配做成一个独立的应用工程,与主工程解耦。
monorepo/
├── packages/
│ ├── apps/
│ │ ├── app/ ← 主工程(Android + iOS,原封不动)
│ │ │ ├── lib/
│ │ │ ├── android/
│ │ │ ├── ios/
│ │ │ └── pubspec.yaml ← 依赖原版插件(pub.dev)
│ │ │
│ │ └── ohos_app/ ← 壳工程(鸿蒙适配,独立打包)
│ │ ├── lib/ ← 只是入口,业务代码复用下面的公共模块
│ │ ├── ohos/ ← 鸿蒙原生代码
│ │ └── pubspec.yaml ← 依赖 Fork 版插件
│ │
│ ├── common/ ← 公共模块
│ └── modules/ ← 业务模块
壳工程 ohos_app 的核心设计:
- 使用 flutter_ohos SDK 单独编译,打包为 .hap 格式
- 不包含业务代码,全部通过 path: 依赖引用公共模块
- 通过 pubspec_overrides.yaml 替换 Fork 版插件,无需改动主工程的依赖
# ohos_app/pubspec_overrides.yaml
# 优先级高于 pubspec.yaml,只对壳工程生效
path_provider:
git:
url: "https://gitcode.com/openharmony-sig/flutter_packages.git"
path: "packages/path_provider/path_provider"
关键机制:pubspec_overrides.yaml 是 Dart/Flutter 内置支持的覆盖机制。当执行 flutter pub get 时,pub 会自动读取该文件,将其中的依赖声明提升到最高优先级,覆盖 pubspec.yaml 中的同名依赖。
| 维度 |
直接 Fork |
壳工程模式 |
| 主工程代码 |
可能需要改依赖 |
不受任何影响 |
| Android/iOS 构建 |
不受影响 |
完全隔离 |
| 鸿蒙构建 |
可能污染 lock 文件 |
独立 lock 文件 |
| 版本管理 |
两套版本混在一起 |
独立版本号、独立打包 |
| 团队协作 |
所有开发者需处理 Fork |
鸿蒙团队维护壳工程即可 |
壳工程让"思路二"从"改主工程依赖"变成了"新建一个专门的项目",隔离性更好,也更适合团队并行开发。
决策逻辑
是否有能力长期维护 Fork 分支与上游的同步?
├─ 是,且有多个插件需要一次性适配 → 思路二
│ └─ 进一步:是否需要隔离主工程? → 壳工程模式
└─ 否,或只适配少数插件 → 思路三或四
开发者视角
代码侵入度:低 🟢
dependencies:
shared_preferences:
git:
url: https://gitcode.com/openharmony-tpc/flutter_packages.git
path: packages/shared_preferences
Dart 代码零修改。原插件的 API 完全保留,调用方式不变。
跨平台兼容性:中 🟡
Android/iOS 用原插件(pub.dev),HarmonyOS 用 Fork 版(git 依赖)。同一插件在不同平台来源不同,pubspec.lock 中的版本一致性需要手动维护。如果采用壳工程模式,隔离性会好很多。
开发者友好度:中 🟡
| 阶段 |
体验 |
| 初始配置 |
简单,只改依赖地址 |
| 日常开发 |
良好,API 不变 |
| 原插件升级 |
⚠️ 需手动合并上游变更,可能冲突 |
| 团队协作 |
⚠️ 需共享 Fork 仓库权限 |
| CI/CD |
git 依赖在网络受限环境可能不稳定 |
结论: 适合短期验证或原型开发。如果只是验证鸿蒙适配是否可行,Fork 改依赖是最快的方式。壳工程模式可以缓解长期维护压力,但涉及 FFI 等非标准通信的插件仍然需要此方案。
思路三:联合插件
架构思想
联合插件(Federated plugins)是 Flutter 官方推荐的插件架构,将一个插件拆为三类独立包:
xxx_plugin/ ← 面向应用的接口(用户直接使用)
xxx_platform_interface/ ← 抽象接口定义
xxx_android/ ← Android 实现
xxx_ios/ ← iOS 实现
xxx_ohos/ ← 鸿蒙实现(新增)
当原插件已经是联合插件架构时,新增一个 xxx_ohos 包即可,它作为 ohos 平台实现注册到主包中。
情况一:已整合至主包
ohos 实现已被主包接纳,成为官方认可的正式平台。
典型案例:screen_brightness_ohos
screen_brightness_ohos 是 screen_brightness 插件的鸿蒙平台实现。
screen_brightness (v2.1.9) — 主包
├─ screen_brightness_platform_interface ← 抽象接口
├─ screen_brightness_android
├─ screen_brightness_ios
├─ screen_brightness_macos
├─ screen_brightness_windows
└─ screen_brightness_ohos (v2.1.3) ← 被主包自动引入
关键看主包 screen_brightness 的 pubspec.yaml:
# screen_brightness/pubspec.yaml
dependencies:
screen_brightness_platform_interface: ">=2.1.1 <3.0.0"
screen_brightness_android: ">=2.1.5 <3.0.0"
screen_brightness_ios: ">=2.1.3 <3.0.0"
screen_brightness_ohos: ">=2.1.3 <3.0.0" # 已纳入主包依赖
flutter:
plugin:
platforms:
ohos:
default_package: screen_brightness_ohos # 正式注册
使用方式极其简单:用户只需引入主包,ohos 实现会自动被拉取:
dependencies:
screen_brightness: ^2.1.9 # 自动包含 ohos 实现
这是最理想的状态 —— ohos 已成为主包的一等公民,用户无需感知 ohos 实现包的存在。
情况二:未整合至主包
ohos 实现包已开发完成并发布到 pub.dev,但尚未被主包接纳为官方平台。
典型案例:wakelock_plus_ohos
wakelock_plus_ohos 是 wakelock_plus 的鸿蒙实现。但主包 wakelock_plus 的 pubspec.yaml 中列出了 android、ios、windows、macos、linux、web,但没有 ohos。
使用者需要手动同时引入两个包:
dependencies:
wakelock_plus: ^1.6.1 # 主包
wakelock_plus_ohos: ^0.0.3 # 鸿蒙实现(手动添加)
| 维度 |
已整合 (screen_brightness) |
未整合 (wakelock_plus) |
| 用户依赖 |
只需主包 |
主包 + ohos 包都需要 |
| 可见性 |
用户无感知 |
用户需知道 ohos 包的存在 |
| 升级节奏 |
跟随主包发布 |
需独立跟踪主包版本 |
| 社区采纳 |
已被官方接纳 |
待社区 PR 合入 |
开发者视角
代码侵入度:零 🟢
# 已整合:只需一行
dependencies:
screen_brightness: ^2.1.9 # 自动包含 ohos 实现
# 未整合:多写一行
dependencies:
wakelock_plus: ^1.6.1
wakelock_plus_ohos: ^0.0.3
Dart 业务代码零修改。import 路径不变,API 调用不变,不需要平台判断。
跨平台兼容性:高 🟢
同一代码库,同一套 import,同一套 API 调用,编译 Android → 自动使用 android 实现,编译 iOS → 自动使用 ios 实现,编译 OHOS → 自动使用 ohos 实现。
ohos 包只在鸿蒙编译时生效,不会影响 Android 和 iOS 的构建。
开发者友好度:高 🟢
业务开发者无感知,不需要了解底层实现。平台实现的更新由插件维护者负责。团队协作只需在 pubspec.yaml 中加一行依赖。
结论: 最高优先级的方案。如果原插件已是联合架构,这是唯一正确的选择,对现有代码的侵入为零。
思路四:基于联合插件理念(普通插件改造)
架构思想
大部分 Flutter 插件并非联合插件架构 —— 它们将所有平台实现集成在同一个包内,使用 pluginClass 声明各平台。对于这类插件,我们可以借鉴联合插件的理念,创建一个独立的 xxx_ohos 包。
这个包的独特设计:
- MethodChannel 名称与原插件 Dart 层完全一致
- 通过在 pubspec.yaml 中声明 ohos 平台,引擎启动时自动注册
Flutter App
│
├─ 依赖原插件 (app_set_id) ← 用户引入这个
│ └─ MethodChannel('app_set_id').invoke('getIdentifier')
│ │
│ ▼
│ MethodChannel 路由
│ ┌──────┬──────┐
│ ▼ ▼ ▼
│ android ios OHOS
│ ↑
└─ 依赖鸿蒙实现包 (app_set_id_ohos) ─────────┘
核心逻辑:原插件的 Dart 层已经创建了 MethodChannel 并发起调用,ohos 包只需要用相同的 channel name 注册一个 ArkTS 处理器即可。用户不需要 import 这个包 —— 它只在构建期起作用。
典型案例:app_set_id_ohos
app_set_id 是一个用于获取 App Set ID 的 Flutter 插件,它是一个普通插件(非联合架构),支持 Android、iOS、macOS、Web 平台,通过 MethodChannel 通信。
app_set_id_ohos 针对它做了鸿蒙适配:
# app_set_id_ohos/pubspec.yaml
name: app_set_id_ohos
flutter:
plugin:
platforms:
ohos:
package: nl.u2312.app_set_id
pluginClass: AppSetIdPlugin
与思路三(联合插件)中依赖平台接口不同,这里的 ohos 包没有依赖平台抽象接口,而是直接注册了一个与主包同名的 MethodChannel 处理器。
使用方式:
dependencies:
app_set_id: ^1.4.0 # 主包,提供 API
app_set_id_ohos: ^1.4.0 # 鸿蒙平台实现
import 'package:app_set_id/app_set_id.dart'; // 只需引入主包
final id = await AppSetId.identifier; // 调用原插件 API
// 底层自动路由到 app_set_id_ohos 的 ArkTS 实现
开发者视角
代码侵入度:零 🟢
dependencies:
app_set_id: ^1.4.0 # 原插件
app_set_id_ohos: ^1.4.0 # 鸿蒙实现(只需在yaml声明,不用import)
Dart 代码零修改,无需平台判断,无需条件编译,不需要 import 任何新东西。
跨平台兼容性:高 🟢
一行代码跑三端,ohos 实现包只在鸿蒙编译时激活,Android 和 iOS 的构建完全不受影响。
开发者友好度:高 🟢
与思路三几乎相同的使用体验。ohos 包可发布到 pub.dev,使用标准依赖管理,比思路二的 git 依赖更稳定。唯一的额外成本是:需要知道"哪些插件需要额外添加 ohos 包"。
但有一个前置条件:使用此方案前,必须在原插件 Dart 代码中确认它使用 MethodChannel 通信。如果原插件使用 FFI 调用 C 库(如 sqflite),此方案不适用,需要回退到思路二。
结论: 实际项目中最常用的方案。大部分插件是普通插件而非联合插件,思路四完美填补了这个缺口。
四种思路架构对比
| 维度 |
思路一 |
思路二 |
思路三(已整合) |
思路三(未整合) |
思路四 |
| Dart 层 |
重写 |
不动 |
新增实现类 |
新增实现类 |
无 |
| 原生层 |
全量新建 |
ohos/ 目录 |
独立 ohos 包 |
独立 ohos 包 |
独立 ohos 包 |
| 用户依赖 |
新插件 |
git 引入 |
只需主包 |
主包+ohos包 |
主包+ohos包 |
| API 兼容 |
❌ 不兼容 |
✅ 兼容 |
✅ 兼容 |
✅ 兼容 |
✅ 兼容 |
| 维护耦合 |
低 |
高(同步上游) |
低 |
中(待整合) |
低 |
| 典型案例 |
holding |
OpenHarmony fork |
screen_brightness_ohos |
wakelock_plus_ohos |
app_set_id_ohos |
四方案综合评估对比
| 评估维度 |
思路一 |
思路二 |
思路三 |
思路四 |
| Dart 代码侵入 |
高(改业务代码) |
无 |
无 |
无 |
| pubspec.yaml 修改 |
全量替换 |
改为 git 依赖 |
加一行(或零行) |
加一行 |
| 跨平台代码复用 |
❌ 需加条件分支 |
✅ 完全复用 |
✅ 完全复用 |
✅ 完全复用 |
| 原插件升级影响 |
手动同步 |
需合并 Fork |
自动跟随主包 |
更新依赖版本 |
| 本地开发配置 |
复杂(双依赖源) |
中等(git 依赖) |
简单(pub.dev) |
简单(pub.dev) |
| CI/CD 适配 |
需双构建脚本 |
git 依赖需鉴权 |
标准构建 |
标准构建 |
| 团队学习成本 |
高 |
中 |
低 |
低 |
| 综合推荐度 |
⭐ |
⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
实际项目中的组合策略
在真实项目中,这四种思路不是互斥的,而是可以组合使用的:
项目引用了 15 个插件:
├─ 3 个是联合插件 → 思路三(直接加 ohos 实现包)
├─ 10 个是普通 MethodChannel 插件 → 思路四(开发 ohos 实现包)
├─ 1 个是鸿蒙独有功能 → 思路一(独立开发)
└─ 1 个使用了 FFI → 思路二(Fork 添加 ohos 目录)
一个鸿蒙应用通常需要同时使用多种思路来解决项目中所有插件的适配问题。
快速决策指南
在实际开发中,按照以下流程判断:
第一步:先检查是否有对应插件
Flutter 社区存在对应插件吗?
├─ 否 → 思路一(自主开发)
└─ 是 → 继续
第二步:看原插件 pubspec.yaml
flutter.plugin 下是 default_package 还是 pluginClass?
├─ default_package → 联合插件架构 → 思路三
│ └─ 进一步:ohos 是否已出现在 default_package 列表中?
│ ├─ 已出现 → 无需适配,直接用
│ └─ 未出现 → 开发 xxx_ohos → 推 PR 合入
│
└─ pluginClass → 普通插件 → 继续第三步
第三步:看原插件 Dart 源码
是否使用 MethodChannel 通信?
├─ 是 → 思路四(创建 xxx_ohos 独立包)
└─ 否(FFI、PlatformView 等)→ 思路二(Fork 添加 ohos 目录)
总结
Flutter 三方插件的鸿蒙化适配,核心逻辑可以归结为一句话:在不修改原插件 Dart 代码的前提下,为鸿蒙平台提供原生层 MethodChannel 处理器。
四种思路的本质差异在于原生代码的组织方式和 Dart 代码的修改程度:
- 思路一(独立仓库): 连 Dart 代码一起重写,适合鸿蒙独有功能
- 思路二(Fork 修改): 在原仓库内增加 ohos 目录,适合批量适配、短期方案
- 思路三(联合插件): 原插件已是联合架构时新增平台实现包,最为规范
- 思路四(联合插件理念): 普通插件借联合插件的理念创建纯原生实现包,最具通用性
在实际项目中,超过 80% 的适配场景可以用思路三或思路四完成。最关键的判断依据是:确认原插件使用 MethodChannel 作为通信方式,并找到正确的 channel name。
参考文档
- HarmonyOS Flutter SDK(flutter_ohos)[2]
- OpenHarmony-tpc/flutter_packages[3]
- screen_brightness_ohos[4]
引用链接
[1]Flutter 联合插件官方文档: https://docs.flutter.dev/development/packages-and-plugins/developing-packages#federated-plugins
[2]HarmonyOS Flutter SDK(flutter_ohos): https://gitcode.com/openharmony-sig/flutter_flutter
[3]OpenHarmony-tpc/flutter_packages: https://gitcode.com/openharmony-tpc/flutter_packages
[4]screen_brightness_ohos: https://pub.dev/packages/screen_brightness_ohos
[5]wakelock_plus_ohos: https://pub.dev/packages/wakelock_plus_ohos
[6]app_set_id_ohos: https://pub.dev/packages/app_set_id_ohos
[7]holding: https://pub.dev/packages/holding