全栈开发知识库

09 鸿蒙(HarmonyOS NEXT / OpenHarmony)平台开发

9.1 现状与原理

HarmonyOS NEXT(纯血鸿蒙,HarmonyOS 5 及以后)不再兼容 APK,应用必须是 HAP 包,原生开发语言为 ArkTS,UI 框架为 ArkUI。Google 官方 Flutter 不支持鸿蒙;可用的是 OpenHarmony SIG 社区(华为及合作伙伴主导)维护的分支 Flutter OH:

  • 仓库:gitcode.com/openharmony-sig/flutter_flutter(Gitee 有镜像)。
  • 版本:跟随官方版本做适配,tag 形如 3.27.5-ohos-x.x.x(基于 3.27.4)、3.35.8-ohos-x.x.x(基于 3.35.7)、3.41.10-ohos-x.x.x(基于 3.41.9)。官方计划中 3.44、3.47 的适配版本分别预计在 2026/09、2026/12 发布,以仓库公告为准。鸿蒙版本通常落后官方 stable 1~2 个大版本。
  • 3.35.7 起,引擎源码合并进同一仓库的 engine/ 目录。

原理(对照第 6 章):Framework(Dart)层基本不变,社区新增了:

Flutter Framework(Dart)         增加 TargetPlatform.ohos 等少量改动
Flutter Engine(C++)             新增 OHOS 平台 shell:
                                    - 渲染到 ArkUI XComponent 提供的 NativeWindow
                                    - VSync 来自鸿蒙 NativeVsync
                                    - 输入、键盘、无障碍、字体对接鸿蒙 NDK
                                    - GPU:OpenGL ES,新版本支持 Impeller(Vulkan)
Embedder(ArkTS + NAPI)          flutter_ohos HAR 包:
                                    FlutterAbility / FlutterPage / FlutterEngine
                                    MethodChannel / EventChannel / PlatformView / Texture
                                    插件接口 FlutterPlugin
宿主工程 ohos/                    DevEco Studio 工程(hvigor 构建、ohpm 依赖)

可以看到架构与 Android 一一对应:FlutterActivity → FlutterAbility,FlutterView → FlutterPage(基于 XComponent),Java 插件 → ArkTS 插件,JNI → NAPI,Gradle → hvigor,Maven → ohpm。

9.2 环境搭建

1. 安装 DevEco Studio

从华为开发者联盟下载 DevEco Studio(自带 HarmonyOS SDK、ohpm、hvigor、node、hdc)。登录华为账号,用于自动签名。

2. 安装 Flutter OH SDK(与官方 Flutter 并存)

git clone https://gitcode.com/openharmony-sig/flutter_flutter.git ~/sdk/flutter_ohos
cd ~/sdk/flutter_ohos
git checkout 3.35.8-ohos-1.0.x     # 选择最新稳定 tag,以仓库 Release 为准

推荐用 FVM 管理:把该目录放入 FVM 的版本目录(~/fvm/versions/3.35.8-ohos),项目内 fvm use 3.35.8-ohos。

3. 环境变量(macOS,~/.zshrc)

# DevEco Studio 工具链
export TOOL_HOME=/Applications/DevEco-Studio.app/Contents
export DEVECO_SDK_HOME=$TOOL_HOME/sdk
export PATH=$TOOL_HOME/tools/ohpm/bin:$PATH
export PATH=$TOOL_HOME/tools/hvigor/bin:$PATH
export PATH=$TOOL_HOME/tools/node/bin:$PATH
export PATH=$DEVECO_SDK_HOME/default/openharmony/toolchains:$PATH   # hdc

# Flutter OH(注意:这个镜像地址与官方 Flutter 的不同)
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://flutter-ohos.obs.cn-south-1.myhuaweicloud.com
export PATH=$HOME/sdk/flutter_ohos/bin:$PATH

变量名和路径以 Flutter OH 仓库《环境搭建指导》为准,DevEco 版本升级后目录可能变化。

注意:

  • FLUTTER_STORAGE_BASE_URL 必须指向华为云的鸿蒙引擎产物地址;官方 Flutter 则使用 storage.flutter-io.cn。在两个 SDK 之间切换时,修改该值后要删除对应 SDK 的 bin/cache 并执行 flutter clean,否则会报 Dart VM snapshot 版本不匹配。
  • hvigor 依赖 ~/.npmrc 中配置的华为 npm 源。
  • 建议写一个切换脚本,或者只在 FVM 的项目级环境中设置,避免和官方 Flutter 互相污染。

4. 检查

flutter doctor -v     # 应出现 HarmonyOS toolchain 一项
flutter devices       # 连接鸿蒙真机(打开开发者模式和 USB 调试)或启动模拟器
hdc list targets

模拟器限制:仅支持 Apple Silicon Mac 和 Windows x64,不支持 Intel Mac;模拟器不支持 Vulkan,需要关闭 Impeller(参考仓库 FAQ)。真机是性能和兼容性测试的唯一依据。

9.3 创建工程 / 给现有工程加鸿蒙

# 新工程
flutter create --platforms ohos,android,ios --org com.example my_app

# 现有工程添加 ohos 目录
cd existing_app
flutter create --platforms ohos .

# 插件 / module
flutter create -t plugin --platforms ohos,android,ios my_plugin
flutter create -t module my_module

ohos/ 目录结构:

ohos/
├── AppScope/
│   ├── app.json5                 # bundleName、versionCode/versionName、图标(≈ Manifest application)
│   └── resources/
├── entry/                        # 主模块(≈ app module)
│   ├── src/main/
│   │   ├── ets/
│   │   │   ├── entryability/EntryAbility.ets   # ≈ MainActivity
│   │   │   ├── pages/Index.ets                 # 承载 FlutterPage 的 ArkUI 页面
│   │   │   └── plugins/GeneratedPluginRegistrant.ets
│   │   ├── module.json5          # 权限、Ability 声明(≈ AndroidManifest)
│   │   └── resources/
│   ├── oh-package.json5          # 模块依赖(≈ build.gradle dependencies)
│   └── build-profile.json5
├── build-profile.json5           # 工程级:签名、products、compatibleSdkVersion
├── hvigorfile.ts                 # ≈ build.gradle
└── oh-package.json5              # 依赖 @ohos/flutter_ohos 等

9.4 构建与运行

flutter run -d <device>              # 调试
flutter build hap --debug
flutter build hap --release          # 产物在 ohos/entry/build/default/outputs/default/*.hap
flutter build app --release          # 上架应用市场的 .app 包
  • 签名:用 DevEco Studio 打开 ohos/ 目录,File → Project Structure → Signing Configs,勾选自动签名(需登录华为账号,真机调试必须签名)。签名信息写入 ohos/build-profile.json5,发布签名材料不要提交到公开仓库。
  • profile 模式需在 build-profile.json5 中添加对应的 buildModeSet。
  • 也可以在 DevEco Studio 中直接运行 ohos 工程(此时 Dart 产物需要先用 flutter build hap 生成),方便调试 ArkTS 代码和查看 hilog。

9.5 宿主入口代码

// ohos/entry/src/main/ets/entryability/EntryAbility.ets
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
import { BatteryPlugin } from '../plugins/BatteryPlugin';

export default class EntryAbility extends FlutterAbility {
  configureFlutterEngine(flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine);
    GeneratedPluginRegistrant.registerWith(flutterEngine);   // pubspec 中的插件
    this.addPlugin(new BatteryPlugin());                     // App 私有插件
  }
}
// ohos/entry/src/main/ets/pages/Index.ets
import common from '@ohos.app.ability.common';
import { FlutterPage } from '@ohos/flutter_ohos';

let storage = LocalStorage.getShared();
const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS';

@Entry(storage)
@Component
struct Index {
  private context = getContext(this) as common.UIAbilityContext;
  @LocalStorageLink('viewId') viewId: string = '';

  build() {
    Column() {
      FlutterPage({ viewId: this.viewId })   // 内部是 XComponent,Flutter 在上面绘制
    }
  }

  // 系统返回手势/返回键交给 Flutter 的 Navigator 处理
  onBackPress(): boolean {
    this.context.eventHub.emit(EVENT_BACK_PRESS);
    return true;
  }
}

以上为 flutter create 生成的模板代码,不同 Flutter OH 版本略有差异,以本地生成的为准。

9.6 ArkTS 插件开发

Dart 侧代码与 Android/iOS 完全相同(同一个 MethodChannel('com.example/battery')),只需要补充 ArkTS 实现。

// ohos/entry/src/main/ets/plugins/BatteryPlugin.ets
import {
  FlutterPlugin,
  FlutterPluginBinding,
  MethodCall,
  MethodCallHandler,
  MethodChannel,
  MethodResult,
} from '@ohos/flutter_ohos';
import batteryInfo from '@ohos.batteryInfo';

export class BatteryPlugin implements FlutterPlugin, MethodCallHandler {
  private channel: MethodChannel | null = null;

  getUniqueClassName(): string {
    return 'BatteryPlugin';
  }

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.channel = new MethodChannel(binding.getBinaryMessenger(), 'com.example/battery');
    this.channel.setMethodCallHandler(this);
  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    this.channel?.setMethodCallHandler(null);
    this.channel = null;
  }

  onMethodCall(call: MethodCall, result: MethodResult): void {
    switch (call.method) {
      case 'getLevel':
        result.success(batteryInfo.batterySOC);   // 电量百分比
        break;                                    // 不要漏 break,否则会落到 default 再次回复
      default:
        result.notImplemented();
    }
  }
}

较老的 Flutter OH 版本中,部分类型需要从子路径导入,例如 @ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin、@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel。如果从包根路径导入时报错,按 IDE 提示改为子路径。

异步调用系统 API 的写法:

onMethodCall(call: MethodCall, result: MethodResult): void {
  if (call.method === 'getPrefs') {
    const key: string = call.argument('key');
    this.store.get(key, '')
      .then((v) => result.success(v))
      .catch((e: Error) => result.error('PREFS_ERROR', e.message, null));
    return;                                       // 每个分支只回复一次
  }
  result.notImplemented();
}

需要 UIAbility(拉起页面、申请权限)时实现 AbilityAware,在 onAttachedToAbility(binding) 中拿到 binding.getAbility(),与 Android 的 ActivityAware 对应。

独立插件包的鸿蒙实现

flutter create -t plugin --platforms ohos my_plugin
my_plugin/
├── lib/my_plugin.dart
├── android/  ios/
└── ohos/                         # 一个 HAR 模块(≈ Android library)
    ├── index.ets                 # 导出插件类
    ├── oh-package.json5          # 依赖 @ohos/flutter_ohos
    └── src/main/ets/components/plugin/MyPlugin.ets
flutter:
  plugin:
    platforms:
      ohos:
        pluginClass: MyPlugin

ArkTS 与 Kotlin 的差异(写插件时最常见的报错)

ArkTS 是 TypeScript 的严格子集:

  • 不允许 any / unknown,所有变量和返回值需要明确类型。
  • 不支持对象字面量直接作为类型(需要先声明 class / interface)。
  • 不支持解构赋值、for..in、动态增删属性。
  • 系统能力以 @ohos.xxx / @kit.XxxKit 模块导入,异步 API 多为 Promise 风格。
  • 主线程是 ArkTS UI 线程,耗时任务用 taskpool 或 worker。

9.7 PlatformView(嵌入 ArkUI 组件)

Dart 侧:

OhosView(                                // Flutter OH 新增的 Widget
  viewType: 'com.example/native_button',
  creationParams: const {'text': 'from flutter'},
  creationParamsCodec: const StandardMessageCodec(),
);

ArkTS 侧(结构示意,API 细节以所用版本的示例工程为准):

import common from '@ohos.app.ability.common';
import { PlatformView, PlatformViewFactory, StandardMessageCodec, Params } from '@ohos/flutter_ohos';

@Component
struct NativeButton {
  @Prop params: Params;
  build() {
    Button('ArkUI 原生按钮').onClick(() => { /* ... */ })
  }
}

@Builder
function buildNativeButton(params: Params) {
  NativeButton({ params: params })
}

class NativeButtonView extends PlatformView {
  getView(): WrappedBuilder<[Params]> {
    return new WrappedBuilder(buildNativeButton);
  }
  dispose(): void {}
}

export class NativeButtonFactory extends PlatformViewFactory {
  constructor() {
    super(StandardMessageCodec.INSTANCE);
  }
  public create(context: common.Context, viewId: number, args: Object): PlatformView {
    return new NativeButtonView();
  }
}

// 插件 onAttachedToEngine 中注册
// binding.getPlatformViewRegistry()?.registerViewFactory('com.example/native_button', new NativeButtonFactory());

外接纹理:通过 binding.getTextureRegistry() 注册纹理,原生侧把 NativeWindow/surfaceId 交给播放器或相机渲染,Dart 端用 Texture(textureId:) 显示。video_player、camera 的鸿蒙实现就是这样做的,可以直接参考其源码。

9.8 三方库适配

pub.dev 上的包分两类:

  1. 纯 Dart 包(dio、provider、riverpod、go_router、freezed、intl…):不含原生代码,在鸿蒙上直接可用。
  2. 含原生代码的插件(shared_preferences、path_provider、camera、image_picker、webview_flutter、permission_handler…):pub.dev 版本没有 ohos 实现,运行时会抛 MissingPluginException。

处理方式:

# pubspec.yaml:用社区适配版本覆盖
dependency_overrides:
  shared_preferences:
    git:
      url: https://gitcode.com/openharmony-sig/flutter_packages.git
      path: packages/shared_preferences/shared_preferences
      ref: <tag 或 commit>          # 务必锁定,避免随默认分支变化
  path_provider:
    git:
      url: https://gitcode.com/openharmony-sig/flutter_packages.git
      path: packages/path_provider/path_provider
      ref: <tag 或 commit>
  permission_handler:
    git:
      url: https://gitcode.com/openharmony-sig/flutter_permission_handler.git
      path: permission_handler
      ref: <tag 或 commit>

查找已适配的库:

  • openharmony-sig/flutter_packages:官方 plugins 的鸿蒙实现(camera、video_player、webview_flutter、url_launcher、image_picker、shared_preferences、path_provider 等)。
  • openharmony-sig/fluttertpc_*:热门三方插件的适配(命名形如 fluttertpc_<包名>)。
  • Flutter OH 仓库中的“三方库适配列表”文档。

没有适配的插件:

  1. 联邦插件:新建一个 xxx_ohos 包实现 xxx_platform_interface,在 pubspec 中 default_package 关联。
  2. 非联邦插件:fork 后增加 ohos/ 目录和 pubspec.yaml 中的 ohos 平台声明。
  3. 依赖 C/C++ 的 FFI 插件:用鸿蒙 NDK(CMake 工具链 ohos.toolchain.cmake,arm64-v8a,musl libc)重新编译 so。Android NDK 编译的 so 不能直接用。
  4. 依赖 Android/iOS 原生 SDK 的插件(地图、推送、支付、登录、统计):需要接入该厂商的鸿蒙版 SDK(HAR 包),用 ArkTS 重写插件实现。这是鸿蒙适配中工作量最大的部分,排期时要逐个评估。

9.9 Add-to-App:现有鸿蒙原生工程接入 Flutter

flutter create -t module my_module
cd my_module
flutter build har --release          # 产出 flutter.har(引擎)和 my_module.har 等

宿主工程 oh-package.json5:

{
  "dependencies": {
    "@ohos/flutter_ohos": "file:./har/flutter.har",
    "@ohos/flutter_module": "file:./har/my_module.har"
  }
}

在原生 UIAbility 中初始化 FlutterManager,在 ArkUI 页面中使用 FlutterEntry 承载 Flutter(≈ Android 的 FlutterFragment):

// EntryAbility.ets(宿主)
import { FlutterManager } from '@ohos/flutter_ohos';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    FlutterManager.getInstance().pushUIAbility(this);
  }
  onDestroy(): void {
    FlutterManager.getInstance().popUIAbility(this);
  }
  onWindowStageCreate(windowStage: window.WindowStage): void {
    FlutterManager.getInstance().pushWindowStage(this, windowStage);
    windowStage.loadContent('pages/Index');
  }
  onWindowStageDestroy() {
    FlutterManager.getInstance().popWindowStage(this);
  }
}
// FlutterHostPage.ets(宿主中的某个页面)
import { FlutterEntry, FlutterPage, FlutterView } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '@ohos/flutter_module';

@Entry
@Component
struct FlutterHostPage {
  private flutterEntry?: FlutterEntry;
  private flutterView?: FlutterView;

  aboutToAppear() {
    this.flutterEntry = new FlutterEntry(getContext(this));   // 可传 initialRoute 参数
    this.flutterEntry.aboutToAppear();
    this.flutterView = this.flutterEntry.getFlutterView();
    GeneratedPluginRegistrant.registerWith(this.flutterEntry.getFlutterEngine()!);
  }
  aboutToDisappear() { this.flutterEntry?.aboutToDisappear(); }
  onPageShow() { this.flutterEntry?.onPageShow(); }
  onPageHide() { this.flutterEntry?.onPageHide(); }

  build() {
    FlutterPage({ viewId: this.flutterView?.getId() })
  }
}

接入 API 在不同 Flutter OH 版本之间有调整,以对应版本仓库中的 add-to-app 文档和示例为准。混合栈可使用已适配鸿蒙的 flutter_boost。

9.10 一套代码中区分鸿蒙

import 'dart:io' show Platform;

// 用字符串比较,代码在官方 Flutter(没有 ohos 枚举值)下也能编译
bool get isOhos => !kIsWeb && Platform.operatingSystem == 'ohos';

注意:TargetPlatform.ohos 只存在于 Flutter OH SDK 中,如果直接写进业务代码,用官方 Flutter 构建 Android/iOS 时会编译失败。

9.11 鸿蒙端常见问题

问题 原因 / 解决
MissingPluginException 插件没有 ohos 实现 → 用 dependency_overrides 替换为适配版或自行适配
两套 SDK 版本不一致 官方 Flutter(3.47)与 Flutter OH(3.35)同时维护:Dart 代码必须兼容较低版本;第三方包版本取两边都能解析的版本;CI 分两条流水线。或者三端统一使用 Flutter OH 的版本(它同样支持 Android/iOS 构建),降低维护成本
pubspec.lock 冲突 两个 SDK 解析出的锁文件不同,可分别生成,或以 Flutter OH 版本为基准统一
Dart VM snapshot 版本不匹配 FLUTTER_STORAGE_BASE_URL 设置错误,修正后删除 bin/cache 并 flutter clean
hvigor 构建失败 / 找不到 module.json5 检查 ~/.npmrc、DevEco 版本、插件工程结构是否为新版格式(参考仓库“插件工程结构升级”文档)
真机安装失败(签名) DevEco 中重新自动签名;设备开启开发者模式;pkcs7 校验失败时参照 FAQ 设置 persist.bms.ohCert.verify
日志看不到 使用 hdc hilog,或在 DevEco 的 Log 面板按 domain/tag 过滤;日志太多时会被限流丢失
权限申请 module.json5 的 requestPermissions 中声明,user_grant 类权限还需运行时调用 abilityAccessCtrl.requestPermissionsFromUser;使用适配版 permission_handler
字体与行高差异 鸿蒙默认字体为 HarmonyOS Sans,与 Android 的 Roboto/思源黑体行高不同,关键 UI 可内置统一字体(见第 10 章)
返回手势无效 检查 Index.ets 的 onBackPress 是否把事件转发给 Flutter
输入法/键盘遮挡 使用新版本 Flutter OH;页面设置 resizeToAvoidBottomInset;必要时在 ArkTS 侧设置 KeyboardAvoidMode
模拟器黑屏 模拟器不支持 Vulkan,关闭 Impeller;Intel Mac 不支持模拟器
性能比 Android 差 确认用 release 包测试;确认是否开启 Impeller;排查 PlatformView 数量;见第 11 章
华为应用市场上架 需要 AGC 发布证书和 Profile;产物为 .app(flutter build app);隐私声明、权限用途说明要完整

9.12 鸿蒙适配工作量评估清单

  1. 列出 pubspec.yaml 中所有带原生代码的插件(flutter pub deps 后查看是否有 android/ ios/ 目录)。
  2. 逐个查询社区是否已适配,记录对应仓库和版本。
  3. 未适配的插件:评估是否有鸿蒙版原生 SDK、是否需要用 ArkTS 重写。
  4. App 自己的 MethodChannel:逐个用 ArkTS 实现。
  5. C/C++ so:用鸿蒙 NDK 重新编译。
  6. 检查代码中 Platform.isAndroid/Platform.isIOS 分支,补充鸿蒙分支。
  7. 真机全量回归:布局、字体、键盘、返回、权限、分享、推送、支付、登录、深链。

动手练习

  1. 安装 DevEco Studio 与 Flutter OH,在鸿蒙真机运行计数器 Demo。
  2. 给第 7 章的电量插件补充 ArkTS 实现,一套 Dart 代码在 Android 与鸿蒙上都能拿到电量。
  3. 在一个使用了 shared_preferences 和 path_provider 的工程中,通过 dependency_overrides 让其在鸿蒙上运行。
本页由 Markdown 自动渲染 · 共 628 篇笔记