Complete Guide: Porting Flutter Apps to HarmonyOS — From Zero to AppGallery
> For engineers who already ship Flutter apps on Android / iOS.
> After this guide you should be able to: set up the HarmonyOS toolchain → produce your first HAP from an existing project → handle plugin and feature compatibility → build a store-ready `.app`.
This is not another Hello World. It is a practical path based on shipping a real app. Sample package name is com.example.myapp — replace it with yours.
Also available: Chinese · Russian
What you will learn
- Why stock Flutter is not enough, and which toolchain you must use
- Step by step what to install, change, and run
- How to wire plugins so the project actually compiles (the longest pain point)
- How to trim features: login, storage, WebView, notifications, push, etc.
- How debug HAP differs from store APP packages
- How signing + Huawei Account clientId alignment prevents a launch-day outage
Build the right mental model first (read before coding)
Moving an existing Flutter app to HarmonyOS is not “add a flavor”. It is closer to “add an entire new platform toolchain”:
| Expectation | Reality |
|---|---|
flutter build apk is enough | Stock Flutter has no hap / HarmonyOS app commands |
| Android plugin implementations are enough | Most federated plugins have no OHOS impl — you need full-chain overrides |
A few Platform.isAndroid checks | You need a capability matrix: Firebase / notifications / some native libs must degrade |
| A release build can go to the store | Debug uses .hap; the store wants .app; signing and OAuth must match |
One-liner to remember:
OHOS Flutter fork + ohos native project + full-chain plugin overrides + Dart capability gating + release signing aligned with Huawei Account.
Follow the steps in order. Many people stall on day 3 because steps 1–2 were wrong and they already started rewriting business code.
Roadmap at a glance
Step 1 Install DevEco Studio and prepare the HarmonyOS SDK layout
Step 2 Install / configure the OpenHarmony Flutter fork
Step 3 Generate / verify the ohos project for your app
Step 4 Write local.properties (SDK + Flutter paths)
Step 5 Configure debug signing so SignHap works
Step 6 Update pubspec: *_ohos packages + dependency_overrides
Step 7 Add AppPlatform abstraction; keep analysis green
Step 8 First flutter build hap --debug; install on device
Step 9 Adapt features (login / storage / WebView / TTS / payments…)
Step 10 Release signing + flutter build app --release for AppGallery
Step 1: Install DevEco and prepare the SDK directory
1.1 What to install
- Install DevEco Studio from Huawei’s developer site (common macOS path:
/Applications/DevEco-Studio.app) - Open DevEco and download the HarmonyOS SDK via the wizard (many projects use API 24 / HarmonyOS 6.1.1-class versions — use what DevEco offers you)
- Confirm CLI tools work:
# hdc: HarmonyOS device tool, usually under DevEco sdk/.../toolchains
hdc list targets
Seeing a connected device — or an empty list while the command runs — means the toolchain is basically present.
1.2 Pitfall: SDK folder name must match hvigor conventions
hvigor 6.x often expects something like:
~/Library/OpenHarmony/Sdk/HarmonyOS-6.1.1/
├── openharmony/
│ ├── ets
│ ├── native
│ ├── toolchains
│ └── ...
└── hms/
├── ets
├── native
└── ...
Symptom: Build cannot find HarmonyOS-6.1.1 / API 24.
Cause: DevEco’s built-in path is often Contents/sdk/default/openharmony, which is not the same as the layout above.
Fix: Symlink (or copy) DevEco components into the expected tree:
#!/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}"
> On Windows, follow DevEco docs for the equivalent SDK. The point is that hvigor must resolve a complete SDK with both `openharmony/` and `hms/`.
**Done when:** `~/Library/OpenHarmony/Sdk/HarmonyOS-6.1.1` (or the folder name matching your `compileSdkVersion`) exists with the expected children.
---
## Step 2: Install the OpenHarmony Flutter fork
### 2.1 Why you must switch Flutter
**On stock Flutter:**
```bash
flutter build -h
You usually see apk / appbundle / ios / web… — no hap, and no HarmonyOS-oriented app.
A community OpenHarmony fork (commonly sources like openharmony-tpc/flutter_flutter — check current official docs) adds:
flutter build hap # debug / installable HAP
flutter build app # AppGallery .app package
Plus engine support for:
Platform.operatingSystem == 'ohos'TargetPlatform.ohos
2.2 How to install
Use FVM or a manual clone in a separate directory. Do not overwrite your day-to-day official Flutter for Android/iOS.
# Example: OHOS-specific Flutter via FVM (use the currently recommended version)
export OHOS_FLUTTER="$HOME/fvm/versions/openharmony_tpc/xxx/bin/flutter"
$OHOS_FLUTTER --version
$OHOS_FLUTTER build -h | grep -E 'hap|app'
Done when: $OHOS_FLUTTER build -h lists both hap and app.
2.3 Always use this Flutter for HarmonyOS commands
# ❌ don't
flutter pub get
flutter build hap
```text
# ✅ do
$OHOS_FLUTTER pub get
$OHOS_FLUTTER build hap --debug
In the IDE, configure a separate Flutter SDK for HarmonyOS builds so one-click runs do not pick the wrong engine.
---
## Step 3: Prepare the `ohos/` project for an existing app
### 3.1 Adding HarmonyOS to an existing Flutter app
**Typical layout:**
```text
your_flutter_app/
├── android/
├── ios/
├── lib/
├── pubspec.yaml
└── ohos/ # new: HarmonyOS Stage project
├── AppScope/
│ └── app.json5 # bundleName, versionCode, versionName
├── entry/ # main module (like android/app)
├── build-profile.json5 # signing, compileSdk, products
├── hvigorfile.ts
├── local.properties # local SDK / Flutter paths
└── oh-package.json5
Depending on your OHOS Flutter tooling:
cd your_flutter_app
$OHOS_FLUTTER create --platforms=ohos .
# or the “enable ohos on existing project” command from your fork’s docs
Then open the ohos/ folder in DevEco Studio (open the project — do not merely browse it as loose files).
3.2 Verify three critical pieces
① AppScope/app.json5
{
"app": {
"bundleName": "com.example.myapp",
"vendor": "example",
"versionCode": 100,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}
② product in build-profile.json5
{
"app": {
"products": [
{
"name": "default",
"compileSdkVersion": "6.1.1(24)",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.0.0(20)",
"runtimeOS": "HarmonyOS",
"signingConfig": "debug" // later: your debug / release config name
}
]
}
}
③ hvigorfile.ts must load the Flutter plugin
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))],
}
**Done when:** DevEco opens `ohos/` with a complete project tree (compiling is not required yet).
---
## Step 4: Configure `local.properties`
In `ohos/local.properties` (adjust paths):
```properties
hwsdk.dir=/Users/YOUR_NAME/Library/OpenHarmony/Sdk
sdk.dir=/Users/YOUR_NAME/Library/OpenHarmony/Sdk
flutter.sdk=/Users/YOUR_NAME/path/to/openharmony_tpc/flutter
flutter.versionName=1.0.0
flutter.versionCode=100
Notes:
flutter.sdkpoints to the root of the OHOS fork from Step 2 (parent ofbin/flutter)- Keep
versionName/versionCodein sync acrosspubspec.yaml(x.y.z+code),AppScope/app.json5, and this file
Done when: Paths exist and flutter.sdk/bin/flutter --version works.
Step 5: Configure debug signing (or you never get a signed package)
5.1 Auto debug signing in DevEco
- Open the
ohosproject in DevEco File→Project Structure→Signing Configs(menu names vary by version)- Enable automatic signing, sign in with a Huawei account, generate debug cert / profile
- Confirm
build-profile.json5has a debugsigningConfigsentry and the product points to it
5.2 Common pitfall: missing signing/material
Symptom: SignHap ENOENT for material.
Cause: DevEco stores encrypted material under the user home (e.g. ~/.ohos/config/material), while the project expects another path.
Fix: Copy/symlink material per DevEco docs, or re-select correct paths in Signing Configs.
5.3 Do not touch release signing yet
Use debug signing only. Goal:
$OHOS_FLUTTER build hap --debug
should produce a signed HAP. Release signing comes in Step 10.
Done when: DevEco or CLI can complete a signed build attempt (other compile errors are OK if signing itself works).
Step 6: Rewrite pubspec.yaml (longest, easiest to get wrong)
6.1 Understand the problem
HarmonyOS porting time is mostly spent on plugins:
- Many pub.dev plugins only implement android / ios / web
- Community hosts
*_ohosimplementations (e.g. on gitcode) - Only adding
foo_ohosto dependencies is often not enough — the resolver may still pick stockfoowithout OHOS code
Correct approach:
- Declare
*_ohoswhen needed - Use
dependency_overridesto pinfooandfoo_platform_interface(if any) to the ohos branch
6.2 Recommended template
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 # use current community 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
# Add as needed:
# audioplayers_ohos / open_file_ohos / file_picker_ohos / record ohos branch, etc.
dependency_overrides:
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
# Also override platform_interface packages together when they exist, e.g.:
# record + record_platform_interface
# share_plus + share_plus_platform_interface
# webview_flutter + webview_flutter_platform_interface
# audioplayers + audioplayers_platform_interface
**Always resolve with OHOS Flutter:**
```bash
$OHOS_FLUTTER pub get
6.3 How to decide which packages still need overrides
- List every native-backed plugin in your
pubspec.yaml - Search gitcode / openharmony-sig / openharmony-tpc / community repos for
*_ohosorbr_*_ohos - When
build hapfails with missing impl /MissingPluginException/ platform analyzer errors, add an override for that package - Keep main package and platform_interface on the same ref family
6.4 Special landmine: exhaustive switch on TargetPlatform breaks
The fork adds TargetPlatform.ohos. Third-party code like:
switch (Theme.of(context).platform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
// ...
case TargetPlatform.linux:
...
// no ohos → analyze / compile failure
}
Common victims include some video control packages (e.g. chewie).
Fix:
- Vendor the package under
third_party/xxx - Replace exhaustive
switchwithif+ default - Point
dependency_overridesto the local 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 / others → Material
return const MaterialControls();
}
Done when: $OHOS_FLUTTER pub get succeeds and analyzer no longer complains about non-exhaustive TargetPlatform.
Step 7: Add a platform abstraction — do not sprinkle if (ohos) everywhere
Create this early; all feature adaptation should go through it.
7.1 Conditional export (Web-safe)
// lib/utils/app_platform.dart
export 'app_platform_stub.dart'
if (dart.library.io) 'app_platform_io.dart';
7.2 IO implementation
// 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;
/// Adjust these flags for your product
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 Decide the capability matrix before coding
| Capability | HarmonyOS approach | Typical reason |
|------------|--------------------|----------------|
| Firebase | Do not initialize | Not covered by the official stack |
| Local notifications | Early-return in business code | Plugin may register but behave poorly |
| In-app WebView | OK via fork + adapter | APIs may lag pub.dev |
| Push | Use Huawei Push (or similar) | Do not assume FCM |
| Some offline native libs | Force online fallback | `.so` / engine not ported |
| Social login | Evaluate; Huawei recommends Account Kit | Google / others may be unavailable |
```dart
Future<void> initializeNotifications() async {
if (!AppPlatform.supportsLocalNotifications) {
debugPrint('skip local notifications on ${AppPlatform.operatingSystem}');
return;
}
// Android / iOS init...
}
Done when: The app imports AppPlatform and startup early-returns unsupported SDKs so it does not crash on launch.
Step 8: First real device build and install
8.1 Environment
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 Build a debug HAP
$OHOS_FLUTTER build hap --debug
Typical output:
build/ohos/hap/entry-default-signed.hap
8.3 Install and start
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
Replace EntryAbility / com.example.myapp with values from your module.json5 / app.json5.
8.4 Failure triage
| Failure | Check first |
|---|---|
| SDK not found | Steps 1 and 4 paths |
| Signing failure | Step 5 Signing Configs / material |
| MissingPlugin / native compile errors | Step 6 overrides |
Analyzer TargetPlatform.ohos | Step 6.4 vendor patch |
| White screen / crash on launch | Step 7 capability gating (Firebase etc.) |
Done when: The device opens your home screen (features may be incomplete, but it starts).
Step 9: Feature adaptation (priority order)
Do not rewrite ten modules in parallel. Suggested order:
9.1 Startup / crash gating
9.2 Local storage
9.3 Network + account login
9.4 WebView / file paths
9.5 Payments + deep links
9.6 A/V, TTS, push, and other verticals
9.1 Startup: stop the crash first
Future<void> bootstrap() async {
if (AppPlatform.supportsFirebase) {
await initFirebase();
}
if (AppPlatform.supportsLocalNotifications) {
await initNotifications();
}
// Shared init...
}
Rule: anything Android always inits but HarmonyOS has no equivalent must be gated.
9.2 Storage: wrap SharedPreferences quirks
Some OHOS implementations throw RangeError after a successful write. Shared wrapper:
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));
}
Do not blindly copy Android directories:
```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 Huawei Account login (recommended path)
Google Sign-In is usually unavailable. Prefer Account Kit:
- ArkTS plugin — call Account Kit; return
authCode/idTokenvia MethodChannel - Dart service — invoke channel; validate
state - UI — show Huawei button only when
AppPlatform.isOhos - Backend — exchange code / ID token for your session
Critical: custom plugins are not in GeneratedPluginRegistrant — register manually:
// 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 sketch:**
```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),
Store-level pitfall: Ability metadata client_id in module.json5 must equal the current signing profile’s appIdentifier. Debug and release IDs differ. See Step 10.
"metadata": [
{ "name": "client_id", "value": "appIdentifier from current p7b profile" },
{ "name": "app_id", "value": "same as above" }
]
9.4 WebView: adapter layer for API drift
OHOS fork of webview_flutter may lack newer pub.dev APIs (e.g. some loadFileWithParams). Centralize:
class LocalHtmlLoader {
static Future<void> loadFile({
required WebViewController controller,
required Uri fileUri,
}) async {
if (fileUri.scheme != 'file') {
await controller.loadRequest(fileUri);
return;
}
await controller.loadFile(fileUri.toFilePath());
}
}
9.5 Payments and deep links
- Configure
querySchemesand Abilityskills/ URIs inmodule.json5 - If a payment SDK ships routes without ArkTS pages, you may need a stub to compile
- Product-wise, ship only verified payment rails first; enable others later
9.6 A/V, TTS, other native libraries
Future<void> speak(String text) async {
if (AppPlatform.isOhos) {
// Do not load unported offline .so
return speakWithCloudTts(text);
}
return speakWithOfflineEngine(text);
}
Hide unavailable engines in settings so users cannot tap into a crash.
Done when: Login, basic persistence, and core screens work on device; unsupported features degrade explicitly.
Step 10: Release signing and store .app
10.1 HAP vs APP
| Artifact | Command | Use |
|---|---|---|
.hap | flutter build hap --release | Device install / beta |
.app | flutter build app --release | AppGallery submission |
Submitting a release HAP to the store is wrong — the store wants an APP package.
10.2 Obtain and configure release certificates
- Create the app in AppGallery Connect with the same
bundleName - Apply for release cert + profile (
release/app_gallery) - Configure a
release(or custom) profile in DevEco Signing Configs - Point product
signingConfiginbuild-profile.json5to it
Keep at least two configs:
| Name | When |
|---|---|
| Debug signing | Daily device builds |
| Release signing | Store packages |
10.3 After switching to release signing, sync Huawei clientId immediately
- Read
appIdentifierfrom the current.p7bprofile - Write it into
module.json5client_id/app_id - Update resource strings such as
huawei_client_idif present - Point backend OAuth to the release credentials
Otherwise: debug Huawei login works, every store user fails login.
Automate “switch signing + sync clientId”; forbid hand edits.
10.4 Build the release APP
# 1) signingConfig is release
# 2) client_id matches release profile
# 3) pubspec / AppScope / local.properties versions match
```text
$OHOS_FLUTTER build app --release \
--build-name=1.0.0 \
--build-number=100
**Success looks like:**
```text
✓ Built build/ohos/app/ohos-default-signed.app
Upload that .app. Keep a versioned local archive for rollback.
10.5 Pre-submit checklist
- Versions match in three places (pubspec / AppScope / build args)
- Artifact is a release-signed
.app - Huawei login verified on the release package (debug does not count)
- Payments / deep-link returns verified on release
- Degraded capabilities match product intent
- Privacy / permissions match store listing
Extra pitfalls cheatsheet
A. Commercial SDKs missing route page sources
**Symptom:** ohpm package installs, but routes point to missing `.ts` pages → ArkTS compile fails.
**Approach:** Generate a minimal stub page before build; hide unfinished payment options in product UI.
B. HarmonyOS deps “bleed” into Android
E.g. after adding a social SDK, Android Manifest Merger fails on usesCleartextTraffic:
<application
android:usesCleartextTraffic="false"
tools:replace="android:usesCleartextTraffic">
Lesson: OHOS-only dependency choices still affect other platforms — regress the whole matrix.
C. Registered plugin ≠ supported capability
A notifications plugin in GeneratedPluginRegistrant does not mean HarmonyOS notifications work. Product promises should follow your Dart supports* flags.
D. Long-lived dual-branch cost
If main development is on dev and HarmonyOS lives on a long branch:
- Merge often, or you will lag by months of features
- After merges, re-test login, payments, WebView, storage, and manual plugin registration
Minimum success path (three milestones)
Milestone A — Environment works
- DevEco + SDK layout ready
- OHOS Flutter can
build hap - DevEco opens
ohos/ - Debug signing works
Milestone B — Package installs
- pubspec overrides let the project compile
AppPlatform+ startup gating: no instant crashbuild hap --debuginstalls and launches
Milestone C — Store-ready
- Core flows work (at least login + main feature)
- Release signing + clientId aligned
build app --releaseproduces.appthat passes store validation
Closing
Porting Flutter to HarmonyOS is hard because of:
- Toolchain change (fork Flutter + DevEco + SDK layout)
- Plugin supply chain rebuild (full-chain
dependency_overrides) - Capability redraw (what to support vs degrade)
- Release signing aligned with account systems (especially Huawei
clientId)
Follow **Step 1 → Step 10**. Each step has a “done when” bar — use it.
If stuck, classify the failure as **environment / signing / dependencies / feature gating** before rewriting more business code.
Good luck shipping your first store-ready HarmonyOS build.