Flutter 适配 HarmonyOS 完整教程:从零到上架的踩坑指南
Flutter 适配 HarmonyOS 完整教程:从零到上架的踩坑指南
> 面向已经会用 Flutter 发 Android / iOS 包的工程师。
> 读完本文,你应该能:搭好鸿蒙工具链 → 让现有项目编出第一份 HAP → 处理插件与业务兼容 → 打出可上架的 `.app`。
这不是「再写一个 Hello World」,而是基于真实 App 上架过程的实操路线。文中示例包名统一写成 com.example.myapp,请自行替换。
你会得到什么
- 为什么官方 Flutter 不够用,必须换哪一条工具链
- 第一步到第 N 步该装什么、改什么、跑什么命令
- 插件怎么配才能编过(这是最长的一坑)
- 业务怎么裁剪:登录、存储、WebView、通知、推送等
- 调试 HAP vs 上架 APP 分别怎么出包
- 签名与华为登录 clientId 如何避免上架后立刻翻车
先建立正确心智模型(读完再动手)
把现有 Flutter 应用「搬」到鸿蒙,不是加一个 flavor。它更接近「加了一条完整新平台工具链」:
| 认知 | 现实 |
|---|---|
flutter build apk 一套就够 | 官方 Flutter 没有 hap / ohos app 子命令 |
| 插件写好 Android 实现就行 | 多数联邦插件 没有 OHOS 实现,要整链 override |
改几行 Platform.isAndroid | 要系统做能力矩阵:Firebase / 通知 / 部分原生库要降级 |
| 打个 release 包就能上架 | 调试用 .hap,应用市场要 .app,签名与 OAuth 还要对齐 |
可以用一句话记住:
OHOS Flutter Fork + ohos 原生工程 + 插件整链 override + Dart 能力裁剪 + 发布签名与华为登录对齐。
接下来按顺序做。不要跳步——很多人卡在第三天,是因为第 1~2 步没配对就去改业务代码。
总流程一览
第 1 步 安装 DevEco Studio,准备 HarmonyOS SDK 目录
第 2 步 安装 / 配置 OpenHarmony 版 Flutter(Fork)
第 3 步 为现有项目生成 / 核对 ohos 工程
第 4 步 写 local.properties,对齐 SDK 与 Flutter 路径
第 5 步 配置调试签名,能 SignHap
第 6 步 改造 pubspec:ohos 插件 + dependency_overrides
第 7 步 写平台抽象 AppPlatform,先让项目能分析通过
第 8 步 首次 flutter build hap --debug,真机安装
第 9 步 逐项适配业务(登录 / 存储 / WebView / TTS / 支付…)
第 10 步 配置发布签名,flutter build app --release 上架
下面逐步展开。
第 1 步:安装 DevEco,准备 SDK 目录
1.1 安装什么
- 从华为开发者网站安装 DevEco Studio(macOS 下常见路径:
/Applications/DevEco-Studio.app) - 打开 DevEco,按向导下载 HarmonyOS SDK(当前工程实践多为 API 24 / HarmonyOS 6.1.1 一类版本,以你 DevEco 可选版本为准)
- 确认命令行工具可用:
# hdc:鸿蒙设备连接工具,一般在 DevEco 的 sdk/.../toolchains 下
hdc list targets
能看到已连接设备,或暂时为空但命令可执行,都说明工具链大致在。
1.2 关键坑:SDK 目录名必须符合 hvigor 约定
hvigor 6.x 一类构建常常要求本机存在类似结构:
~/Library/OpenHarmony/Sdk/HarmonyOS-6.1.1/
├── openharmony/
│ ├── ets
│ ├── native
│ ├── toolchains
│ └── ...
└── hms/
├── ets
├── native
└── ...
现象: 编译报找不到 HarmonyOS-6.1.1 / API 24。
原因: DevEco 内置 SDK 路径往往是 Contents/sdk/default/openharmony,不等于上面这个目录名约定。
做法: 把 DevEco 内组件软链(或拷贝)到约定目录。可参考下面脚本逻辑自行落地:
#!/usr/bin/env bash
set -euo pipefail
```text
DEVECO_APP="${DEVECO_APP:-/Applications/DevEco-Studio.app}"
SDK_HOME="${HOME}/Library/OpenHarmony/Sdk"
SOURCE_OH="${DEVECO_APP}/Contents/sdk/default/openharmony"
SOURCE_HMS="${DEVECO_APP}/Contents/sdk/default/hms"
TARGET_SDK="${SDK_HOME}/HarmonyOS-6.1.1"
mkdir -p "${TARGET_SDK}/openharmony" "${TARGET_SDK}/hms"
for component in ets js native previewer toolchains; do
ln -sfn "${SOURCE_OH}/${component}" "${TARGET_SDK}/openharmony/${component}"
done
for component in ets native previewer toolchains; do
ln -sfn "${SOURCE_HMS}/${component}" "${TARGET_SDK}/hms/${component}"
done
echo "SDK ready: ${TARGET_SDK}" ls -la "${TARGET_SDK}"
> Windows 用户请按 DevEco 文档配置同等 SDK;核心是让 hvigor 能解析到带 `openharmony/` 与 `hms/` 的完整 SDK。
**本步完成标准:** `~/Library/OpenHarmony/Sdk/HarmonyOS-6.1.1`(或你项目 `compileSdkVersion` 对应的版本名)存在且含子目录。
---
## 第 2 步:安装 OpenHarmony 版 Flutter(Fork)
### 2.1 为什么必须换 Flutter
**在官方稳定版 Flutter 上执行:**
```bash
flutter build -h
你通常只能看到 apk / appbundle / ios / web……没有 hap,也没有鸿蒙含义的 app。
OpenHarmony 社区维护的 Fork(常见来源:openharmony-tpc/flutter_flutter 等,请以官方文档当前推荐仓库为准)才会带上:
flutter build hap # 出调试 / 安装用 HAP
flutter build app # 出应用市场用的 APP 包
以及引擎侧能力:
Platform.operatingSystem == 'ohos'TargetPlatform.ohos
2.2 怎么装
推荐用 FVM 或手动 clone,单独放一个目录,不要覆盖你日常 Android/iOS 用的官方 Flutter。
# 示例:用 FVM 装一份 OHOS 专用 Flutter(版本号以社区当前推荐为准)
# 装完后记住这个 bin/flutter 的绝对路径
export OHOS_FLUTTER="$HOME/fvm/versions/openharmony_tpc/xxx/bin/flutter"
$OHOS_FLUTTER --version
$OHOS_FLUTTER build -h | grep -E 'hap|app'
本步完成标准: $OHOS_FLUTTER build -h 能看到 hap 与 app 两个子命令。
2.3 以后所有鸿蒙命令都用这套 Flutter
养成习惯:
# ❌ 不要
flutter pub get
flutter build hap
```text
# ✅ 要
$OHOS_FLUTTER pub get
$OHOS_FLUTTER build hap --debug
IDE 里也建议为「鸿蒙构建」单独配置 Flutter SDK 路径,避免一键跑错引擎。
---
## 第 3 步:为现有项目准备 `ohos/` 工程
### 3.1 已有 Flutter 项目怎么加鸿蒙端
**典型结构会变成:**
```text
your_flutter_app/
├── android/
├── ios/
├── lib/
├── pubspec.yaml
└── ohos/ # 新增:HarmonyOS Stage 工程
├── AppScope/
│ └── app.json5 # bundleName、versionCode、versionName
├── entry/ # 主模块(类比 android/app)
├── build-profile.json5 # 签名、compileSdk、product
├── hvigorfile.ts
├── local.properties # 本机 SDK / Flutter 路径(一般不提交明文秘密)
└── oh-package.json5
创建方式取决于你使用的 OHOS Flutter 工具版本,常见是:
cd your_flutter_app
$OHOS_FLUTTER create --platforms=ohos .
# 或按当前 Fork 文档中的「为已有项目启用 ohos」命令
然后用 DevEco Studio 打开 ohos/ 目录(注意:打开的是 ohos 工程,不是简单当资源文件夹看一眼)。
3.2 核对三个关键字段
① AppScope/app.json5
{
"app": {
"bundleName": "com.example.myapp",
"vendor": "example",
"versionCode": 100,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}
② build-profile.json5 的 product
{
"app": {
"products": [
{
"name": "default",
"compileSdkVersion": "6.1.1(24)",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.0.0(20)",
"runtimeOS": "HarmonyOS",
"signingConfig": "debug" // 稍后改成你的调试 / 发布配置名
}
]
}
}
③ hvigorfile.ts 要挂上 Flutter 插件
import path from 'path'
import { appTasks } from '@ohos/hvigor-ohos-plugin'
import { flutterHvigorPlugin } from 'flutter-hvigor-plugin'
```text
export default {
system: appTasks,
plugins: [flutterHvigorPlugin(path.dirname(__dirname))],
}
**本步完成标准:** DevEco 能打开 `ohos/`,工程树完整,暂不要求一定编过。
---
## 第 4 步:配置 `local.properties`
在 `ohos/local.properties` 写本机路径(按你机器改):
```properties
hwsdk.dir=/Users/你的用户名/Library/OpenHarmony/Sdk
sdk.dir=/Users/你的用户名/Library/OpenHarmony/Sdk
flutter.sdk=/Users/你的用户名/path/to/openharmony_tpc/flutter
flutter.versionName=1.0.0
flutter.versionCode=100
说明:
flutter.sdk指向 第 2 步那份 OHOS Fork 根目录(含bin/flutter的上一级)versionName/versionCode建议与pubspec.yaml的x.y.z+code、以及AppScope/app.json5三处保持一致
本步完成标准: 路径真实存在,flutter.sdk/bin/flutter --version 可执行。
第 5 步:配置调试签名(否则永远签不出包)
5.1 用 DevEco 生成自动调试签名
- DevEco 打开
ohos工程 File→Project Structure→Signing Configs(具体菜单位置随版本略有差异)- 勾选自动签名,登录华为账号,生成调试证书 / Profile
- 确认
build-profile.json5里已经写入一套调试用的signingConfigs,且 product 的signingConfig指向它
5.2 常见坑:找不到 signing/material
现象: SignHap 报 ENOENT,提示找不到 material。
原因: DevEco 把加密口令材料放在用户目录(如 ~/.ohos/config/material),工程默认路径对不上。
做法: 按 DevEco / 官方文档把 material 拷贝或软链到工程签名目录,或在 Signing Configs 里重新选正确路径。
5.3 先不要碰发布签
此阶段只用 调试签名,目标是:
$OHOS_FLUTTER build hap --debug
能产出已签名 HAP。发布签放到第 10 步。
本步完成标准: DevEco 或 CLI 能完成一次签名构建(哪怕还有其它编译错误,至少签名链路通)。
第 6 步:改造 pubspec.yaml(最长、最易错)
6.1 先认清问题
鸿蒙适配最耗时的不是写页面,而是 插件:
- pub.dev 上很多插件只有 android / ios / web 实现
- 社区在 gitcode 等托管了
*_ohos实现 - 只在 dependencies 里加
foo_ohos往往不够——解析器仍可能选到无 ohos 实现的主线foo
正确姿势是两件套:
- 需要时声明
*_ohos - 用
dependency_overrides钉死foo、foo_platform_interface(如有)到 ohos 分支
6.2 推荐写法模板
dependencies:
flutter:
sdk: flutter
```text
shared_preferences: ^2.5.4
shared_preferences_ohos:
git:
url: https://gitcode.com/openharmony-tpc/flutter_packages.git
path: packages/shared_preferences/shared_preferences_ohos
ref: br_shared_preferences-v2.5.4_ohos # ref 以社区当前分支为准
path_provider: ^2.1.5
path_provider_ohos:
git:
url: https://gitcode.com/openharmony-sig/flutter_packages.git
path: packages/path_provider/path_provider_ohos
ref: br_path_provider-v2.1.5_ohos
permission_handler: ^12.0.1
permission_handler_ohos:
git:
url: https://gitcode.com/CPF-Flutter/flutter_permission_handler.git
path: permission_handler_ohos
ref: br_v12.0.1_ohos
# 按你项目实际用到的再加:
# audioplayers_ohos / open_file_ohos / file_picker_ohos / record ohos 分支 等
dependency_overrides:
# 主包也要钉到 ohos 分支,否则实现选不中
shared_preferences:
git:
url: https://gitcode.com/openharmony-tpc/flutter_packages.git
path: packages/shared_preferences/shared_preferences
ref: br_shared_preferences-v2.5.4_ohos
path_provider:
git:
url: https://gitcode.com/openharmony-sig/flutter_packages.git
path: packages/path_provider/path_provider
ref: br_path_provider-v2.1.5_ohos
permission_handler:
git:
url: https://gitcode.com/CPF-Flutter/flutter_permission_handler.git
path: permission_handler
ref: br_v12.0.1_ohos
# 有 platform_interface 的务必一起 override,例如:
# record + record_platform_interface
# share_plus + share_plus_platform_interface
# webview_flutter + webview_flutter_platform_interface
# audioplayers + audioplayers_platform_interface
**拉取依赖时务必用 OHOS Flutter:**
```bash
$OHOS_FLUTTER pub get
6.3 如何判断还要 override 哪些包
- 把你现有
pubspec.yaml里所有带原生实现的插件列出来 - 逐个在 gitcode / openharmony-sig / openharmony-tpc / 社区仓搜索
*_ohos或br_*_ohos flutter build hap报缺实现、MissingPluginException、或分析器报平台相关错误时,就对这个包补 override- 主包和 platform_interface 用同一族 ref,不要混版本
6.4 特殊雷:TargetPlatform.ohos 让穷尽 switch 编译失败
Fork Flutter 给枚举多了 TargetPlatform.ohos。第三方若写:
switch (Theme.of(context).platform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
// ...
case TargetPlatform.linux:
...
// 没有 ohos → 分析期 / 编译期直接挂
}
典型受害者包括某些播放器控件库(如 chewie)。
改法:
- vendor(拷贝)该库到
third_party/xxx - 把穷尽
switch改成if+ 默认分支 dependency_overrides指到本地 path
示例:
Widget build(BuildContext context) {
final TargetPlatform platform = Theme.of(context).platform;
if (platform == TargetPlatform.iOS) {
return const CupertinoControls(/* ... */);
}
if (platform == TargetPlatform.macOS ||
platform == TargetPlatform.windows ||
platform == TargetPlatform.linux) {
return const MaterialDesktopControls();
}
// Android / ohos / 其他 → Material
return const MaterialControls();
}
本步完成标准: $OHOS_FLUTTER pub get 成功;dart analyze 不再因 TargetPlatform.ohos 报未穷尽。
第 7 步:写平台抽象,避免 if (ohos) 散落全项目
建议一开工就建好平台抽象,后面业务适配都走它。
7.1 条件导出(兼容 Web 编译)
// lib/utils/app_platform.dart
export 'app_platform_stub.dart'
if (dart.library.io) 'app_platform_io.dart';
7.2 IO 实现
// lib/utils/app_platform_io.dart
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart';
```dart
abstract final class AppPlatform {
AppPlatform._();
static bool get isOhos => Platform.operatingSystem == 'ohos';
static bool get isWeb => kIsWeb;
static String get operatingSystem => Platform.operatingSystem;
/// 按你业务真实情况改这些开关
static bool get supportsFirebase =>
Platform.isAndroid ||
Platform.isIOS ||
Platform.isMacOS ||
Platform.isWindows;
static bool get supportsLocalNotifications =>
Platform.isAndroid ||
Platform.isIOS ||
Platform.isLinux ||
Platform.isWindows;
static bool get supportsInAppWebView =>
Platform.isAndroid ||
Platform.isIOS ||
isOhos;
}
### 7.3 Web stub
```dart
// lib/utils/app_platform_stub.dart
import 'package:flutter/foundation.dart';
```dart
abstract final class AppPlatform {
AppPlatform._();
static bool get isOhos => false;
static bool get isWeb => kIsWeb;
static String get operatingSystem => 'web';
static bool get supportsFirebase => true;
static bool get supportsLocalNotifications => false;
static bool get supportsInAppWebView => false;
}
### 7.4 能力矩阵怎么定(先定策略,再写代码)
| 能力 | 鸿蒙怎么处理 | 原因(常见) |
|------|--------------|--------------|
| Firebase | 不初始化 | 官方生态不覆盖 |
| 本地通知 | 业务层直接 return | 插件可能装了但行为不完整 |
| 内嵌 WebView | 可用,走 fork + 适配层 | API 可能滞后主线 |
| 推送 | 换华为推送等 | 不能照搬 FCM |
| 部分离线原生库(如自管 so) | 强制降级在线方案 | so / 引擎未适配 |
| 三方登录 | 评估账号体系;华为推荐 Account Kit | Google / QQ 等不一定可用 |
**初始化通知时写成:**
```dart
Future<void> initializeNotifications() async {
if (!AppPlatform.supportsLocalNotifications) {
debugPrint('skip local notifications on ${AppPlatform.operatingSystem}');
return;
}
// Android / iOS 初始化...
}
本步完成标准: 主工程能 import AppPlatform,启动路径上对不支持能力做了 early-return,避免一跑就崩。
第 8 步:第一次真正构建并装到真机
8.1 环境变量
export DEVECO_APP="/Applications/DevEco-Studio.app"
export DEVECO_SDK_HOME="$DEVECO_APP/Contents/sdk"
export OHOS_BASE_SDK_HOME="$HOME/Library/OpenHarmony/Sdk"
export OHOS_FLUTTER="$HOME/path/to/ohos-flutter/bin/flutter"
export PATH="$DEVECO_APP/Contents/tools/hvigor/bin:$DEVECO_APP/Contents/tools/ohpm/bin:$PATH"
cd your_flutter_app
$OHOS_FLUTTER pub get
8.2 构建 debug HAP
$OHOS_FLUTTER build hap --debug
成功后大致在:
build/ohos/hap/entry-default-signed.hap
8.3 安装并启动
hdc list targets
hdc -t <deviceId> install -r build/ohos/hap/entry-default-signed.hap
hdc -t <deviceId> shell aa start -a EntryAbility -b com.example.myapp
把 EntryAbility / com.example.myapp 换成你 module.json5 / app.json5 里的真实值。
8.4 这一步常见失败怎么拆
| 失败点 | 先查 |
|---|---|
| 找不到 SDK | 第 1、4 步路径 |
| 签名失败 | 第 5 步 Signing Configs / material |
| 插件 MissingPlugin / 原生编译失败 | 第 6 步 overrides |
Dart 分析 TargetPlatform.ohos | 第 6.4 节 vendor 补丁 |
| 装上了白屏 / 启动崩 | 第 7 步能力裁剪是否漏了 Firebase 等 |
本步完成标准: 真机能打开 App 主界面(功能可以不全,但能起来)。
第 9 步:业务适配教程(按优先级做)
主界面起来后,不要并行改十个模块。建议按这个顺序:
9.1 启动链路 / 崩溃点裁剪
9.2 本地存储
9.3 网络与账号登录
9.4 WebView / 文件路径
9.5 支付与深链
9.6 音视频 / TTS / 推送等垂类能力
9.1 启动链路:先让它不崩
排查 main.dart / 启动 Service:
Future<void> bootstrap() async {
if (AppPlatform.supportsFirebase) {
await initFirebase();
}
if (AppPlatform.supportsLocalNotifications) {
await initNotifications();
}
// 其它各平台都需要的初始化...
}
原则:凡是 Android 上默认会 init、但鸿蒙没有对等服务的 SDK,必须闸住。
9.2 本地存储:给 SP 一层兼容兜底
部分 ohos 实现写入成功后,返回值解析可能抛 RangeError,业务会误判失败。建议统一封装:
Future<bool> setOhosCompatible(
String key,
Future<bool> Function() action,
) async {
try {
return await action();
} catch (e) {
if (AppPlatform.isOhos && e is RangeError) {
debugPrint('OHOS preferences write quirk, treat as success: $key');
return true;
}
rethrow;
}
}
```dart
Future<bool> setString(String key, String value) {
return setOhosCompatible(key, () => prefs.setString(key, value));
}
**路径也不要照搬 Android:**
```dart
Future<Directory> getAppDirectory() async {
if (AppPlatform.isOhos) {
final dir = Directory(
'${Directory.systemTemp.path}${Platform.pathSeparator}my_app_cache',
);
if (!dir.existsSync()) {
await dir.create(recursive: true);
}
return dir;
}
if (Platform.isIOS) {
return getApplicationDocumentsDirectory();
}
return getApplicationSupportDirectory();
}
9.3 华为账号登录(推荐路径)
鸿蒙上 Google 登录通常不可用;华为侧推荐 Account Kit。典型分层:
- ArkTS 插件:调 Account Kit,走 MethodChannel 回传
authCode/idToken - Dart Service:调 Channel,做 state 校验
- 登录页:仅
AppPlatform.isOhos展示华为按钮 - 后端:用授权码 / ID Token 换会话
原生注册(极重要): 自研插件不会进 GeneratedPluginRegistrant,必须手动挂:
// entry/src/main/ets/entryability/EntryAbility.ets
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos'
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant'
import HuaweiLoginPlugin from '../plugins/HuaweiLoginPlugin'
```text
export default class EntryAbility extends FlutterAbility {
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
flutterEngine.getPlugins()?.add(new HuaweiLoginPlugin())
}
}
**Dart 侧 Channel 示意:**
```dart
class HuaweiLoginService {
static const _channel = MethodChannel('com.example.myapp/huawei_login');
```dart
Future<Map<String, String>?> auth() async {
final state = _randomState();
final raw = await _channel.invokeMethod<Map<dynamic, dynamic>>(
'authById',
{
'forceLogin': false,
'state': state,
'nonce': _randomState(),
'idTokenSignAlgorithm': 'PS256',
},
);
if (raw == null) return null;
if ((raw['errorCode'] as int? ?? -1) != 0) return null;
if (raw['state'] != null && raw['state'] != state) return null;
return {
'authorizationCode': '${raw['authCode'] ?? ''}',
'idToken': '${raw['idToken'] ?? ''}',
'openId': '${raw['openID'] ?? ''}',
'unionId': '${raw['unionID'] ?? ''}',
};
}
}
**UI:**
```dart
if (AppPlatform.isOhos)
HuaweiLoginButton(onTap: controller.loginWithHuawei),
还有一个上架级大坑: module.json5 里 Ability metadata 的 client_id,必须等于当前签名 Profile 的 appIdentifier。调试签和发布签不是同一个 ID。做法见第 10 步。
module.json5 示意:
"metadata": [
{ "name": "client_id", "value": "从当前 p7b Profile 读到的 appIdentifier" },
{ "name": "app_id", "value": "同上" }
]
9.4 WebView:用适配层挡住主线 API 差异
鸿蒙 fork 的 webview_flutter 可能没有 pub.dev 最新 API(例如某些 loadFileWithParams)。业务侧统一封装:
class LocalHtmlLoader {
static Future<void> loadFile({
required WebViewController controller,
required Uri fileUri,
}) async {
if (fileUri.scheme != 'file') {
await controller.loadRequest(fileUri);
return;
}
// 各平台走各自实现;ohos 兜底 loadFile
await controller.loadFile(fileUri.toFilePath());
}
}
9.5 支付与深链
- 在
module.json5配好querySchemes、Abilityskills/ uri(微信、支付宝等按你接的 SDK 来) - 某支付 SDK 若 ArkTS 路由缺页,可能需要补 stub 才能先编过
- 产品上可以先只开已验证闭环的支付(例如先微信),另一条等 SDK 完整再开
9.6 音视频 / TTS / 其它原生库
策略模板:
Future<void> speak(String text) async {
if (AppPlatform.isOhos) {
// 不要加载未适配的离线 so
return speakWithCloudTts(text);
}
return speakWithOfflineEngine(text);
}
设置页直接隐藏不可用引擎,避免用户点了崩溃。
本步完成标准: 登录、基础读写、关键业务页在真机可走通;不支持的能力有明确降级,而不是静默失败。
第 10 步:发布签名与上架 .app
10.1 HAP 和 APP 分别干什么
| 产物 | 命令 | 用途 |
|---|---|---|
.hap | flutter build hap --release | 真机安装、内测 |
.app | flutter build app --release | 应用市场上架 |
很多人用 release HAP 去交商店——不对。商店要 APP 包。
10.2 申请并配置发布证书
- 在 AppGallery Connect 创建应用,包名与
bundleName一致 - 申请 发布 证书与 Profile(注意类型是 release / app_gallery)
- 在 DevEco Signing Configs 配一套
release(或你自定义名如agcRelease) build-profile.json5的 product.signingConfig改成这套
建议至少准备两套配置:
| 名称 | 何时用 |
|---|---|
| debug 签 | 日常真机 |
| release 签 | 打上架包 |
10.3 切到发布签后,立刻同步华为登录 clientId
切换签名后:
- 从当前 Profile(
.p7b)读出appIdentifier - 写回
module.json5的client_id/app_id - 如有资源字符串
huawei_client_id,一并改 - 后端 OAuth 配置也改成 发布 这一套
否则会出现:调试包华为登录正常,市场上架包所有人登不上。
可以把「切签 + 同步 clientId」做成脚本,禁止手改。
10.4 打正式 APP
# 1)确认 signingConfig 已是 release
# 2)确认 client_id 已与 release Profile 对齐
# 3)确认 pubspec / AppScope / local.properties 版本一致
```text
$OHOS_FLUTTER build app --release \
--build-name=1.0.0 \
--build-number=100
**成功类似:**
```text
✓ Built build/ohos/app/ohos-default-signed.app
用商店后台上传该 .app。建议在本地再复制一份带版本号的归档,方便回滚对比。
10.5 上架前验收清单
- 版本号三处一致(pubspec / AppScope / 构建参数)
- 使用 release 签名打的
.app - 华为登录在 release 包上实测通过(debug 通过不算)
- 微信支付 / 深链跳回在 release 包验证
- 已降级能力符合产品预期(不是「忘了做」)
- 隐私合规、权限声明与应用市场资料一致
额外坑位速查(适配时对照)
A. 支付宝等商用 SDK 缺路由实现页
现象: ohpm 依赖装了,但 route 指向的 .ts / 页面不存在,ArkTS 编译失败。
思路: 构建前生成最小 stub 页面,让路由能解析;产品层可先隐藏未闭环支付。
B. 鸿蒙依赖「回流」弄坏 Android
例如接入某社交 SDK 后,Android Manifest Merger 因 usesCleartextTraffic 冲突失败。解法:
<application
android:usesCleartextTraffic="false"
tools:replace="android:usesCleartextTraffic">
教训: 为鸿蒙加的依赖也会影响其它平台,要做全矩阵回归。
C. 插件进了 Registrant,业务却不能当作可用
GeneratedPluginRegistrant 注册了通知插件 ≠ 鸿蒙通知已可用。以你在 Dart 写的 supports* 为准做产品承诺。
D. 长期双分支合并成本
如果主开发在 dev、鸿蒙在长期适配分支,记得:
- 定期合并主线,否则三个月后功能差一截
- 合并后重点回归:登录、支付、WebView、存储、插件注册代码是否被冲掉
推荐你照着执行的「最小成功路径」
把目标拆成三个里程碑,不要一天求全:
里程碑 A:环境通
- DevEco + SDK 目录约定完成
- OHOS Flutter 能
build hap ohos/工程能被 DevEco 打开- 调试签名可用
里程碑 B:包能装
- pubspec overrides 让工程编过
AppPlatform+ 启动裁剪,真机不秒崩build hap --debug安装启动成功
里程碑 C:能上架
- 关键业务在鸿蒙可闭环(至少登录 + 主功能)
- release 签名 + clientId 对齐
build app --release产出.app并过商店校验
结语
Flutter 适配 HarmonyOS,难点不在「多写几个 Widget」,而在于:
- 换工具链(Fork Flutter + DevEco + SDK 目录)
- 重建插件供应链(整链
dependency_overrides) - 重定义能力边界(什么支持、什么降级)
- 上架签名与账号体系对齐(尤其是华为登录 clientId)
按本文 **第 1 步 → 第 10 步** 顺序推进,每步都有「完成标准」,会少走很多回头路。
若卡在某一步:先确认是 **环境 / 签名 / 依赖 / 业务裁剪** 哪一类,再对症查,不要在错误层级上反复改业务代码。
祝你顺利打出第一份可上架的鸿蒙包。