很多鸿蒙应用在调试阶段都会遇到这样的现象:代码逻辑没有报错,模拟器里也能跑,但换成真机后不是安装失败,就是点图标没反应,或者权限弹窗完全不出现。排查到最后,问题往往不在 ArkTS 或 Java 代码里,而是配置文件中的某个元素写漏、写错或放错了层级。HarmonyOS 的配置文件承担元数据职责,它向编译工具链和应用市场描述这个包是谁、能跑在哪些设备、入口在哪里、需要哪些权限。理解这些元素,比单纯拷贝模板更能减少无效构建。

一、配置文件不是普通 JSON,而是编译期的能力声明
鸿蒙应用工程中的配置文件主要有两种形态。早期 FA 模型使用 config.json,工程根目录和每个 HAP 包内都有对应文件;现在主推的 Stage 模型使用 module.json5,通常位于模块源码的 main 目录下。虽然两者都长得像 JSON,但含义并不完全相同。config.json 采用严格 JSON,不允许注释和尾逗号;module.json5 基于 JSON5 语法,允许写注释和尾逗号,这让多模块工程的可维护性更好。
从结构上看,FA 模型把应用级信息和模块级信息拆成 app、deviceConfig、module 三块;Stage 模型更扁平,模块内直接声明 name、type、deviceTypes、abilities、requestPermissions 等元素。无论哪种模型,配置文件都不是运行时才动态解析的普通文本,而是参与编译、签名、打包、上架校验的关键输入。比如 bundleName 写错,签名和包名对不上,安装阶段就会直接拒绝。
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": ["phone", "tablet"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["action.system.home"]
}
]
}
]
}
}
上面这段 module.json5 虽然简单,但已经包含了入口模块常见元素。name 是模块名,type 为 entry 表示该模块可作为主入口,mainElement 指向 abilities 数组中的 EntryAbility。pages 使用资源引用方式指向一个页面列表文件,而不是把所有页面路径写死在这里。requestPermissions 没有出现,说明该模块没有声明敏感权限。这样拆解后,每个字段都能对应到一个明确的编译或运行行为。
二、核心元素按功能分组理解更直观
配置文件里的元素数量不少,但可以按功能分成身份标识、入口能力、设备形态、权限与元数据四组。身份标识主要由 bundleName、versionCode、versionName 以及应用图标、标签等组成。它们决定包的唯一性和版本升级关系。bundleName 必须使用反向域名格式,一经发布不建议修改,否则会被系统视为不同应用。
入口能力集中在 module 对象下的 type、mainElement、abilities、pages 和 skills。type 决定模块是 entry、feature 还是 har。entry 是可安装入口,feature 是随 entry 一起打包的动态模块,har 是静态共享包。mainElement 必须与某个 ability 的 name 完全一致,否则系统找不到首页。abilities 数组中的每个对象描述一个 UIAbility 或 ServiceExtensionAbility 等,其中 srcEntry 指定实现源码路径,skills 声明系统如何通过 action 和 entity 拉起它。
设备形态由 deviceTypes 控制。这个数组声明当前模块可以在哪些设备上安装运行,例如 phone、tablet、tv、wearable、2in1。漏填某个目标设备,不一定在所有环境立即报错,但真机安装或应用市场上架时会被过滤。权限与元数据则对应 requestPermissions 和 metadata。前者声明敏感权限;后者以键值对形式给系统组件、卡片、第三方 SDK 提供扩展配置。
这里特别要区分 requestPermissions 和运行时动态申请。配置文件中声明只是告诉系统这个应用可能需要某权限,部分权限还需要在代码里通过 abilityAccessCtrl 接口向用户弹窗请求。如果只在代码里申请、没有在配置中声明,系统会直接拒绝;反过来只声明不动态申请,敏感权限同样不会生效。
{
"module": {
"name": "entry",
"type": "entry",
"mainElement": "MainAbility",
"deviceTypes": ["phone", "tablet"],
"requestPermissions": [
{
"name": "ohos.permission.CAMERA",
"reason": "$string:camera_permission_reason",
"usedScene": {
"abilities": ["MainAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.INTERNET"
}
]
}
}
上面示例中的 CAMERA 权限带上了 reason 和 usedScene,这是因为相机属于用户敏感资源,系统需要知道申请理由和使用场景,以便在权限弹窗中给出说明。INTERNET 属于普通权限,通常只需要 name 即可。usedScene 的 when 可以选 inuse 或 always,部分后台定位类权限必须使用 always,并且上架审核也有对应要求。
三、常见配置误区与排查顺序
第一个高频误区是把 type 写成 module。有些开发者看到模板里的 module 名称,误以为 type 的值也应该是 module。实际上 module.json5 的顶层对象名是 module,type 字段必须写 entry、feature 或 har。写成 module 会导致打包工具无法识别模块类型,构建直接失败。类似错误还有把 mainElement 写成页面路径,而不是 ability 的 name。页面路径属于 pages 资源,mainElement 只关心入口 ability。
第二个误区是 deviceTypes 与真机不匹配。开发时如果只在平板模拟器上调试,可能顺手只留下 tablet,结果手机安装时提示包与设备不兼容。排查这种问题不用怀疑代码,先看设备类型是否覆盖目标设备。同时要注意,多模块工程中每个模块的 deviceTypes 都要单独检查,feature 模块的设备类型如果与 entry 不一致,也可能导致某些设备无法获得完整功能。
第三个误区是权限 name 拼写不完整。权限名必须使用系统规定的完整字符串,例如 ohos.permission.CAMERA,不能简写成 CAMERA。部分静态检查可能不报错,但运行时会按无权限处理。遇到权限不生效,建议先把配置文件里的权限名复制到官方权限列表里比对,再检查代码中是否同步调用了动态申请接口。
第四个容易忽视的点是修改配置文件后没有清理构建缓存。配置文件虽然参与编译,但增量构建有时不会重新生成全部元数据。遇到改了 mainElement 或删了权限后真机行为没变化,可以尝试在 DevEco Studio 中执行 Clean Project 再重新构建。若仍然异常,再检查 build-profile.json5 中的 signingConfigs 是否引用了正确的模块名,因为签名信息同样会影响安装。
整体来看,配置文件的每一个元素都不是孤立存在。type、mainElement、abilities、skills 形成入口链路;deviceTypes 和 deliveryWithInstall、installationFree 共同决定分发方式;requestPermissions 和代码申请构成权限闭环。遇到配置相关报错,可以按包名、入口、设备、权限四个维度逐项核对,比盲目搜索报错信息更有效率。
鸿蒙OS配置文件元素module.json5修改时间:2026-09-27 21:34:40