HarmonyOS 应用开发《掌上英语》第6篇-资源管理最佳实践多模块资源复用

资源管理最佳实践:多模块资源复用策略

一、引言

在多模块 HarmonyOS 应用中,资源管理是一个容易被忽视但至关重要的问题。资源放哪儿?怎么引用?暗色模式怎么覆盖?跨模块怎么复用?这些问题如果处理不当,会导致资源冗余、引用混乱和包体积膨胀。

本文以一个包含 11 个模块的英语学习 App 为案例,系统分析其资源管理策略,涵盖目录结构、引用路径、暗色模式适配和跨模块资源复用方案。


二、多模块资源目录结构

本项目采用"通用资源集中 + 特有资源分散"的策略。每个模块的 resources/ 目录结构统一遵循 HarmonyOS 标准:

复制代码
模块名/
  src/main/resources/
    base/              # 基础资源(默认主题)
      element/         # 资源定义(颜色、字号、字符串等)
        color.json
        float.json
        string.json
      media/           # 图片资源
        ic_back.png
        ic_search.png
    dark/              # 暗色模式覆盖
      media/
        ic_back.png

2.1 commonLib:通用资源的集散地

commons/commonLib 作为底层公共库,存放被所有模块共享的资源:

复制代码
commons/commonLib/src/main/resources/
  base/
    element/
      color.json       # 基础色值定义
      float.json       # 字号/间距定义
      string.json      # 字符串定义
    media/
      banner1.png
      ic_back.png       # 通用返回按钮
      ic_filled.svg     # SVG 图标
      ic_more.png
      ic_upload.png
  dark/
    media/
      ic_back.png      # 暗色模式下的返回按钮(白色版本)

2.2 feature 模块:业务特色资源

每个 feature 模块拥有自己的资源目录,存放该业务特有的资源。以 homePage 为例:

复制代码
features/homePage/src/main/resources/
  base/
    element/
      color.json
      float.json       # 包含 50+ 自定义间距/字号
      string.json      # 业务相关字符串
    media/
      ic_avatar.png
      ic_back.png
      ic_search.png
      ic_home.svg
      ic_star.svg
      ic_mic.svg
      ...
  dark/
    media/
      ic_back.png
      ic_delete.png

minePagetopicPage 类似,各自维护自己的资源集。

2.3 component 模块:自包含资源

组件模块为了保持独立性,也包含自己的资源。以 search 组件为例:

复制代码
components/search/src/main/resources/
  base/
    element/
      float.json
      string.json
    media/
      ic_back.png
      ic_delete.svg
  dark/
    media/
      ic_back.png

三、资源引用路径分析

3.1 $r 引用语法

HarmonyOS 使用 $r() 函数引用资源,语法为:

typescript 复制代码
$r('app.type.name')    // 引用本模块或依赖模块的应用资源
$r('sys.type.name')    // 引用系统资源
$r('har.type.name')    // 引用 HAR 包资源(特殊场景)

3.2 应用资源 vs 系统资源

在主要页面中,应用资源和系统资源混合使用:

typescript 复制代码
// product/entry/src/main/ets/pages/MainEntry.ets
.fontSize($r('sys.float.Caption_M'))       // 系统字号
.fontColor($r('sys.color.icon_secondary')) // 系统颜色
.fontColor($r('app.color.icon_bg_blue'))   // 应用自定义颜色

// features/minePage/src/main/ets/views/MinePage.ets
.backgroundColor($r('sys.color.comp_background_list_card'))  // 系统色
.backgroundColor($r('sys.color.background_secondary'))       // 系统色
.fontSize($r('sys.float.Title_M'))                          // 系统字号
.width($r('app.float.vp_16'))                               // 应用间距
.height($r('app.float.vp_16'))

选择策略

  • 系统资源优先sys.color.*sys.float.* 等系统预置资源,自动适配深色模式和不同设备
  • 应用资源补充app.color.*app.float.* 用于自定义业务需求

3.3 常见资源引用示例

资源类型 引用方式 典型场景
系统颜色 $r('sys.color.background_secondary') 页面背景色
系统字号 $r('sys.float.Title_M') 标题字号
系统圆角 $r('sys.float.corner_radius_level10') 卡片圆角
应用颜色 $r('app.color.icon_bg_blue') 品牌色
应用间距 $r('app.float.vp_16') 布局间距
应用图片 $r('app.media.ic_search') 图标
应用字符串 $r('app.string.page_show') 页面文案

四、暗色模式资源覆盖

4.1 覆盖机制

HarmonyOS 的暗色模式通过 resources/dark/ 目录实现。系统在切换到深色模式时,自动加载 dark/ 目录下的同名资源覆盖 base/ 目录中的资源。

以返回按钮图标为例:

复制代码
# 亮色模式
resources/base/media/ic_back.png        → 深色图标

# 暗色模式
resources/dark/media/ic_back.png        → 白色/浅色图标

4.2 项目中使用了 dark 覆盖的模块

几乎所有模块都提供了暗色模式的图标覆盖:

模块 覆盖的资源 路径
commonLib ic_back.png commons/commonLib/src/main/resources/dark/media/ic_back.png
homePage ic_back.png, ic_delete.png features/homePage/src/main/resources/dark/media/
minePage ic_back.png, iconRight.png, person.png, star.svg features/minePage/src/main/resources/dark/media/
topicPage ic_back.png, ic_share.svg features/topicPage/src/main/resources/dark/media/
search ic_back.png components/search/src/main/resources/dark/media/

4.3 最佳实践

1. 图标必须覆盖

带有透明背景的图标在深色模式下会"消失",因此需要提供高亮版本。

2. 颜色无需覆盖

使用 $r('sys.color.*') 系统颜色的场景,系统会自动切换色值,无需在 dark/ 中定义。

3. 图片资源考虑 9-patch

对于需要拉伸的背景图,使用 9-patch 格式(.9.png),暗色模式提供对应的暗色版本。

4. SVG 优先

SVG 图标更小、支持主题色继承,优先使用 .svg 格式。项目中 ic_filled.svgic_star.svgic_home.svg 等均为 SVG 格式。


五、跨模块资源引用限制与解决方案

5.1 核心限制

HarmonyOS 的 HAR 包之间存在资源引用限制:一个 HAR 包不能直接引用另一个 HAR 包的资源 。也就是说,在 base_select 组件中无法通过 $r('app.media.xxx') 引用 homePage 模块中的图片。

5.2 项目中的解决方案

本项目采用了多层分工的策略来解决这个问题:

第一层:通用资源放在 commonLib

commonLib 被所有模块依赖,放在其中的资源对所有模块可见:

json5 复制代码
// commons/commonLib/src/main/resources/base/media/
// 以下资源对所有依赖 commonLib 的模块可见
banner1.png
ic_back.png
ic_filled.svg
ic_more.png
ic_upload.png

所有 feature 模块和 entry 模块都依赖 commonLib:

json5 复制代码
// features/homePage/oh-package.json5
{
  "dependencies": {
    "commonlib": "file:../../commons/commonLib"
  }
}

因此,在任何页面中都可以引用:

typescript 复制代码
Image($r('app.media.ic_back'))  // commonLib 中的资源

第二层:特有资源放在模块内

各模块特有的资源存放在自己模块内,不对外暴露。例如 homePage 特有的 ic_home.svg 只能被 homePage 模块中的页面引用。

第三层:entry 层资源的特殊地位

product/entry 作为应用入口模块,拥有访问所有模块资源的能力,因此一些需要在全局引用的资源可以放在 entry 层。

5.3 资源冲突处理

当多个模块定义了同名资源时,最后构建的模块覆盖前面的。为了避免冲突:

  1. 命名约定 :资源名使用模块前缀,如 homePage 使用 ic_home.svgminePage 使用 icon_msg.png
  2. commonLib 优先:通用资源优先定义在 commonLib 中,避免重复
  3. 系统资源优先 :能用 $r('sys.color.*') 的,尽量不创建自定义资源

5.4 实际引用示例分析

MinePage 的源码可以观察资源的混合使用模式:

typescript 复制代码
// 系统资源(深色模式自动适配)
.fontSize($r('sys.float.Title_M'))
.fontColor($r('sys.color.font_primary'))
.backgroundColor($r('sys.color.comp_background_list_card'))
.borderRadius($r('sys.float.corner_radius_level10'))

// 应用资源(自定义业务)
Image($r('app.media.iconRight'))
Image($r('app.media.icon_practice'))
.width($r('app.float.vp_16'))
.height($r('app.float.vp_16'))
.margin({ left: $r('app.float.vp_12') })

这种混合使用模式确保了:

  • 系统资源:自适应深色模式、字体缩放等系统设置
  • 应用资源:满足业务特定的视觉需求

六、资源管理的工程化建议

6.1 float.json 的合理使用

本项目各模块的 float.json 中定义了大量的间距值:

json 复制代码
{
  "float": [
    { "name": "vp_2", "value": "2vp" },
    { "name": "vp_4", "value": "4vp" },
    { "name": "vp_8", "value": "8vp" },
    // ... 从 2vp 到 300vp 共 50+ 个间距定义
  ]
}

建议:

  • 只定义业务中实际用到的值,不必全覆盖
  • 使用语义化的命名(如 vp_card_padding)替代纯数字命名
  • 跨模块复用的间距定义在 commonLib 中

6.2 资源去重策略

定期使用工具扫描各模块的 media/ 目录,识别重复资源:

  • 同样的 ic_back.png 出现在了 5 个模块中 → 应该移到 commonLib
  • 只在一个模块中使用的资源 → 保留在模块内
  • 资源只增不减 → 建立资源评审机制

6.3 SVG 优先原则

本项目同时使用了 .png.svg 格式。SVG 的优势:

  • 文件小(通常为 PNG 的 1/5 ~ 1/10)
  • 无损缩放,适合多分辨率适配
  • 支持颜色继承,部分场景下暗色模式无需额外资源

建议新资源优先使用 SVG 格式,仅复杂照片类资源使用 PNG。


七、总结

多模块资源管理需要遵循以下核心原则:

  1. 集中共享:通用资源集中在 commonLib,被所有模块依赖
  2. 分散自治:模块特有资源放在模块内,不对外暴露
  3. 系统优先 :优先使用 sys.* 系统资源,减少自定义资源
  4. 暗色覆盖 :只覆盖 media/ 资源,颜色通过系统资源自适应
  5. 命名防冲突:使用模块前缀或语义化命名,避免同名覆盖

通过合理的资源分层和管理,11 个模块的庞大工程保持了资源的清晰可维护,既避免了冗余,又实现了跨模块复用。


八、参考源码路径

文件 路径
commonLib 资源目录 d:\HarmonyOS\WorkSpace\Exam1.0.4\commons\commonLib\src\main\resources\
homePage 资源目录 d:\HarmonyOS\WorkSpace\Exam1.0.4\features\homePage\src\main\resources\
minePage 资源目录 d:\HarmonyOS\WorkSpace\Exam1.0.4\features\minePage\src\main\resources\
topicPage 资源目录 d:\HarmonyOS\WorkSpace\Exam1.0.4\features\topicPage\src\main\resources\
search 组件资源目录 d:\HarmonyOS\WorkSpace\Exam1.0.4\components\search\src\main\resources\
MainEntry 资源引用 d:\HarmonyOS\WorkSpace\Exam1.0.4\product\entry\src\main\ets\pages\MainEntry.ets
MinePage 资源引用 d:\HarmonyOS\WorkSpace\Exam1.0.4\features\minePage\src\main\ets\views\MinePage.ets
相关推荐
2301_768103491 小时前
HarmonyOS趣味相机实战第7篇:Preferences相册缓存、旧数据兼容与异常兜底
harmonyos·arkts·preferences·本地缓存·数据兼容
会飞锦鲤2 小时前
基于YOLOv10的瓜果成熟度智能检测系统
人工智能·python·深度学习·yolo·flask
voidmort2 小时前
19. 合成数据(Synthetic Data)与模型对齐
人工智能·深度学习·机器学习
larance2 小时前
机器学习特征预处理之序号编码
人工智能·深度学习·机器学习
HONG````2 小时前
ArkTS 并发编程:TaskPool 多线程实战
harmonyos·arkts
不羁的木木2 小时前
HarmonyOS APP实战-基于Image Kit的图像处理APP - 第8篇:图片编码与保存
图像处理·华为·harmonyos
春卷同学2 小时前
HarmonyOS掌上记账APP开发实践第2篇:从零搭建记账应用 — MoneyTrack 工程全景解析![
华为·harmonyos
春卷同学2 小时前
HarmonyOS掌上记账APP开发实践第1篇:HarmonyOS 多模块 HAR 架构最佳实践 — MoneyTrack 多模块拆分之道
华为·架构·harmonyos
大鱼>3 小时前
宠物活动轨迹追踪系统:GPS/BDS+UWB+BLE多定位融合方案
人工智能·深度学习·算法·iot·宠物