鸿蒙 Stage 模型下的 Flutter 应用配置详解

📅 2026/7/8 14:29:07
鸿蒙 Stage 模型下的 Flutter 应用配置详解
Stage 模型是 HarmonyOS 新一代应用架构Flutter 鸿蒙应用也基于它构建。本文以 E-Brufen电子布洛芬——一个心理健康 Flutter 应用的真实配置为蓝本逐文件、逐字段解读 Stage 模型下的三层配置文件以及鸿蒙独有的资源引用系统。前置E-Brufen 项目概览在深入配置之前先了解这个 Flutter 项目的实际架构有助于理解为什么这样配置。lib/ ├── main.dart # 应用入口Hive CE 初始化 → MaterialApp ├── theme/app_theme.dart # Material 3 主题品牌色、卡片渐变、文字样式 ├── models/mood_entry.dart # 情绪数据模型MoodType 枚举 MoodEntry 类 ├── data/ │ ├── settings.dart # 用户设置持久化Hive CE Box │ └── mood_storage.dart # 情绪日记 CRUD纯 Dart无 SQLite 依赖 ├── widgets/ │ ├── home_card.dart # 首页模块入口卡片 │ ├── mood_picker.dart # 5 表情情绪选择器 │ ├── mood_chart.dart # 周情绪柱状图 │ └── breathing_circle.dart # 呼吸球动画组件 └── pages/ ├── home_page.dart # 首页问候语 三大模块 速记 ├── soundscape/soundscape_page.dart # 白噪音场景选择 定时器 ├── breathe/breathe_page.dart # 呼吸练习模式选择 计时 └── diary/diary_page.dart # 情绪日记记录 时间线 统计关键特征纯离线应用使用 Hive CE纯 Dart 键值存储替代 SQLite零原生插件依赖完美适配鸿蒙平台。这意味着requestPermissions可以为空数组——不需要网络权限、不需要存储权限、不需要麦克风权限。一、Stage 模型 vs FA 模型HarmonyOS 提供两种应用模型。理解它们的差异才能理解配置文件为什么这样设计。1.1 概念对比维度FA 模型 (Feature Ability)Stage 模型最小粒度PageAbility一个页面即为一个 AbilityUIAbility一个 Ability 可包含多个页面配置文件config.json单一文件JSON 格式app.json5module.json5分层配置JSON5 格式生命周期页面级生命周期组件级生命周期更精细多实例不支持支持同一 UIAbility 可启动多实例进程模型所有 Ability 运行在同一进程支持跨进程 Ability绑定调用无标准 Call 机制支持 Call 调用跨设备同步调用推荐度逐步淘汰API 9 起不推荐✅ 当前唯一推荐模型1.2 .json5 格式优势Stage 模型使用 JSON5 作为配置格式相比传统 JSON 多了三项实用特性{ // 支持单行注释——解释字段用途 bundleName: com.flutter.brufen, // 也支持行尾注释 /* 支持多行注释——大段说明 */ versionCode: 1000000, // 尾随逗号合法copy-paste 更友好 }这让配置文件天然具有自文档化能力。在团队协作中开发者可以直接在配置旁写说明不需要额外维护 README。1.3 Flutter 与 Stage 模型的关系Flutter 鸿蒙应用本质上是一个嵌入在 UIAbility 中的 Flutter Engine。Stage 模型配置决定了这个容器的行为app.json5定义应用的全局身份包名、版本、图标module.json5定义 Flutter 模块的能力入口 Ability、页面路由、设备类型build-profile.json5定义签名、SDK 版本、构建模式下面的章节逐一展开。二、app.json5应用全局配置app.json5位于ohos/AppScope/下是应用的身份证。E-Brufen 的实际配置如下// ohos/AppScope/app.json5 { app: { bundleName: com.flutter.brufen, // 应用包名全局唯一标识 vendor: example, // 开发者/厂商名称 versionCode: 1000000, // 版本号整数用于更新检测 versionName: 1.0.0, // 版本名展示给用户 icon: $media:1, // 应用图标资源引用 label: $string:app_name // 应用名称资源引用 } }2.1 bundleName应用的唯一身份证bundleName是鸿蒙应用在系统中的唯一标识类似于 Android 的applicationId或 iOS 的 Bundle Identifier。它在以下场景被使用签名 Profile绑定的 Profile 中的包名必须与此完全一致否则签名验证失败应用市场AppGallery 使用 bundleName 区分不同应用数据沙箱应用的数据目录路径由 bundleName 决定跨应用调用其他应用通过 bundleName 唤起你的应用E-Brufen 使用com.flutter.brufen——反向域名格式简洁明了。开发阶段可以自由定义但一旦发布上架bundleName 不可更改改包名等于一个新应用。2.2 vendor开发者标识vendor是开发者/厂商的标识字符串。E-Brufen 当前填写的是example。在正式发布时建议修改为你的开发者名称或公司名称这样在应用信息页面会展示该标识。2.3 versionCode 与 versionName版本双轨制鸿蒙沿用 Android 的版本双轨制字段类型用途用户可见versionCode整数系统判断版本新旧否versionName字符串展示给用户是versionCode必须严格递增。每次提交新版本到 AppGallery 时系统会比较 versionCode新值 旧值 → 允许上架新值 旧值 → 拒绝上架推荐使用语义化编码主版本 × 1,000,000 次版本 × 1,000 补丁版本。versionCode MAJOR * 1000000 MINOR * 1000 PATCH 1.0.0 → 1000000 1.0.1 → 1000001 1.1.0 → 1001000 2.0.0 → 2000000E-Brufen 的1000000即对应1.0.0。2.4 icon应用图标引用$media:1是资源引用语法详见第五章指向AppScope/resources/base/media/1.png。为什么叫1.png而不是app_icon.png这是因为 E-Brufen 使用了程序化图标生成方案——构建脚本动态生成图标文件命名为1.png可避免与app_icon.png的命名冲突。详见应用图标生成指南。2.5 label应用名称引用$string:app_name引用字符串资源。实际定义在ohos/AppScope/resources/base/element/string.json{string:[{name:app_name,value:E-Brufen}]}这样设计的好处是如果需要国际化只需在不同语言目录下创建对应的string.json如en_US/element/string.json配置本身无需修改。三、module.json5模块配置核心module.json5位于ohos/entry/src/main/下是 Stage 模型配置的核心文件。它定义了模块的 Ability、页面路由、设备类型、权限等。E-Brufen 的实际配置// ohos/entry/src/main/module.json5 { module: { name: entry, // 模块名 type: entry, // 模块类型 description: $string:module_desc, // 模块描述 mainElement: EntryAbility, // 主入口 Ability 名称 deviceTypes: [phone], // 目标设备类型 deliveryWithInstall: true, // 随应用安装 installationFree: false, // 不支持免安装 pages: $profile:main_pages, // 页面路由表 abilities: [{ /* ... */ }], // Ability 列表 requestPermissions: [] // 权限申请 } }下面逐字段深度解析。3.1 name 与 type模块身份name: entry—— 模块名称与build-profile.json5中 modules 的 name 对应type: entry—— 模块类型可选值entry主模块应用的主入口feature动态特性模块支持按需分发shared共享库模块Flutter 鸿蒙应用通常只有一个entry类型的模块。3.2 mainElement应用主入口mainElement: EntryAbility指定了应用的启动 Ability。它必须与abilities数组中某个 Ability 的name字段匹配。当用户点击桌面图标时系统会根据此字段找到对应的 Ability 并启动。3.3 deviceTypes目标设备类型deviceTypes: [phone]E-Brufen 目前仅声明phone支持。鸿蒙支持的设备类型包括值含义phone手机tablet平板tv智慧屏car车机wearable智能手表2in1二合一设备default通用不限制设备类型如果你的 Flutter 应用适配了多种屏幕尺寸可以声明多个类型[phone, tablet]。Flutter 开发者提示Flutter 本身是跨分辨率的只需在 Dart 层做好响应式布局就可以在module.json5中声明更多设备类型扩大应用分发范围。3.4 deliveryWithInstall 与 installationFree字段E-Brufen 值含义deliveryWithInstalltrueHAP 包随应用安装installationFreefalse不支持免安装原子化服务这是标准配置。如果你开发原子化服务类似微信小程序需要设置installationFree: true并配置相应的元服务信息。3.5 abilitiesUIAbility 配置重点abilities数组包含一个或多个 UIAbility 配置。E-Brufen 只有一个入口 Abilityabilities: [ { name: EntryAbility, // Ability 名称 srcEntry: ./ets/entryability/EntryAbility.ets, // ArkTS 源码入口 description: $string:EntryAbility_desc, // 能力描述 icon: $media:1, // Ability 图标 label: $string:EntryAbility_label, // Ability 标签 startWindowIcon: $media:icon, // 启动页图标 startWindowBackground: $color:start_window_background, // 启动页背景色 exported: true, // 允许外部调用 skills: [ { entities: [entity.system.home], actions: [action.system.home] } ] } ]3.5.1 name 与 srcEntryname: Ability 的逻辑名称供mainElement引用srcEntry: ArkTS 源码路径.ets文件这是鸿蒙原生的入口文件。在 Flutter 应用中这个文件通常会启动 Flutter Engine 并加载 Dart 代码3.5.2 icon 与 label这两个字段均为资源引用icon→$media:1→resources/base/media/1.pnglabel→$string:EntryAbility_label→resources/base/element/string.json中值为E-Brufen实际字符串资源定义// ohos/entry/src/main/resources/base/element/string.json{string:[{name:module_desc,value:电子布洛芬 - 你的随身心理舒缓助手},{name:EntryAbility_desc,value:白噪音、呼吸引导、情绪日记},{name:EntryAbility_label,value:E-Brufen}]}3.5.3 startWindowIcon 与 startWindowBackground冷启动体验这是 Stage 模型一个非常贴心的特性。当用户点击图标时系统在 Flutter Engine 初始化完成之前会先显示一个启动窗startWindowIcon: 启动窗中央的图标E-Brufen 引用$media:icon即resources/base/media/icon.pngstartWindowBackground: 启动窗的背景色E-Brufen 引用$color:start_window_background值为#FFFFFF纯白实际颜色资源定义// ohos/entry/src/main/resources/base/element/color.json{color:[{name:start_window_background,value:#FFFFFF}]}这样用户点击 E-Brufen 图标后会先看到白色背景上的应用图标约几百毫秒然后无缝过渡到 Flutter 渲染的页面。配置得当的启动窗可以消除白屏等待的糟糕体验。3.5.4 exported外部可见性exported: true表示该 Ability 可以被其他应用或系统组件调用。主 Ability 通常需要true否则桌面无法启动它。对于内部使用的 Ability建议设置为false以增强安全性。3.5.5 skills能力声明桌面图标的关键skills: [ { entities: [entity.system.home], actions: [action.system.home] } ]这个 skills 配置非常关键——它决定了你的应用是否出现在桌面。含义字段值含义entitiesentity.system.home声明该 Ability 属于桌面类别actionsaction.system.home声明该 Ability 响应回到桌面动作系统在构建桌面时会扫描所有声明了entity.system.homeaction.system.home的 Ability并将其图标展示在桌面上。如果省略这个 skills你的应用安装后不会出现桌面图标只能通过其他方式启动如 deeplink。常见的 FQ为什么同时需要 entities 和 actions因为鸿蒙的 Intent 匹配采用实体 动作双维度过滤两者都匹配才算命中。扩展知识skills 还可以声明自定义的 scheme 跳转。例如如果你的应用需要从浏览器通过ebrufen://open唤起就需要在 skills 中添加对应的 actions 和 uris 配置。3.6 pages页面路由表pages: $profile:main_pages$profile:main_pages引用resources/base/profile/main_pages.json// ohos/entry/src/main/resources/base/profile/main_pages.json{src:[pages/Index]}pages/Index对应entry/src/main/ets/pages/Index.ets文件。在 Flutter 鸿蒙应用中这个 Index 页面通常是一个简单的容器负责承载 Flutter Engine 渲染的内容。如果你的应用有多个 ArkTS 页面例如混合开发场景可以在这里列出所有 ArkTS 页面路径系统会据此生成路由表。3.7 requestPermissions权限申请requestPermissions: []空数组——这是 E-Brufen 的一个重要设计决策。它不申请任何系统权限不需要ohos.permission.INTERNET—— 纯离线应用无网络请求不需要ohos.permission.MICROPHONE—— 白噪音是纯视觉放松不录制音频不需要ohos.permission.WRITE_USER_STORAGE—— 数据存储使用 Hive CE应用沙箱内存储无需额外权限这个决策带来三个好处审核更快无敏感权限的应用在 AppGallery 审核流程中优先级更高用户信任安装时不会弹出权限提示用户更愿意尝试无运行时申请逻辑Flutter 中无需处理权限弹窗代码更简洁如果你开发的是需要联网的 Flutter 应用需要在requestPermissions中添加requestPermissions: [ { name: ohos.permission.INTERNET, reason: $string:internet_reason, usedScene: { abilities: [EntryAbility], when: always } } ]四、build-profile.json5构建配置两层build-profile.json5 在 E-Brufen 项目中出现在两个层级各有不同的职责。4.1 工程级ohos/build-profile.json5定义全局构建参数——签名、SDK 版本、构建模式、模块列表。// ohos/build-profile.json5工程级 { app: { // ── 签名配置 ── signingConfigs: [ { name: default, type: HarmonyOS, material: { storeFile: D:/Flutter/firstproject/firstproject.p12, // 密钥库文件 storePassword: 00000019..., // 密钥库密码 keyAlias: aaa, // 密钥别名 keyPassword: 00000019..., // 密钥密码 signAlg: SHA256withECDSA, // 签名算法 profile: D:/Flutter/firstproject/123456Release.p7b, // 签名 Profile certpath: D:/Flutter/firstproject/22.cer // 证书文件 } } ], // ── 产品配置SDK 版本 ── products: [ { name: default, signingConfig: default, // 引用上面的签名配置 compatibleSdkVersion: 6.1.0(23), // 最低兼容 SDK runtimeOS: HarmonyOS, targetSdkVersion: 6.1.0(23) // 目标 SDK } ], // ── 构建模式 ── buildModeSet: [ { name: debug }, { name: profile }, // 可调试的优化构建类似 Android 的 profile 模式 { name: release } ] }, // ── 模块列表 ── modules: [ { name: entry, srcPath: ./entry, targets: [ { name: default, applyToProducts: [default] } ] } ] }签名配置详解文件作用.p12密钥库文件包含私钥和证书链.cer数字证书公钥.p7bProfile 文件绑定证书、设备、应用包名和权限这三个文件构成了鸿蒙的签名三要素类似于 Android 的.jks.pepk体系。在团队协作中.p12 文件和密码不能提交到公开仓库。build-profile.json5中的密码是经过加密的00000019前缀不是明文。SDK 版本E-Brufen 目标 SDK 为6.1.0(23)对应 HarmonyOS 6.1.0API Level 23。compatibleSdkVersion表示最低兼容版本——低于此版本的设备无法安装。三种构建模式模式用途特点debug开发调试可断点、可热重载、未压缩profile性能分析可调试 优化编译release正式发布无调试信息、代码混淆、体积最小4.2 模块级ohos/entry/build-profile.json5定义单个模块的构建参数// ohos/entry/build-profile.json5模块级 { apiType: stageMode, // ★ 声明使用 Stage 模型 buildOption: {}, targets: [ { name: default, runtimeOS: HarmonyOS }, { name: ohosTest // 测试目标 } ] }apiType: stageMode是最关键的一行——没有它系统会按 FA 模型处理导致配置解析错误。targets定义了构建目标default是常规构建ohosTest为单元测试构建。4.3 两层配置的关系ohos/build-profile.json5 ← 工程级签名、SDK、模块声明 │ └── entry/build-profile.json5 ← 模块级apiType、targets工程级定义用什么签名打什么包模块级定义用什么模型构建模块。两者协同工作工程级声明了模块的存在modules[].name: entry模块级声明了模块的类型apiType: stageMode。五、资源引用系统$type:name鸿蒙的资源引用语法是$type:name这是配置文件中最重要的间接层。它让 UI 文本、图标、颜色与代码解耦支持国际化。5.1 引用语法全表语法资源类型实际路径E-Brufen 实例$string:name字符串resources/*/element/string.json$string:app_name→E-Brufen$media:name媒体图片resources/*/media/name.png$media:1→1.png应用图标$color:name颜色resources/*/element/color.json$color:start_window_background→#FFFFFF$profile:name配置文件resources/*/profile/name.json$profile:main_pages→main_pages.json$float:name浮点数resources/*/element/float.json未在 E-Brufen 中使用*代表资源限定符目录如base、zh_CN、en_US系统根据设备语言自动匹配。5.2 国际化的实际运作E-Brufen 的字符串资源分布在三个目录目录语言EntryAbility_label 值resources/base/element/string.json默认中文E-Brufenresources/zh_CN/element/string.json简体中文E-Brufenresources/en_US/element/string.json英文firstproject系统匹配优先级精确匹配 语言匹配 base 默认值。例如设备语言为zh_CN→ 直接读取zh_CN/目录设备语言为zh_TW→ 无精确匹配回退到zh匹配如果有否则回退到base/设备语言为ja_JP→ 无匹配回退到base/注意E-Brufen 的英文资源填写的是firstproject默认项目名正式发布前需要更新为正确的英文名。5.3 资源引用最佳实践永远使用$string不要硬编码文本。即使是单语言应用集中管理字符串也便于后期维护。图标使用编号而非描述性名称。E-Brufen 使用1.png而非app_icon.png——这在程序化生成图标的场景下尤为实用构建脚本不需要关心语义命名。颜色资源集中管理。启动背景色放在color.json而非硬编码方便统一调整。六、配置文件全景图综合以上所有内容E-Brufen 的完整配置结构如下ohos/ ├── AppScope/ │ ├── app.json5 ← 应用级包名、版本、图标、名称 │ └── resources/base/ │ ├── element/string.json ← app_name: E-Brufen │ └── media/1.png ← 应用图标程序化生成 │ ├── entry/ │ ├── build-profile.json5 ← 模块构建apiType、stageMode │ └── src/main/ │ ├── module.json5 ← 模块级Ability、页面、权限、设备类型 │ ├── ets/ │ │ ├── entryability/EntryAbility.ets ← ArkTS 入口启动 Flutter Engine │ │ └── pages/Index.ets ← 页面容器承载 Flutter 渲染 │ └── resources/ │ ├── base/ │ │ ├── element/ │ │ │ ├── string.json ← 默认字符串 │ │ │ └── color.json ← 颜色资源 │ │ ├── media/ │ │ │ ├── icon.png ← 启动窗图标 │ │ │ └── 1.png ← Ability 图标 │ │ └── profile/ │ │ └── main_pages.json ← 页面路由表 │ ├── zh_CN/element/string.json ← 简体中文 │ └── en_US/element/string.json ← 英文 │ └── build-profile.json5 ← 工程级签名、SDK、构建模式、模块列表配置决策回溯回顾 E-Brufen 的每一个配置决策及其理由配置项决策理由apiTypestageMode唯一推荐的模型FA 已逐步淘汰deviceTypes[phone]首版仅适配手机后续可扩展requestPermissions[]纯离线应用Hive CE 本地存储无需任何系统权限exportedtrue主 Ability 必须导出否则桌面无图标skillsentity.system.home声明出现在桌面的能力icon/startWindowIcon$media:1/$media:icon程序化生成的应用图标 vs 静态启动窗图标分开管理buildModeSetdebug profile release覆盖开发、性能分析、发布全流程七、Flutter 开发者的配置速查如果你是 Flutter 开发者初次接触鸿蒙配置以下是最小改动指南7.1 必须修改的字段文件字段修改内容app.json5bundleName改为你自己的包名app.json5vendor改为你的开发者名称build-profile.json5signingConfigs.material.*替换为你的签名文件路径AppScope/resources/base/element/string.jsonapp_name你的应用名entry/src/main/resources/base/element/string.json所有value更新为你的应用描述7.2 Flutter 特有的注意事项不需要修改srcEntryFlutter 应用的 ArkTS 入口文件由 Flutter SDK 生成通常不需要手动修改除非你需要自定义 Flutter Engine 启动参数。$profile:main_pages保留默认Flutter 应用通常只有一个pages/Index由 Flutter 路由接管页面切换。注意versionCode递增每次发布到 AppGallery 前务必递增versionCode。签名证书管理.p12、.cer、.p7b不要提交到 Git。建议放在独立的安全目录或使用环境变量。离线优先如果你的 Flutter 应用也是离线应用如 E-Brufen可以清空requestPermissions以简化审核。小结Stage 模型的三层配置文件职责分明工程级 build-profile.json5→ 签名 SDK 版本 构建模式应用级 app.json5→ 包名 版本 图标模块级 module.json5→ Ability 页面 权限 设备类型对于 Flutter 鸿蒙开发者理解这三层结构和资源引用系统$string、$media、$color、$profile后就能灵活配置应用。E-Brufen 的配置体现了离线优先的设计理念——零权限申请、纯 Dart 存储、简洁的模块结构——这既简化了开发也提升了审核通过率和用户信任度。