【OpenHarmony/HarmonyOs 】HarmonyOS NEXT 工程配置详解:app.json5、module.json5 与 main_pages.json

🧱 HarmonyOS 项目能否安装、启动和跳转,不只取决于 ArkTS 代码。应用级配置、模块级配置和页面清单共同描述了包名、设备类型、权限、Ability 与路由入口。

一、三份配置各管什么

AppScope/app.json5
  └─ 整个应用:包名、版本、图标、厂商

entry/src/main/module.json5
  └─ entry 模块:Ability、权限、设备、扩展能力

entry/src/main/resources/base/profile/main_pages.json
  └─ 当前模块可加载的 ArkUI 页面

应用可以包含多个模块,但包名和版本属于全局;页面与 Ability 则属于具体模块。先理解层级,再修改配置,能够避免字段放错位置。

系统从桌面图标进入 ArkUI 页面的完整链路可以概括为:

点击桌面图标
  → app.json5 确认应用身份、名称和图标
  → module.json5 根据 skills 找到 EntryAbility
  → srcEntry 加载 EntryAbility.ets
  → onWindowStageCreate() 调用 loadContent()
  → main_pages.json 验证目标页面已经注册
  → 构建 WelcomePage 或 HomePage

因此,“能安装但打开白屏”未必是 ArkUI 布局错误,也可能是 Ability 路径、页面清单、资源引用或 loadContent() 目标不一致。

二、应用级 app.json5

{
  "app": {
    "bundleName": "shan.lian.daohang",
    "vendor": "shan.lian.daohang",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:layered_image",
    "label": "$string:app_name"
  }
}

bundleName

它是应用的稳定身份,必须与 AGC/AppGallery Connect 中登记的包名一致。发布后随意更换会被视为另一个应用,也会影响签名、数据目录和云服务配置。

versionCode 与 versionName

versionName 面向用户,例如 1.0.0;versionCode 用于系统判断升级顺序,发布新版本时必须递增。不要只改显示版本而忘记内部版本号。

资源引用

$media:layered_image$string:app_name 引用资源,而不是硬编码路径。系统可根据设备、语言和主题选择合适资源。

常见资源引用包括:

$string:app_name                字符串
$color:start_window_background  颜色
$media:layered_image            图片或分层图标
$profile:main_pages             Profile 配置

建议把版本概念也分清:versionName 面向用户,versionCode 判断升级顺序,而本地数据的 schemaVersion 应独立维护。应用升级不一定修改数据格式,数据迁移也不能只靠显示版本判断。

三、模块类型与入口

{
  "module": {
    "name": "entry",
    "type": "entry",
    "mainElement": "EntryAbility",
    "pages": "$profile:main_pages"
  }
}

type: "entry" 表示这是应用入口模块,mainElement 指向主要 Ability。pages 通过资源引用连接页面清单,而不是直接在此写所有页面。

模块还配置了:

"deliveryWithInstall": true,
"installationFree": false

前者表示模块随安装交付,后者描述当前模块不是免安装形态。应用能够拉起元服务,不代表应用自身就是元服务,这两个概念不能混淆。未来若将 AI、工具箱拆成 feature 模块,还要重新规划模块依赖和按需交付。

四、声明支持的设备

"deviceTypes": [
  "phone",
  "tablet",
  "2in1"
]

声明支持并不代表 UI 已经完成适配。开发者仍要检查窗口断点、横竖屏、输入方式、信息密度和安全区。配置决定“允许运行”,布局决定“是否好用”。

设备 重点检查
手机 底部手势区、两列 Grid、单手操作
平板 三至四列布局、横屏、内容最大宽度
2in1 键鼠焦点、窗口缩放、悬停反馈

五、网络权限

"requestPermissions": [
  { "name": "ohos.permission.INTERNET" }
]

LinkOS 需要请求搜索建议和加载网页,因此必须声明网络权限。权限应遵循最小化原则:未使用的位置、相机、麦克风不要提前申请。涉及用户授权的权限还需要运行时请求和拒绝后的降级路径。

权限设计可以连续追问三个问题:是否真的需要、应在什么时机申请、用户拒绝后如何降级。例如模拟语音搜索不应提前申请麦克风;真实语音功能也应在用户点按麦克风时再申请,并在拒绝后保留文字搜索。

六、UIAbility 配置

"abilities": [
  {
    "name": "EntryAbility",
    "srcEntry": "./ets/entryability/EntryAbility.ets",
    "icon": "$media:layered_image",
    "label": "$string:EntryAbility_label",
    "startWindowIcon": "$media:startIcon",
    "startWindowBackground": "$color:start_window_background",
    "exported": true,
    "skills": [
      {
        "entities": ["entity.system.home"],
        "actions": ["ohos.want.action.home"]
      }
    ]
  }
]

srcEntry 必须与源码路径一致;启动窗口图标和背景决定 ArkUI 首帧构建前的过渡画面;skills 声明它可以作为桌面入口启动。

exported 会影响组件是否可被其他应用访问。能设为 false 的组件不要公开,公开组件要验证传入 Want,避免把外部参数当可信数据。

启动窗口会在 ArkUI 首帧完成前显示。为了减少视觉闪烁,startWindowBackground 应接近首屏背景,启动图标尺寸应稳定。Preferences 初始化属于首屏决策所需操作,可以在 Ability 中等待;天气、推荐和 AGC 非关键请求则应延后异步执行。

skills 不只是桌面声明。未来若增加 Deep Link、分享接收或文件打开,也需要对应 action/entity,并在 Ability 中校验 Want 参数的类型、长度和协议。外部入口越多,攻击面越大。

七、页面清单

{
  "src": [
    "pages/v2/WelcomePage",
    "pages/v2/HomePage",
    "pages/v2/MiniAppPage",
    "pages/v2/AIAssistantPage",
    "pages/v2/MinePage",
    "pages/v2/WebViewPage"
  ]
}

新增 .ets 页面后还要加入清单。常见问题包括路径大小写不一致、移动文件后未更新清单、路由使用旧目录、把不带 @Entry 的普通组件误当页面。

项目仍保留 v1 源码,但当前清单只登记 v2 生产页面。这可以避免旧页面继续进入正式路由。路由字符串还可以集中管理:

export class AppRoutes {
  static readonly WELCOME = 'pages/v2/WelcomePage';
  static readonly HOME = 'pages/v2/HomePage';
  static readonly WEB = 'pages/v2/WebViewPage';
}

常量减少业务代码中的拼写错误,但最终仍要与 main_pages.json 同步。

八、扩展能力

项目注册了备份扩展:

"extensionAbilities": [
  {
    "name": "EntryBackupAbility",
    "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
    "type": "backup",
    "exported": false,
    "metadata": [
      {
        "name": "ohos.extension.backup",
        "resource": "$profile:backup_config"
      }
    ]
  }
]

扩展能力由系统在特定场景调度,不等同于普通 UI 页面。exported: false 也符合内部系统能力的最小暴露原则。

当前备份 Ability 只记录回调日志,因此配置代表“已注册能力骨架”,不是“收藏已经完成备份”。真正落地还需要定义数据范围、快照版本、恢复校验和失败回滚。

九、构建配置之间的一致性

还要检查 build-profile.json5 中 targetSdkVersion、compatibleSdkVersion、产品和签名配置。SDK 版本、使用的 API 和设备系统不匹配时,可能出现编译成功但安装失败,或使用了目标版本不可用接口。

项目还启用了严格检查:

"strictMode": {
  "caseSensitiveCheck": true,
  "useNormalizedOHMUrl": true
}

大小写检查可以提前暴露路径问题,规范化 OHM URL 有助于统一模块导入。遇到错误时应修正真实路径,不应为了短期通过构建而关闭严格模式。

十、AGC、签名与环境一致性

接入 AGC 时,控制台应用、bundleName、签名材料与 agconnect-services.json 必须属于同一个项目。常见错误包括下载了另一个应用的配置、debug/release 签名不匹配、修改包名后没有重新配置云服务,以及把示例文件当成真实配置。

需要特别强调:agconnect-services.json 是客户端识别 AGC 项目的配置,不是保存第三方私密密钥的地方。DeepSeek 等服务密钥仍应只存在于云函数环境变量。

建议区分构建环境:

Debug:开发签名、测试服务地址、详细诊断日志
Release:正式签名、正式地址、受控日志、混淆

任何环境都不能把真实业务密钥硬编码进源码。

十一、四类常见故障

1. router 提示页面不存在

检查页面是否登记、路径是否误加 .ets、大小写是否一致,以及页面移动后是否仍使用旧路由。

2. 安装后无法从桌面启动

检查 mainElement、Ability 的 name/srcEntry、home skill 和签名,不要只检查页面 build 方法。

3. 网络接口全部失败

依次检查 INTERNET 权限、HTTPS 地址、设备网络、证书和服务域名。声明权限并不能解决证书或接口错误。

4. 模拟器正常,真机无法安装

重点检查签名、Profile、设备系统版本、SDK 兼容范围和 bundleName。

十二、排错顺序 ✅

  1. 确认 JSON5 语法和尾逗号;
  2. 检查资源名是否真实存在;
  3. 检查 Ability 名称与 srcEntry
  4. 检查页面是否登记;
  5. 检查 bundleName 与 AGC 配置;
  6. 检查 SDK、签名与设备版本;
  7. 清理构建缓存后重新同步;
  8. 查看 hilog 中的明确错误码。

十三、发布前检查表

  • bundleName 与 AGC 控制台完全一致;
  • versionCode 已递增,versionName 展示正确;
  • 图标、应用名和启动背景使用正式资源;
  • 删除未使用权限;
  • 所有生产页面已登记,v1 页面未暴露;
  • Ability 的 exported 符合最小权限;
  • SDK 与目标真机匹配;
  • release 签名和 Profile 正确;
  • AGC 文件属于正式项目且没有业务密钥;
  • release 包完成冷启动、路由、网络和备份回调验证。

十四、总结

app.json5 定义应用身份,module.json5 描述模块能力,main_pages.json 注册页面入口,构建配置再决定 SDK 与签名。把这几层关系理顺,权限、路由、Ability、备份和多设备支持才会形成完整工程,而不是一组互不理解的配置文件。✅

img

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐