HarmonyOS 鸿蒙Next中多 HAP/HSP 模块间 Resources 资源覆盖与合并优先级:为什么 icon 被替换了?

HarmonyOS 鸿蒙Next中多 HAP/HSP 模块间 Resources 资源覆盖与合并优先级:为什么 icon 被替换了? 项目采用多模块架构(entry + 2 个 HAR + 1 个 HSP),在资源管理上遇到了以下问题:

  1. 图标被替换:entry 模块的 resources/base/media/app_icon.png 是 A 图标,但某个 HAR 模块也定义了同名的 app_icon.png,最终安装后应用图标变成了 HAR 里的版本
  2. 字符串取错值:多个模块都定义了 $string:app_name,有的模块显示的是 entry 的值,有的模块显示的是 HAR 的值,行为不一致
  3. HSP 资源不生效:HSP 模块中定义了 $color:primary_color,但在 entry 中引用时取到的是 entry 自己的值,HSP 的值被忽略了
  4. overlay 机制不清楚:听说有资源 overlay 机制可以覆盖系统资源,但文档描述模糊,不知道优先级如何

更多关于HarmonyOS 鸿蒙Next中多 HAP/HSP 模块间 Resources 资源覆盖与合并优先级:为什么 icon 被替换了?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

12 回复

尊敬的开发者,您好,

【背景知识】

资源访问优先级由资源加载机制和模块依赖关系共同决定。系统按照以下顺序查找同名资源(优先级从高到低):

  1. 当前模块资源:当前代码所在模块的资源目录(如 entry/src/main/resources/base)。
  2. 直接依赖模块:当前模块直接在 module.json5 中声明的依赖模块。
  3. 传递依赖模块:直接依赖模块的依赖(即间接依赖)。
  4. 公共模块(Common):通常作为基础库被所有模块依赖的公共资源。

例如在 dependencies 里面有多个依赖库:

{
  "dependencies": {
    "a": "file:../a",
    "b": "file:../b",
    "c": "file:../c"
  }
}

则优先级为当前模块entry -> a -> b -> c

【解决方案】

资源重名,会按照优先级进行覆盖,在编译构建HAP时,DevEco Studio会从HAP模块及依赖的模块中收集资源文件,如果不同模块下的资源文件出现重名冲突时,DevEco Studio会按照以下优先级进行覆盖(优先级由高到低):

  1. AppScope(仅API9的Stage模型支持)。
  2. HAP包自身模块。
  3. 依赖的HAR模块,如果依赖的多个HAR之间有资源冲突,会按照依赖顺序进行覆盖(依赖顺序在前的优先级较高)。 例如下方示例中dayjs和lottie中包含同名文件时,会优先使用dayjs中的资源。
// oh-package.json5
{
  "dependencies": {
    "dayjs": "^1.10.4",
    "lottie": "^2.0.0"
  }
}

另外如果在AppScope/HAP模块/HAR模块的国际化目录中配置了资源,在相同的国际化限定词下,合并的优先级也遵循上述规则。同时,国际化限定词中配置的优先级高于在base中的配置。如:在AppScope的base中配置了资源字段,在HAR模块的en_US中配置了同样的资源字段,则在en_US的使用场景中,会更优先使用HAR模块中配置的资源字段。关于HSP 资源不生效是因为构建时会将 HSP 的资源配置合并到 HAP 中,但运行时 HAP 无法直接访问 HSP 的资源文件,如果需要使用 HSP 资源可以参考:访问跨HAP/HSP包资源

因此,对于不同模板中资源名冲突这种情况,应当:

  • 避免命名冲突。

  • 公共资源使用唯一命名(如 common_icon.png)。

  • 模块特定资源使用模块前缀(如 a_icon.png)。

  • 将公共资源放在专门的 common 模块,避免在多个模块重复定义。

  • 使用 module.json5 的 exclude 字段排除不需要的资源。

    "resources": {
      "exclude": ["media/icon.png"]  // 排除特定资源
    }
    

参考文档:导出资源

更多关于HarmonyOS 鸿蒙Next中多 HAP/HSP 模块间 Resources 资源覆盖与合并优先级:为什么 icon 被替换了?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


一、问题现象

在多模块 HarmonyOS 工程中,如果 HAP、HAR、公共模块或依赖库中存在名称相同的资源文件,构建时可能会出现资源被覆盖的情况。最终生效的资源并不是随机决定的,而是由模块自身资源、依赖关系以及资源限定目录共同决定。


二、资源生效规则

构建 HAP 时,DevEco Studio 会收集当前模块及其依赖模块中的资源,并按照优先级进行合并。当多个位置存在同名资源时,优先级较高的资源会覆盖优先级较低的资源。

整体优先级通常可以理解为:

AppScope > HAP 当前模块 > 依赖的 HAR 模块

其中,AppScope 资源仅在 API 9 Stage 模型下支持。

对于多个 HAR 依赖之间的资源冲突,则会根据依赖声明顺序判断优先级。声明越靠前,优先级越高。

例如:

{
  "dependencies": {
    "dayjs": "^1.10.4",
    "lottie": "^2.0.0"
  }
}

如果 dayjslottie 中存在同名资源,则会优先使用 dayjs 中的资源。

同理,如果依赖关系如下:

{
  "dependencies": {
    "a": "file:../a",
    "b": "file:../b",
    "c": "file:../c"
  }
}

资源优先级可以理解为:

entry 模块 > a > b > c

三、国际化资源的优先级

如果资源配置在国际化目录中,还需要结合限定词进行判断。在相同限定词场景下,资源仍然按照模块优先级进行合并。

但需要注意的是,限定词目录中的资源优先级高于 base 目录中的资源。

例如,AppScope/base 中配置了某个资源字段,而某个 HAR 模块的 en_US 目录中配置了同名字段,那么在 en_US 环境下,会优先使用 HAR 模块 en_US 目录中的资源。


四、HSP 资源访问说明

HSP 的资源在构建阶段会参与合并,但运行时 HAP 不能直接访问 HSP 内部的资源文件。因此,如果业务中需要使用 HSP 中的资源,应按照跨 HAP/HSP 包资源访问方式进行处理,而不能直接按普通 HAP 或 HAR 资源的访问方式使用。


五、推荐处理方式

为了避免不同模板或模块之间出现资源冲突,建议从命名和资源归属两方面进行规范:

  1. 避免多个模块使用完全相同的资源名称。

  2. 公共资源统一添加公共前缀,例如:

common_icon.png
common_bg_login.png
  1. 模块私有资源添加模块标识,例如:
user_icon.png
order_empty.png
a_icon.png
  1. 将通用资源集中放入独立的 common 模块,避免多个模块重复维护同一份资源。

  2. 对于不需要参与打包的资源,可以在 module.json5 中通过 exclude 排除:

"resources": {
  "exclude": ["media/icon.png"]
}

六、总结

资源重名时,最终生效结果主要取决于模块优先级、依赖声明顺序以及资源限定词目录。为了减少构建期覆盖带来的不确定性,建议在项目初期就制定统一的资源命名规范,并将公共资源集中管理。

学习了

资源匹配

应用使用某资源时,系统会根据当前设备状态优先从相匹配的限定词目录中寻找该资源。只有当resources目录中没有与设备状态匹配的限定词目录,或者在限定词目录中找不到该资源时,才会去base目录中查找。rawfile是原始文件目录,不会根据设备状态去匹配不同的资源。

限定词目录与设备状态的匹配规则

  • 在为设备匹配对应的资源文件时,限定词目录匹配的优先级从高到低依次为:移动国家码和移动网络码 > 区域(可选组合:语言、语言_文字、语言_国家或地区、语言_文字_国家或地区)> 横竖屏 > 设备类型 > 颜色模式 > 屏幕密度。
  • 如果限定词目录中包含移动国家码和移动网络码、语言、文字、横竖屏、设备类型、颜色模式限定词,则对应限定词的取值必须与当前的设备状态完全一致,该目录才能够参与设备的资源匹配。例如,限定词目录“zh_CN-car-ldpi”不能参与“en_US”设备的资源匹配。
  • 如果存在多个屏幕密度限定词目录,则优先向上匹配最接近的屏幕密度限定词目录,否则向下匹配最为接近的屏幕密度限定词目录。例如,假设存在限定词目录“xldpi”和“xxldpi”,设备屏幕密度为“xxldpi”,则会匹配“xxldpi”限定词目录。

应用界面加载资源规则,更多请参考国际化和本地化文档。

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/resource-categories-and-access-V5

多模块工程里,资源名冲突最好当成设计问题处理,不要依赖构建合并时的偶然优先级。尤其是 app_icon、app_name、primary_color 这种通用名称,在 entry、HAR、HSP 中重复很容易出现你看到的覆盖和取值不一致。

建议规范如下:

  1. entry 只放应用级资源,比如图标、应用名、全局主题 token。
  2. HAR/HSP 资源加模块前缀,例如 order_icon_xxx、pay_color_primary,避免和 entry 同名。
  3. 公共组件不要引用 app_name、app_icon 这类应用级资源,改成由宿主传入。
  4. HSP 的资源尽量在 HSP 自己的组件内部消费,跨模块引用时要明确模块边界和依赖关系。
  5. overlay 机制不要用来解决业务模块资源冲突,它更偏资源替换/定制场景。

简单说,模块化项目要靠命名空间和资源职责划分来避免覆盖,而不是靠同名资源比较优先级。

学习了

他这个取值定义就是要求不要同名,

这类问题建议先把“资源归属”和“资源名称”拆开看:

  1. $r(‘app.xxx.name’) 最终对应的是一个 Resource 描述对象,里面包含 bundleName、moduleName 和资源 id。跨 entry/HAR/HSP 复用同一个资源名不是稳定契约;不同模块代码里生成的 Resource 归属可能不同,运行时再按资源对象或资源名取值,就容易出现“同名但来源不一致”的现象。

  2. HAR 会随依赖方一起参与编译/打包,公共库里不要放 app_icon、app_name、primary_color 这类通用名,尤其不要和 entry 同名。建议给每个库资源加模块前缀,例如 lib_user_app_name、hsp_player_primary_color。

  3. 应用图标、应用名称这类入口级元信息只在 entry 的配置和 entry 资源里维护。库模块如果需要默认图标或文案,应使用库私有资源名,再由 entry 显式决定是否引用。

  4. HSP 是独立共享包,entry 中写 $r(‘app.color.primary_color’) 不应期待自动解析到 HSP 的同名资源。HSP 组件内部使用自己的资源;如果 entry 需要使用 HSP 资源,建议由 HSP 导出 Resource 常量或接口,调用方直接传 Resource,避免靠同名覆盖。

  5. overlay 不是普通业务模块之间的资源覆盖机制。公开能力是对声明为 overlay module 的模块进行启停和查询;普通 HAR/HSP 的资源冲突不建议用 overlay 解决。

排查建议:全仓搜索 app_icon、app_name、primary_color 等同名资源,先把公共库里的通用资源名全部重命名;清理构建缓存后重新安装;再确认 entry 的图标和应用名称只引用 entry 自己的资源。这样比依赖合并顺序稳定。

嗯,支持一下。。

期待解决

在HarmonyOS Next中,HSP共享包的资源优先级高于HAP模块。当HAP与HSP存在同名icon资源时,编译合并阶段HSP资源会覆盖HAP中的同名项,因此图标被替换。若多个HAP间同名,则feature模块优先级高于entry模块。需检查各模块resources下重复的同名文件。

HarmonyOS 多模块资源合并遵循“高优先级覆盖低优先级”的规则,默认顺序为:AppScope > entry 模块 > HSP > HAR

  1. icon 被 HAR 替换
    按此规则,entry 的 app_icon.png 优先级高于 HAR,理论上不会被覆盖。若实际被替换,说明该 HAR 可能被配置为 resource overlay(资源叠加)模块,或项目在 AppScope/其他更高优先级位置也定义了同名资源。overlay 机制会主动覆盖低优先级资源,优先级最高。

  2. 字符串取不到统一值
    资源解析遵循“模块内优先”。各模块在自身代码中引用 $string:app_name 时,会先解析本模块的同名资源;若本模块没有,才向上查找依赖模块。因此 entry 页面取 entry 的值,HAR 页面取 HAR 的值,表现出不一致,这是正常行为。

  3. HSP 资源不生效
    entry 中已定义了 primary_color,优先级高于 HSP,所以 entry 引用时仍然使用自己的值。若要使用 HSP 的值,需在 entry 中删除同名资源。

  4. overlay 机制
    它是编译期资源覆盖机制,通过构建配置指定某个模块作为 overlay,其资源会覆盖常规优先级中的同名资源,用于适配不同设备或定制场景。

回到顶部