鸿蒙中 访问hsp和har包的资源文件
本文介绍了模块化开发中的资源管理方案,重点解决资源冗余、维护困难和一致性问题。提出了集中管理和统一访问的资源优化方法,详细阐述了HAR和HSP资源的跨模块访问技术,包括通过$r语法、resourceManager和createModuleContext等多种实现方式。针对不同场景推荐了相应方案:简单UI资源推荐$r语法,大量HSP资源建议采用资源管理类封装。同时分析了资源冲突解决策略和命名规范,强
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、背景
模块化开发的资源管理
-
资源重复:多个模块定义相同资源,造成冗余
-
维护困难:资源分散在不同模块,更新维护成本高
-
一致性差:相同功能在不同模块中使用不同资源
跨模块资源访问方案
-
集中管理:将共享资源集中存放在特定模块
-
统一访问:提供标准化方式访问跨模块资源
-
减少冗余:避免重复定义,提高开发效率
-
便于维护:资源变更只需修改一处
二、跨模块访问 HAR 资源
方法一:通过 $r 或 $rawfile 语法访问
适用场景
-
简单的、静态的资源引用
-
在 UI 组件中直接引用资源
-
资源使用场景简单,无需复杂处理
语法格式
// 访问字符串资源
Text($r('app.string.module_shared_string'))
// 访问图片资源
Image($r('app.media.module_shared_image'))
// 访问颜色资源
.backgroundColor($r('app.color.primary_color'))
// 访问原始文件
Text($rawfile('config_file.json'))
应用示例
@Entry
@Component
struct ProductDetailPage {
build() {
Column() {
// 使用HAR中的字符串资源
Text($r('app.string.product_title'))
.fontSize($r('app.float.title_font_size'))
.fontColor($r('app.color.text_primary'))
// 使用HAR中的图片资源
Image($r('app.media.product_default_image'))
.width(200)
.height(200)
}
}
}
方法二:通过 resourceManager 访问资源
适用场景
-
需要程序化处理资源数据
-
图像效果处理、字符串动态拼接
-
需要获取资源原始数据的复杂业务逻辑
核心优势
-
性能更优:使用资源ID作为参数,避免字符串解析
-
功能丰富:提供更多资源处理接口
-
灵活性高:支持同步/异步获取资源
实现方式
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct ResourceProcessor {
// 通过上下文获取ResourceManager
private resourceMgr: resourceManager.ResourceManager = getContext().resourceManager;
aboutToAppear() {
// 同步获取字符串资源(推荐方式)
const welcomeText = this.resourceMgr.getStringSync(
$r('app.string.welcome_message').id
);
// 同步获取图片资源
const logoImage = this.resourceMgr.getMediaContentSync(
$r('app.media.app_logo').id
);
// 异步获取颜色资源
this.resourceMgr.getColor($r('app.color.theme_color').id)
.then(colorValue => {
console.info(`Theme color value: ${colorValue}`);
});
// 获取原始文件内容
const configData = this.resourceMgr.getRawFileContentSync('app_config.json');
}
build() {
Column() {
// 使用获取到的资源
Text(this.processedText)
Image(this.processedImage)
}
}
}
优化建议
-
优先使用ID方式:
getStringSync(resId)比getStringByNameSync(name)性能更好 -
避免频繁调用:在
aboutToAppear中预先获取资源,避免在build中频繁调用 -
使用同步接口:在非主线程场景下使用同步接口避免阻塞
三、跨模块访问 HSP 资源
方法一:通过 $r 或 $rawfile 语法访问(指定HSP模块)
语法格式
// 访问HSP模块中的字符串资源
Text($r('[hsp_module_name].string.resource_name'))
// 访问HSP模块中的媒体资源
Image($r('[hsp_module_name].media.image_name'))
// 访问HSP模块中的原始文件
Text($rawfile('[hsp_module_name].file_name'))
应用示例
@Entry
@Component
struct CrossModuleUI {
build() {
Column() {
// 访问基础HSP模块的资源
Text($r('[base_hsp].string.common_cancel'))
.fontSize(16)
// 访问UI组件HSP模块的资源
Image($r('[ui_components].media.ic_arrow_right'))
.width(24)
.height(24)
// 访问主题HSP模块的颜色资源
.backgroundColor($r('[theme_hsp].color.background_primary'))
}
.padding($r('[layout_hsp].float.default_padding'))
}
}
方法二:通过 createModuleContext 访问资源
适用场景
-
需要对HSP资源进行数据处理
-
少量资源的程序化访问
-
不希望添加显式依赖的场景
实现方式
import { application } from '@kit.AbilityKit';
@Entry
@Component
struct HSPResourceAccessor {
private hspResources: Map<string, any> = new Map();
aboutToAppear() {
// 创建HSP模块上下文
application.createModuleContext(getContext(), 'shared_ui_hsp')
.then(moduleContext => {
const resManager = moduleContext.resourceManager;
// 通过名称获取字符串资源
const buttonText = resManager.getStringByNameSync('btn_confirm_text');
this.hspResources.set('confirmText', buttonText);
// 通过名称获取图片资源
const iconImage = resManager.getMediaByNameSync('ic_success');
this.hspResources.set('successIcon', iconImage);
// 获取维度资源
const spacing = resManager.getFloatByNameSync('spacing_medium');
this.hspResources.set('mediumSpacing', spacing);
})
.catch(error => {
console.error(`Failed to access HSP resources: ${error.message}`);
});
}
build() {
Column() {
Text(this.hspResources.get('confirmText') || 'Default Text')
Image(this.hspResources.get('successIcon'))
}
.padding(this.hspResources.get('mediumSpacing') || 0)
}
}
方法优缺点
优点:
-
无需在模块间添加依赖关系
-
使用相对简单直接
缺点:
-
硬编码问题:需要手动编写资源名称字符串
-
维护困难:HSP资源名称变更时,使用方需要同步修改
-
类型安全:缺乏编译时检查,容易出错
-
不适合大量资源:资源较多时代码冗长
方法三:HSP导出资源管理类(推荐方案)
适用场景
-
大量资源的跨模块访问
-
需要对资源进行封装和抽象
-
希望提供类型安全的资源访问接口
实现步骤
步骤1:在HSP中创建资源管理类
// shared_resources_hsp/src/main/ets/utils/ResourceExporter.ets
export class SharedResourceManager {
// 字符串资源
static getCommonStrings() {
return {
confirm: $r('app.string.btn_confirm'),
cancel: $r('app.string.btn_cancel'),
loading: $r('app.string.status_loading'),
error: $r('app.string.status_error')
};
}
// 图片资源
static getIcons() {
return {
arrowRight: $r('app.media.ic_arrow_right'),
arrowLeft: $r('app.media.ic_arrow_left'),
close: $r('app.media.ic_close'),
menu: $r('app.media.ic_menu')
};
}
// 颜色资源
static getThemeColors() {
return {
primary: $r('app.color.theme_primary'),
secondary: $r('app.color.theme_secondary'),
background: $r('app.color.background_primary'),
text: $r('app.color.text_primary')
};
}
// 维度资源
static getLayoutDimensions() {
return {
spacingSmall: $r('app.float.spacing_small'),
spacingMedium: $r('app.float.spacing_medium'),
spacingLarge: $r('app.float.spacing_large'),
cornerRadius: $r('app.float.corner_radius_default')
};
}
// 获取特定主题资源
static getDarkThemeResources() {
return {
background: $r('app.color.dark_background'),
text: $r('app.color.dark_text_primary'),
card: $r('app.color.dark_surface')
};
}
}
步骤2:在HSP入口文件中导出
// shared_resources_hsp/index.ets
export { SharedResourceManager } from './src/main/ets/utils/ResourceExporter';
export { ThemeManager } from './src/main/ets/utils/ThemeManager';
export { ImageProcessor } from './src/main/ets/utils/ImageProcessor';
步骤3:使用方导入并使用
// 使用方模块
import { SharedResourceManager } from 'shared_resources_hsp';
@Entry
@Component
struct ProductScreen {
private resources = SharedResourceManager.getCommonStrings();
private icons = SharedResourceManager.getIcons();
private colors = SharedResourceManager.getThemeColors();
private dimensions = SharedResourceManager.getLayoutDimensions();
build() {
Column() {
// 使用HSP导出的字符串资源
Text(this.resources.loading)
.fontSize(18)
.fontColor(this.colors.text)
// 使用HSP导出的图标资源
Image(this.icons.close)
.width(24)
.height(24)
.onClick(() => {
// 关闭操作
})
Button(this.resources.confirm)
.backgroundColor(this.colors.primary)
.borderRadius(this.dimensions.cornerRadius)
}
.padding(this.dimensions.spacingMedium)
.backgroundColor(this.colors.background)
}
}
方法优势
-
封装性好:HSP内部资源变化不影响使用方
-
类型安全:提供完整的TypeScript类型支持
-
易于维护:资源变更只需修改HSP内部实现
-
使用简便:使用方无需了解资源具体名称
-
功能丰富:支持资源组合和业务逻辑封装
四、资源冲突解决
资源覆盖优先级
当不同模块存在同名资源时,按照以下优先级覆盖(从高到低):
-
AppScope 中的资源 - 最高优先级
-
HAP 包自身模块资源
-
依赖的 HAR/HSP 模块资源
-
按照
oh-package.json5中dependencies的顺序 -
依赖顺序在前的模块优先级较高
-
示例
// oh-package.json5
{
"dependencies": {
"shared_ui_components": "1.0.0", // 优先级较高
"third_party_library": "2.1.0", // 优先级较低
"theme_package": "1.2.0" // 优先级最低
}
}
建议
-
命名空间化:在资源名称前添加模块前缀,如
module_prefix_resource_name -
明确依赖:在文档中明确说明资源依赖关系
-
版本管理:使用语义化版本管理共享资源模块
五、方案选择
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 简单UI资源引用 | 方法一:$r 语法 |
简单直接,代码清晰 |
| HAR资源访问 | 方法一或方法二 | 访问方式与本地资源一致 |
| 少量HSP资源 | 方法二:createModuleContext | 灵活,无需添加依赖 |
| 大量HSP资源 | 方法三:资源管理类 | 类型安全,易于维护 |
| 团队协作开发 | 方法三:资源管理类 | 接口稳定,降低耦合 |
| 资源需要处理 | 方法二或方法三 | 支持程序化资源处理 |
更多推荐

所有评论(0)