Полное руководство: адаптация Flutter под HarmonyOS — от нуля до публикации в AppGallery
> Для инженеров, которые уже выпускают Flutter-приложения на Android / iOS.
> После прочтения вы сможете: поднять toolchain HarmonyOS → собрать первый HAP из существующего проекта → закрыть совместимость плагинов и фич → собрать `.app` для магазина.
Это не очередной Hello World, а практический путь по опыту реального релиза. Пример имени пакета — com.example.myapp; замените на своё.
Чему вы научитесь
- Почему обычного Flutter недостаточно и какую toolchain нужно использовать
- По шагам: что ставить, что менять, какие команды запускать
- Как настроить плагины, чтобы проект реально собрался (самый длинный «подводный камень»)
- Как урезать возможности: логин, хранилище, WebView, уведомления, push и т.д.
- Чем отличаются debug HAP и store APP
- Как выровнять подпись и clientId Huawei Account, чтобы не «лечь» сразу после релиза
Сначала правильная модель (прочитайте до кода)
Перенос Flutter-приложения на HarmonyOS — это не «добавить flavor». Это ближе к «добавить целую новую платформенную toolchain»:
| Ожидание | Реальность |
|---|---|
Достаточно flutter build apk | В обычном Flutter нет команд hap / HarmonyOS-app |
| Реализаций под Android хватит | У большинства federated-плагинов нет OHOS-реализации — нужен полный override цепочки |
Пара проверок Platform.isAndroid | Нужна матрица возможностей: Firebase / уведомления / часть нативных библиотек деградируют |
| Release-сборка = в магазин | Для отладки — .hap, для магазина — .app; подпись и OAuth должны совпадать |
Одной фразой:
Форк OHOS Flutter + нативный проект ohos + полный override плагинов + гейтинг возможностей в Dart + release-подпись, согласованная с Huawei Account.
Идите по порядку. Многие «залипают» на третий день, потому что шаги 1–2 сделаны неправильно, а бизнес-код уже переписывают.
Обзор маршрута
Шаг 1 Установить DevEco Studio и подготовить каталог SDK HarmonyOS
Шаг 2 Установить / настроить форк OpenHarmony Flutter
Шаг 3 Сгенерировать / проверить проект ohos
Шаг 4 Прописать local.properties (пути SDK и Flutter)
Шаг 5 Настроить debug-подпись, чтобы работал SignHap
Шаг 6 Переработать pubspec: пакеты *_ohos + dependency_overrides
Шаг 7 Добавить абстракцию AppPlatform; пройти анализ
Шаг 8 Первый flutter build hap --debug; установка на устройство
Шаг 9 Адаптировать фичи (логин / хранилище / WebView / TTS / оплата…)
Шаг 10 Release-подпись + flutter build app --release для AppGallery
Шаг 1. Установка DevEco и подготовка каталога SDK
1.1 Что поставить
- Установите DevEco Studio с сайта разработчика Huawei (на macOS часто:
/Applications/DevEco-Studio.app) - Откройте DevEco и скачайте HarmonyOS SDK по мастеру (часто API 24 / HarmonyOS 6.1.1 — ориентируйтесь на доступные версии)
- Проверьте CLI:
# hdc: утилита устройства HarmonyOS, обычно в sdk/.../toolchains DevEco
hdc list targets
Устройство в списке — или пустой список при работающей команде — значит toolchain в целом на месте.
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 часто Contents/sdk/default/openharmony — это не та схема выше.
Решение: сделать symlink (или копию) компонентов 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. Суть: hvigor должен видеть полный SDK с `openharmony/` и `hms/`.
**Критерий готовности:** существует `~/Library/OpenHarmony/Sdk/HarmonyOS-6.1.1` (или имя под ваш `compileSdkVersion`) с нужными подкаталогами.
---
## Шаг 2. Установка форка OpenHarmony Flutter
### 2.1 Почему нужно менять Flutter
**На обычном Flutter:**
```bash
flutter build -h
Обычно видны apk / appbundle / ios / web… — нет hap и HarmonyOS-app.
Сообщественный форк OpenHarmony (источники вроде openharmony-tpc/flutter_flutter — сверяйте актуальные docs) даёт:
flutter build hap # debug / устанавливаемый HAP
flutter build app # пакет .app для AppGallery
И поддержку в engine:
Platform.operatingSystem == 'ohos'TargetPlatform.ohos
2.2 Как установить
FVM или ручной clone в отдельный каталог. Не перезаписывайте обычный Flutter для Android/iOS.
# Пример: отдельный OHOS Flutter через FVM (версию берите из текущих рекомендаций)
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 Все команды HarmonyOS — только этим Flutter
# ❌ нельзя
flutter pub get
flutter build hap
```text
# ✅ нужно
$OHOS_FLUTTER pub get
$OHOS_FLUTTER build hap --debug
В IDE настройте отдельный Flutter SDK для сборок HarmonyOS, чтобы «одна кнопка» не брала неверный engine.
---
## Шаг 3. Подготовка проекта `ohos/` для существующего приложения
### 3.1 Как добавить HarmonyOS к существующему Flutter-проекту
**Типичная структура:**
```text
your_flutter_app/
├── android/
├── ios/
├── lib/
├── pubspec.yaml
└── ohos/ # новый Stage-проект HarmonyOS
├── AppScope/
│ └── app.json5 # bundleName, versionCode, versionName
├── entry/ # основной модуль (как android/app)
├── build-profile.json5 # подпись, compileSdk, products
├── hvigorfile.ts
├── local.properties # локальные пути SDK / Flutter
└── oh-package.json5
В зависимости от версии OHOS Flutter:
cd your_flutter_app
$OHOS_FLUTTER create --platforms=ohos .
# или команда «включить ohos в существующий проект» из docs вашего fork
Затем откройте каталог ohos/ в DevEco Studio (именно проект, а не просто просмотр файлов).
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"
}
}
② product в 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" // позже: имя debug / release-конфига
}
]
}
}
③ 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— корень OHOS-форка из шага 2 (родительbin/flutter)versionName/versionCodeсинхронизируйте сpubspec.yaml(x.y.z+code) иAppScope/app.json5
Критерий готовности: пути существуют, flutter.sdk/bin/flutter --version работает.
Шаг 5. Debug-подпись (иначе подписанного пакета не будет)
5.1 Автоподпись в DevEco
- Откройте проект
ohosв DevEco File→Project Structure→Signing Configs(названия меню зависят от версии)- Включите автоматическую подпись, войдите в аккаунт Huawei, сгенерируйте debug-сертификат / profile
- Убедитесь, что в
build-profile.json5есть debugsigningConfigs, а product указывает на него
5.2 Частая ловушка: нет signing/material
Симптом: SignHap с ENOENT по material.
Причина: DevEco кладёт зашифрованный material в домашний каталог (напр. ~/.ohos/config/material), а проект ждёт другой путь.
Решение: скопировать/сделать symlink по docs DevEco или заново выбрать пути в Signing Configs.
5.3 Release-подпись пока не трогайте
Только debug. Цель:
$OHOS_FLUTTER build hap --debug
должна дать подписанный HAP. Release — на шаге 10.
Критерий готовности: DevEco или CLI может пройти этап подписи (остальные ошибки компиляции допустимы).
Шаг 6. Переработка pubspec.yaml (самый длинный и коварный шаг)
6.1 В чём проблема
Больше всего времени на адаптацию уходит на плагины:
- На pub.dev многие плагины имеют только android / ios / web
- Сообщество публикует
*_ohos(например на gitcode) - Одного
foo_ohosв dependencies часто недостаточно — resolver всё равно может взять обычныйfooбез OHOS
Правильный подход:
- При необходимости объявить
*_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:
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 - Если
build hapпадает с missing impl /MissingPluginException/ ошибками анализатора — добавьте override - Основной пакет и platform_interface — из одной семьи ref
6.4 Особая мина: исчерпывающий switch по TargetPlatform
В форке появился TargetPlatform.ohos. Код вида:
switch (Theme.of(context).platform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
// ...
case TargetPlatform.linux:
...
// нет ohos → падает анализ / сборка
}
Частые жертвы — некоторые UI-библиотеки плеера (например chewie).
Исправление:
- Vendor пакета в
third_party/xxx - Заменить exhaustive
switchнаif+ default - Направить
dependency_overridesна 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 / прочее → Material
return const MaterialControls();
}
Критерий готовности: $OHOS_FLUTTER pub get успешен; анализатор больше не ругается на неполный TargetPlatform.
Шаг 7. Абстракция платформы — не размазывайте if (ohos) по всему коду
Сделайте сразу; вся дальнейшая адаптация — через неё.
7.1 Условный export (безопасно для 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 Сначала матрица возможностей, потом код
| Возможность | Подход на HarmonyOS | Типичная причина |
|-------------|---------------------|------------------|
| Firebase | Не инициализировать | Нет в официальном стеке |
| Локальные уведомления | Early-return в бизнес-коде | Плагин может быть, поведение — нет |
| In-app WebView | OK через fork + adapter | API может отставать от pub.dev |
| Push | Huawei Push и аналоги | Не рассчитывать на FCM |
| Часть offline-нативки | Принудительный online fallback | `.so` / engine не портированы |
| Соцлогин | Оценить; Huawei рекомендует Account Kit | Google и др. могут быть недоступны |
```dart
Future<void> initializeNotifications() async {
if (!AppPlatform.supportsLocalNotifications) {
debugPrint('skip local notifications on ${AppPlatform.operatingSystem}');
return;
}
// init Android / iOS...
}
Критерий готовности: приложение импортирует AppPlatform, на старте отсекает неподдерживаемые SDK и не падает сразу.
Шаг 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 |
Анализатор TargetPlatform.ohos | П. 6.4 vendor-патч |
| Белый экран / краш при старте | Шаг 7 гейтинг (Firebase и т.п.) |
Критерий готовности: на устройстве открывается домашний экран (фичи могут быть неполными, но приложение стартует).
Шаг 9. Адаптация бизнес-фич (по приоритету)
Не правьте десять модулей параллельно. Рекомендуемый порядок:
9.1 Старт / отсечение крашей
9.2 Локальное хранилище
9.3 Сеть и логин
9.4 WebView / пути к файлам
9.5 Оплата и deep links
9.6 A/V, TTS, push и прочие вертикали
9.1 Старт: сначала не падать
Future<void> bootstrap() async {
if (AppPlatform.supportsFirebase) {
await initFirebase();
}
if (AppPlatform.supportsLocalNotifications) {
await initNotifications();
}
// общая инициализация...
}
Правило: всё, что на Android всегда инициализируется, а на HarmonyOS нет аналога, должно быть перекрыто.
9.2 Хранилище: обёртка над SharedPreferences
Некоторые 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 Вход через Huawei Account (рекомендуемый путь)
Google Sign-In обычно недоступен. Предпочтительно Account Kit:
- ArkTS-плагин — Account Kit;
authCode/idTokenчерез MethodChannel - Dart-сервис — вызов channel и проверка
state - UI — кнопка Huawei только при
AppPlatform.isOhos - Бэкенд — обмен code / 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:**
```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),
Ловушка уровня магазина: client_id в metadata Ability (module.json5) должен равняться appIdentifier текущего signing profile. Debug и release — разные ID. См. шаг 10.
"metadata": [
{ "name": "client_id", "value": "appIdentifier из текущего p7b profile" },
{ "name": "app_id", "value": "то же значение" }
]
9.4 WebView: слой-адаптер против дрейфа API
OHOS-форк webview_flutter может не иметь новых API pub.dev (например некоторых loadFileWithParams). Централизуйте:
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 Оплата и deep links
- Настройте
querySchemesи Abilityskills/ URI вmodule.json5 - Если платёжный SDK отдаёт маршруты без ArkTS-страниц — может понадобиться stub для сборки
- Продуктово сначала включайте только проверенные способы оплаты
9.6 A/V, TTS и прочая нативка
Future<void> speak(String text) async {
if (AppPlatform.isOhos) {
// Не грузите непортированный offline .so
return speakWithCloudTts(text);
}
return speakWithOfflineEngine(text);
}
Скрывайте недоступные движки в настройках, чтобы пользователь не натыкался на краш.
Критерий готовности: логин, базовое сохранение данных и ключевые экраны работают на устройстве; неподдерживаемое явно деградирует.
Шаг 10. Release-подпись и .app для магазина
10.1 HAP vs APP
| Артефакт | Команда | Назначение |
|---|---|---|
.hap | flutter build hap --release | Установка / бета |
.app | flutter build app --release | Публикация в AppGallery |
Сдавать в магазин release HAP нельзя — нужен пакет APP.
10.2 Получение и настройка release-сертификатов
- Создайте приложение в AppGallery Connect с тем же
bundleName - Закажите release-сертификат и profile (
release/app_gallery) - Настройте
release(или своё имя) в Signing Configs DevEco - Укажите его в product.
signingConfigфайлаbuild-profile.json5
Минимум две конфигурации:
| Имя | Когда |
|---|---|
| Debug | Ежедневные сборки на устройство |
| Release | Пакеты для магазина |
10.3 После переключения на release сразу синхронизируйте Huawei clientId
- Прочитайте
appIdentifierиз текущего.p7b - Запишите в
module.json5поляclient_id/app_id - Обновите строки вроде
huawei_client_id, если есть - На бэкенде OAuth переведите на release-учётные данные
Иначе: на debug Huawei-логин работает, всем пользователям из магазина — нет.
Автоматизируйте «смена подписи + sync clientId»; ручные правки запретите.
10.4 Сборка release 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 - Huawei-логин проверен на release-пакете (debug не считается)
- Оплата / возврат по deep link проверены на release
- Деградации совпадают с продуктовым замыслом
- Политика конфиденциальности / разрешения совпадают с карточкой магазина
Дополнительные ловушки (шпаргалка)
A. Коммерческие SDK без исходников страниц маршрутов
**Симптом:** ohpm-зависимость есть, route указывает на отсутствующий `.ts` → падает ArkTS.
**Подход:** минимальный stub-страница перед сборкой; в UI скрывать неготовые способы оплаты.
B. Зависимости HarmonyOS «протекают» в Android
Например после соцSDK падает Manifest Merger из‑за usesCleartextTraffic:
<application
android:usesCleartextTraffic="false"
tools:replace="android:usesCleartextTraffic">
Вывод: выбор зависимостей «ради ohos» бьёт по другим платформам — регрессируйте всю матрицу.
C. Плагин в Registrant ≠ возможность поддерживается
Уведомления в GeneratedPluginRegistrant не означают, что на HarmonyOS они работают. Обещания продукта стройте по вашим Dart-флагам supports*.
D. Цена долгоживущей второй ветки
Если основная разработка в dev, а HarmonyOS — на отдельной ветке:
- Мержите часто, иначе отстанете на месяцы фич
- После merge заново проверьте логин, оплату, WebView, хранилище и ручную регистрацию плагинов
Минимальный путь успеха (три вехи)
Веха A — окружение живое
- DevEco + корректная раскладка SDK
- OHOS Flutter умеет
build hap - DevEco открывает
ohos/ - Debug-подпись работает
Веха B — пакет ставится
- Overrides в pubspec позволяют собрать проект
AppPlatform+ гейтинг старта: нет мгновенного крашаbuild hap --debugставится и запускается
Веха C — готово к магазину
- Ключевые сценарии работают (минимум логин + основная фича)
- Release-подпись + clientId выровнены
build app --releaseдаёт.app, проходящий проверки магазина
Заключение
Адаптация Flutter под HarmonyOS сложна из‑за:
- Смены toolchain (форк Flutter + DevEco + раскладка SDK)
- Пересборки цепочки плагинов (полные
dependency_overrides) - Переопределения границ возможностей (что поддерживать, что деградировать)
- Согласования release-подписи с аккаунт-системой (особенно Huawei
clientId)
Идите от шага 1 к шагу 10. У каждого шага есть критерий «готово» — используйте его. Если застряли: сначала классифицируйте проблему как окружение / подпись / зависимости / гейтинг фич, и только потом снова лезьте в бизнес-код.
Удачи с первым релизным пакетом HarmonyOS для магазина.