Stage模型应用程序包结构
为了让开发者能对应用程序包在不同阶段的形态有更加清晰的认知,分别对开发态、编译态、发布态的应用程序结构展开介绍。
开发态包结构
在DevEco Studio上创建一个项目工程,并尝试创建多个不同类型的Module。根据实际工程中的目录对照本章节进行学习,可以有助于理解开发态的应用程序结构。

说明
- AppScope目录由DevEco Studio自动生成,不可更改。
- Module目录名称可以由DevEco Studio自动生成(比如entry、library等),也可以自定义。为了便于说明,下表中统一采用Module_name表示。
工程结构主要包含的文件类型及用途如下:
文件类型 | 说明 |
---|---|
配置文件 | 包括应用级配置信息、以及Module级配置信息: - AppScope > app.json5:app.json5配置文件,用于声明应用的全局配置信息,比如应用Bundle名称、应用名称、应用图标、应用版本号等。 - Module_name > src > main > module.json5:module.json5配置文件,用于声明Module基本信息、支持的设备类型、所含的组件信息、运行所需申请的权限等。 |
ArkTS源码文件 | Module_name > src > main > ets:用于存放Module的ArkTS源码文件(.ets文件)。 |
资源文件 | 包括应用级资源文件、以及Module级资源文件,支持图形、多媒体、字符串、布局文件等,详见资源分类与访问。 - AppScope > resources :用于存放应用需要用到的资源文件。 - Module_name > src > main > resources :用于存放该Module需要用到的资源文件。 |
其他配置文件 | 用于编译构建,包括构建配置文件、编译构建任务脚本、混淆规则文件、依赖的共享包信息等。 - build-profile.json5:工程级或Module级的构建配置文件,包括应用签名、产品配置等。 - hvigorfile.ts:应用级或Module级的编译构建任务脚本,开发者可以自定义编译构建工具版本、控制构建行为的配置参数。 - obfuscation-rules.txt:混淆规则文件。混淆开启后,在使用Release模式进行编译时,会对代码进行编译、混淆及压缩处理,保护代码资产。 - oh-package.json5:用于存放依赖库的信息,包括所依赖的三方库和共享包。 |
编译态包结构
不同类型的Module编译后会生成对应的HAP、HAR、HSP等文件,开发态视图与编译态视图的对照关系如下:

从开发态到编译态,Module中的文件会发生如下变更:
- ets目录:ArkTS源码编译生成.abc文件。
- resources目录:AppScope目录下的资源文件会合入到Module下面资源目录中,如果两个目录下存在重名文件,编译打包后只会保留AppScope目录下的资源文件。
- module配置文件:AppScope目录下的app.json5文件字段会合入到Module下面的module.json5文件之中,编译后生成HAP或HSP最终的module.json文件。
说明
在编译HAP和HSP时,会把他们所依赖的HAR直接编译到HAP和HSP中。
发布态包结构
每个应用中至少包含一个.hap文件,可能包含若干个.hsp文件、也可能不含,一个应用中的所有.hap与.hsp文件合在一起称为Bundle,其对应的bundleName是应用的唯一标识(详见app.json5配置文件中的bundleName标签)。
当应用发布上架到应用市场时,需要将Bundle打包为一个.app后缀的文件用于上架,这个.app文件称为App Pack(Application Package),与此同时,DevEco Studio工具自动会生成一个pack.info文件。pack.info文件描述了App Pack中每个HAP和HSP的属性,包含APP中的bundleName和versionCode信息、以及Module中的name、type和abilities等信息。
说明
- App Pack是发布上架到应用市场的基本单元,但是不能在设备上直接安装和运行。
- 在应用签名、云端分发、端侧安装时,都是以HAP/HSP为单位进行签名、分发和安装的。

选择合适的包类型
HAP、HAR、HSP三者的功能和使用场景总结对比如下:
Module类型 | 包类型 | 说明 |
---|---|---|
Ability | HAP | 应用的功能模块,可以独立安装和运行,必须包含一个entry类型的HAP,可选包含一个或多个feature类型的HAP。 |
Static Library | HAR | 静态共享包,编译态复用。 - 支持应用内共享,也可以发布后供其他应用使用。 - 作为二方库,发布到OHPM私仓,供公司内部其他应用使用。 - 作为三方库,发布到OHPM中心仓,供其他应用使用。 - 多包(HAP/HSP)引用相同的HAR时,会造成多包间代码和资源的重复拷贝,从而导致应用包膨大。 - 注意:编译HAR时,建议开启混淆能力,保护代码资产。 |
Shared Library | HSP | 动态共享包,运行时复用。 - 当多包(HAP/HSP)同时引用同一个共享包时,采用HSP替代HAR,可以避免HAR造成的多包间代码和资源的重复拷贝,从而减小应用包大小。 |
HAP、HSP、HAR支持的规格对比如下,其中“√”表示是,“×”表示否。
开发者可以根据实际场景所需的能力,选择相应类型的包进行开发。在后续的章节中还会针对如何使用HAP、HAR、HSP分别展开详细介绍。
规格 | HAP | HAR | HSP |
---|---|---|---|
支持在配置文件中声明UIAbility组件与ExtensionAbility组件 | √ | × | × |
支持在配置文件中声明pages页面 | √ | × | √ |
支持包含资源文件与.so文件 | √ | √ | √ |
支持依赖其他HAR文件 | √ | √ | √ |
支持依赖其他HSP文件 | √ | √ | √ |
支持在设备上独立安装运行 | √ | × | × |
说明
- HAR虽然不支持在配置文件中声明pages页面,但是可以包含pages页面,并通过命名路由的方式进行跳转。
- 由于HSP仅支持应用内共享,如果HAR依赖了HSP,则该HAR文件仅支持应用内共享,不支持发布到二方仓或三方仓供其他应用使用,否则会导致编译失败。
- HAR和HSP均不支持循环依赖,也不支持依赖传递。
HSP
HSP(Harmony Shared Package)是动态共享包,可以包含代码、C++库、资源和配置文件,通过HSP可以实现代码和资源的共享。HSP不支持独立发布,而是跟随其宿主应用的APP包一起发布,与宿主应用同进程,具有相同的包名和生命周期。
说明
应用内HSP:在编译过程中与应用包名(bundleName)强耦合,只能给某个特定的应用使用。
集成态HSP:构建、发布过程中,不与特定的应用包名耦合;使用时,工具链支持自动将集成态HSP的包名替换成宿主应用包名,并且会重新签名生成一个新的HSP包,作为宿主应用的安装包,这个新的HSP也属于应用内HSP。
使用场景
-
多个HAP/HSP共用的代码和资源放在同一个HSP中,可以提高代码、资源的可重用性和可维护性,同时编译打包时也只保留一份HSP代码和资源,能够有效控制应用包大小。
-
HSP在运行时按需加载,有助于提升应用性能。
-
同一个组织内部的多个应用之间,可以使用集成态HSP实现代码和资源的共享。
约束限制
- HSP不支持在设备上单独安装/运行,需要与依赖该HSP的HAP一起安装/运行。HSP的版本号必须与HAP版本号一致。
- HSP不支持在配置文件中声明ExtensionAbility组件和UIAbility组件。
- HSP可以依赖其他HAR或HSP,但不支持循环依赖,也不支持依赖传递。
说明
循环依赖:例如有三个HSP,HSP-A、HSP-B和HSP-C,循环依赖指HSP-A依赖HSP-B,HSP-B依赖HSP-C,HSP-C又依赖HSP-A。
依赖传递:例如有三个HSP,HSP-A、HSP-B和HSP-C,依赖关系是HSP-A依赖HSP-B,HSP-B依赖HSP-C。不支持传递依赖指HSP-A可以使用HSP-B的方法和组件,但是HSP-A不能直接使用HSP-C的方法和组件。
创建
通过DevEco Studio创建一个HSP模块,详见创建HSP模块,我们以创建一个名为library的HSP模块为例。基本的工程目录结构如下:
MyApplication
├── library
│ ├── src
│ │ └── main
│ │ ├── ets
│ │ │ └── pages
│ │ │ └── index.ets //模块library的页面文件
│ │ ├── resources //模块library的资源目录
│ │ └── module.json5 //模块library的配置文件
│ ├── oh-package.json5 //模块级
│ ├── index.ets //入口文件index.ets
│ └── build-profile.json5 //模块级
└── build-profile.json5 //工程级
开发
介绍如何导出HSP的ArkUI组件、接口、资源,供应用内的其他HAP/HSP引用。
导出ArkUI组件
ArkUI组件可以通过export导出,例如:
// library/src/main/ets/components/MyTitleBar.ets
@Component
export struct MyTitleBar {
build() {
Row() {
Text($r('app.string.library_title'))
.id('library')
.fontFamily('HarmonyHeiTi')
.fontWeight(FontWeight.Bold)
.fontSize(32)
.fontColor($r('app.color.text_color'))
}
.width('100%')
}
}
对外暴露的接口,需要在入口文件index.ets中声明:
// library/index.ets
export { MyTitleBar } from './src/main/ets/components/MyTitleBar';
导出ts类和方法
通过export导出ts类和方法,例如:
// library/src/main/ets/utils/test.ets
export class Log {
static info(msg: string): void {
console.info(msg);
}
}
export function add(a: number, b: number): number {
return a + b;
}
export function minus(a: number, b: number): number {
return a - b;
}
对外暴露的接口,需要在入口文件index.ets中声明:
// library/index.ets
export { Log, add, minus } from './src/main/ets/utils/test';
导出native方法
在HSP中也可以包含C++编写的so。对于so中的native方法,HSP通过间接的方式导出,以导出liblibrary.so的乘法接口multi为例:
// library/src/main/ets/utils/nativeTest.ets
import native from 'liblibrary.so';
export function nativeMulti(a: number, b: number): number {
let result: number = native.multi(a, b);
return result;
}
对外暴露的接口,需要在入口文件index.ets中声明:
// library/index.ets
export { nativeMulti } from './src/main/ets/utils/nativeTest';
通过$r访问HSP中的资源
在组件中,经常需要使用字符串、图片等资源。HSP中的组件需要使用资源时,一般将其所用资源放在HSP包内,而非放在HSP的使用方处,以符合高内聚低耦合的原则。
在工程中,常通过$r/$rawfile的形式引用应用资源。可以用$r/$rawfile访问本模块resources目录下的资源,如访问resources目录下定义的图片src/main/resources/base/media/example.png时,可以用$r("app.media.example")。有关$r/$rawfile的详细使用方式,请参阅文档资源分类与访问中“资源访问-应用资源”小节。
不推荐使用相对路径的方式,容易引用错误路径。例如:
当要引用上述同一图片资源时,在HSP模块中使用Image("../../resources/base/media/example.png"),实际上该Image组件访问的是HSP调用方(如entry)下的资源entry/src/main/resources/base/media/example.png。
// library/src/main/ets/pages/Index.ets
// 正确用例
Image($r('app.media.example'))
.id('example')
.borderRadius('48px')
// 错误用例
Image("../../resources/base/media/example.png")
.id('example')
.borderRadius('48px')
导出HSP中的资源
跨包访问HSP内资源时,推荐实现一个资源管理类,以封装对外导出的资源。采用这种方式,具有如下优点:
- HSP开发者可以控制自己需要导出的资源,不需要对外暴露的资源可以不用导出。
- 使用方无须感知HSP内部的资源名称。当HSP内部的资源名称发生变化时,也不需要使用方跟着修改。
其具体实现如下:
将需要对外提供的资源封装为一个资源管理类:
// library/src/main/ets/ResManager.ets
export class ResManager{
static getPic(): Resource{
return $r('app.media.pic');
}
static getDesc(): Resource{
return $r('app.string.shared_desc');
}
}
对外暴露的接口,需要在入口文件index.ets中声明:
// library/index.ets
export { ResManager } from './src/main/ets/ResManager';
使用
介绍如何引用HSP中的接口,以及如何通过页面路由实现HSP的pages页面跳转与返回。
引用HSP中的接口
要使用HSP中的接口,首先需要在使用方的oh-package.json5中配置对它的依赖,详见引用动态共享包。
依赖配置成功后,就可以像使用HAR一样调用HSP的对外接口了。例如,上面的library已经导出了下面这些接口:
// library/index.ets
export { Log, add, minus } from './src/main/ets/utils/test';
export { MyTitleBar } from './src/main/ets/components/MyTitleBar';
export { ResManager } from './src/main/ets/ResManager';
export { nativeMulti } from './src/main/ets/utils/nativeTest';
在使用方的代码中,可以这样使用:
// entry/src/main/ets/pages/index.ets
import { Log, add, MyTitleBar, ResManager, nativeMulti } from 'library';
import { BusinessError } from '@ohos.base';
import router from '@ohos.router';
const TAG = 'Index';
@Entry
@Component
struct Index {
@State message: string = '';
build() {
Column() {
List() {
ListItem() {
MyTitleBar()
}
.margin({ left: '35px', top: '32px' })
ListItem() {
Text(this.message)
.fontFamily('HarmonyHeiTi')
.fontSize(18)
.textAlign(TextAlign.Start)
.width('100%')
.fontWeight(FontWeight.Bold)
}
.width('685px')
.margin({ top: 30, bottom: 10 })
ListItem() {
// ResManager返回的Resource对象,可以传给组件直接使用,也可以从中取出资源来使用
Image(ResManager.getPic())
.id('image')
.borderRadius('48px')
}
.width('685px')
.margin({ top: 10, bottom: 10 })
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
ListItem() {
Text($r('app.string.add'))
.fontSize(18)
.textAlign(TextAlign.Start)
.width('100%')
.fontWeight(500)
.height('100%')
}
.id('add')
.borderRadius(24)
.width('685px')
.height('84px')
.backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
.margin({ top: 10, bottom: 10 })
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.onClick(() => {
Log.info('add button click!');
this.message = 'result: ' + add(1, 2);
})
ListItem() {
Text($r('app.string.get_string_value'))
.fontSize(18)
.textAlign(TextAlign.Start)
.width('100%')
.fontWeight(500)
.height('100%')
}
.id('getStringValue')
.borderRadius(24)
.width('685px')
.height('84px')
.backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
.margin({ top: 10, bottom: 10 })
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.onClick(() => {
// 先通过当前上下文获取hsp模块的上下文,再获取hsp模块的resourceManager,然后再调用resourceManager的接口获取资源
getContext()
.createModuleContext('library')
.resourceManager
.getStringValue(ResManager.getDesc())
.then(value => {
console.log('getStringValue is ' + value);
this.message = 'getStringValue is ' + value;
})
.catch((err: BusinessError) => {
console.error('getStringValue promise error is ' + err);
});
})
ListItem() {
Text($r('app.string.native_multi'))
.fontSize(18)
.textAlign(TextAlign.Start)
.width('100%')
.fontWeight(500)
.height('100%')
}
.id('nativeMulti')
.borderRadius(24)
.width('685px')
.height('84px')
.backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
.margin({ top: 10, bottom: 10 })
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.onClick(() => {
Log.info('nativeMulti button click!');
this.message = 'result: ' + nativeMulti(3, 4);
})
}
.alignListItem(ListItemAlign.Center)
}
.width('100%')
.backgroundColor($r('app.color.page_background'))
.height('100%')
}
}
页面路由跳转
若开发者想在entry模块中,添加一个按钮跳转至library模块中的menu页面(路径为:library/src/main/ets/pages/menu.ets),那么可以在使用方的代码(entry模块下的Index.ets,路径为:entry/src/main/ets/pages/Index.ets)里这样使用:
import { Log, add, MyTitleBar, ResManager, nativeMulti } from 'library';
import { BusinessError } from '@ohos.base';
import router from '@ohos.router';
const TAG = 'Index';
@Entry
@Component
struct Index {
@State message: string = '';
build() {
Column() {
List() {
ListItem() {
Text($r('app.string.click_to_menu'))
.fontSize(18)
.textAlign(TextAlign.Start)
.width('100%')
.fontWeight(500)
.height('100%')
}
.id('clickToMenu')
.borderRadius(24)
.width('685px')
.height('84px')
.backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
.margin({ top: 10, bottom: 10 })
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.onClick(() => {
router.pushUrl({
url: '@bundle:com.samples.hspsample/library/ets/pages/Menu'
}).then(() => {
console.log('push page success');
}).catch((err: BusinessError) => {
console.error('pushUrl failed, code is' + err.code + ', message is' + err.message);
})
})
}
.alignListItem(ListItemAlign.Center)
}
.width('100%')
.backgroundColor($r('app.color.page_background'))
.height('100%')
}
}
其中router.pushUrl方法的入参中url的内容为:
'@bundle:com.samples.hspsample/library/ets/pages/Menu'
url内容的模板为:
'@bundle:包名(bundleName)/模块名(moduleName)/路径/页面所在的文件名(不加.ets后缀)'
页面路由返回
如果当前处于HSP中的页面,需要返回之前的页面时,可以使用router.back方法,但是返回的页面必须是当前页面跳转路径上的页面。
import router from '@ohos.router';
@Entry
@Component
struct Index3 { // 路径为:`library/src/main/ets/pages/Back.ets
@State message: string = 'HSP back page';
build() {
Row() {
Column() {
Text(this.message)
.fontFamily('HarmonyHeiTi')
.fontWeight(FontWeight.Bold)
.fontSize(32)
.fontColor($r('app.color.text_color'))
.margin({ top: '32px' })
.width('624px')
Button($r('app.string.back_to_HAP'))
.id('backToHAP')
.fontFamily('HarmonyHeiTi')
.height(48)
.width('624px')
.margin({ top: 550 })
.type(ButtonType.Capsule)
.borderRadius($r('sys.float.ohos_id_corner_radius_button'))
.backgroundColor($r('app.color.button_background'))
.fontColor($r('sys.color.ohos_id_color_foreground_contrary'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
// 绑定点击事件
.onClick(() => {
router.back({ // 返回HAP的页面
url: 'pages/Index' // 路径为:`entry/src/main/ets/pages/Index.ets`
})
})
Button($r('app.string.back_to_HSP'))
.id('backToHSP')
.fontFamily('HarmonyHeiTi')
.height(48)
.width('624px')
.margin({ top: '4%' , bottom: '6%' })
.type(ButtonType.Capsule)
.borderRadius($r('sys.float.ohos_id_corner_radius_button'))
.backgroundColor($r('app.color.button_background'))
.fontColor($r('sys.color.ohos_id_color_foreground_contrary'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
// 绑定点击事件
.onClick(() => {
router.back({ // 返回HSP的页面
url: '@bundle:com.samples.hspsample/library/ets/pages/Menu' //路径为:`library/src/main/ets/pages/Menu.ets
})
})
}
.width('100%')
}
.backgroundColor($r('app.color.page_background'))
.height('100%')
}
}
页面返回router.back方法的入参中url说明:
-
如果从HSP页面返回HAP页面,url的内容为:
'pages/Index'
url内容的模板为:
'页面所在的文件名(不加.ets后缀)'
HAR
HAR(Harmony Archive)是静态共享包,可以包含代码、C++库、资源和配置文件。通过HAR可以实现多个模块或多个工程共享ArkUI组件、资源等相关代码。
使用场景
- 支持应用内共享,也可以发布后供其他应用使用。
- 作为二方库,发布到OHPM私仓,供公司内部其他应用使用。
- 作为三方库,发布到OHPM中心仓,供其他应用使用。
- 多包(HAP/HSP)引用相同的HAR时,会造成多包间代码和资源的重复拷贝,从而导致应用包膨大。
约束限制
- HAR不支持在设备上单独安装/运行,只能作为应用模块的依赖项被引用。
- HAR不支持在配置文件中声明ExtensionAbility组件,但支持UIAbility组件。
说明
如果使用startAbility接口拉起HAR中的UIAbility,接口参数中的moduleName取值需要为依赖该HAR的HAP/HSP的moduleName。
- HAR不支持在配置文件中声明pages页面,但是可以包含pages页面,并通过命名路由的方式进行跳转。
- HAR不支持引用AppScope目录中的资源。在编译构建时,AppScope中的内容不会打包到HAR中,因此会导致HAR资源引用失败。
- HAR可以依赖其他HAR,但不支持循环依赖,也不支持依赖传递。
创建
通过DevEco Studio创建一个HAR模块,详见创建库模块。
开发
介绍如何导出HAR的ArkUI组件、接口、资源,供其他应用或当前应用的其他模块引用。
Index.ets文件是HAR导出声明文件的入口,HAR需要导出的接口,统一在Index.ets文件中导出。Index.ets文件是DevEco Studio默认自动生成的,用户也可以自定义,在模块的oh-package.json5文件中的main字段配置入口声明文件,配置如下所示:
{
"main": "Index.ets"
}
导出ArkUI组件
ArkUI组件的导出方式与ts的导出方式一致,通过export导出ArkUI组件,示例如下:
// library/src/main/ets/components/mainpage/MainPage.ets
@Component
export struct MainPage {
@State message: string = 'HAR MainPage';
build() {
Column() {
Row() {
Text(this.message)
.fontSize(32)
.fontWeight(FontWeight.Bold)
}
.margin({ top: '32px' })
.height(56)
.width('624px')
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center, alignContent: FlexAlign.Center }) {
Column() {
Image($r('app.media.pic_empty')).width('33%')
Text($r('app.string.empty'))
.fontSize(14)
.fontColor($r('app.color.text_color'))
}
}.width('100%')
.height('90%')
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.page_background'))
}
}
HAR对外暴露的接口,在Index.ets导出文件中声明如下所示:
// library/Index.ets
export { MainPage } from './src/main/ets/components/mainpage/MainPage';
导出ts类和方法
通过export导出ts类和方法,支持导出多个ts类和方法,示例如下所示:
// library/src/main/ts/test.ets
export class Log {
static info(msg: string) {
console.info(msg);
}
}
export function func() {
return 'har func';
}
export function func2() {
return 'har func2';
}
HAR对外暴露的接口,在Index.ets导出文件中声明如下所示:
// library/Index.ets
export { Log } from './src/main/ts/test';
export { func } from './src/main/ts/test';
export { func2 } from './src/main/ts/test';
导出native方法
在HAR中也可以包含C++编写的so。对于so中的native方法,HAR通过以下方式导出,以导出liblibrary.so的加法接口add为例:
// library/src/main/ets/utils/nativeTest.ets
import native from 'liblibrary.so';
export function nativeAdd(a: number, b: number): number {
let result: number = native.add(a, b);
return result;
}
HAR对外暴露的接口,在Index.ets导出文件中声明如下所示:
// library/Index.ets
export { nativeAdd } from './src/main/ets/utils/nativeTest';
导出资源
在编译构建HAP时,DevEco Studio会从HAP模块及依赖的模块中收集资源文件,如果不同模块下的资源文件出现重名冲突时,DevEco Studio会按照以下优先级进行覆盖(优先级由高到低):
- AppScope(仅Stage模型支持)。
- HAP包自身模块。
- 依赖的HAR模块,如果依赖的多个HAR之间有资源冲突,会按照工程oh-package.json5中dependencies下的依赖顺序进行覆盖,依赖顺序在前的优先级较高。例如下方示例中dayjs和lottie中包含同名文件时,会优先使用dayjs中的资源。
说明
如果在AppScope/HAP模块/HAR模块的国际化目录中配置了资源,在相同的国际化限定词下,合并的优先级也遵循上述规则。同时,国际化限定词中配置的优先级高于在base中的配置。如:在AppScope的base中配置了资源字段,在HAR模块的en_US中配置了同样的资源字段,则在en_US的使用场景中,会更优先使用HAR模块中配置的资源字段。
// oh-package.json5
{
"dependencies": {
"dayjs": "^1.10.4",
"lottie": "^2.0.0"
}
}
使用
介绍如何配置HAR依赖,并引用HAR的ArkUI组件、接口、资源。
引用HAR前,需要先配置对HAR的依赖,详见引用HAR文件和资源。
引用HAR的ArkUI组件
HAR的依赖配置成功后,可以引用HAR的ArkUI组件。ArkUI组件的导入方式与ts的导入方式一致,通过import引入HAR导出的ArkUI组件,示例如下所示:
// entry/src/main/ets/pages/IndexSec.ets
import { MainPage } from 'library';
@Entry
@Component
struct IndexSec {
build() {
Row() {
// 引用HAR的ArkUI组件
MainPage()
}
.height('100%')
}
}
引用HAR的ts类和方法
通过import引用HAR导出的ts类和方法,示例如下所示:
// entry/src/main/ets/pages/Index.ets
import { Log } from 'library';
import { func } from 'library';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column() {
Text(this.message)
.fontFamily('HarmonyHeiTi')
.fontWeight(FontWeight.Bold)
.fontSize(32)
.fontWeight(700)
.fontColor($r('app.color.text_color'))
.textAlign(TextAlign.Start)
.margin({ top: '32px' })
.width('624px')
//引用HAR的ts类和方法
Button($r('app.string.button'))
.id('button')
.height(48)
.width('624px')
.margin({ top: '4%' })
.type(ButtonType.Capsule)
.fontFamily('HarmonyHeiTi')
.borderRadius($r('sys.float.ohos_id_corner_radius_button'))
.backgroundColor($r('app.color.button_background'))
.fontColor($r('sys.color.ohos_id_color_foreground_contrary'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.onClick(() => {
// 引用HAR的类和方法
Log.info('har msg');
this.message = 'func return: ' + func();
})
}
.width('100%')
.backgroundColor($r('app.color.page_background'))
.height('100%')
}
}
引用HAR的native方法
通过import引用HAR导出的native方法,示例如下所示:
// entry/src/main/ets/pages/Index.ets
import { nativeAdd } from 'library';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column() {
Text(this.message)
.fontFamily('HarmonyHeiTi')
.fontWeight(FontWeight.Bold)
.fontSize(32)
.fontWeight(700)
.fontColor($r('app.color.text_color'))
.textAlign(TextAlign.Start)
.margin({ top: '32px' })
.width('624px')
//引用HAR的native方法
Button($r('app.string.native_add'))
.id('nativeAdd')
.height(48)
.width('624px')
.margin({ top: '4%', bottom: '6%' })
.type(ButtonType.Capsule)
.fontFamily('HarmonyHeiTi')
.borderRadius($r('sys.float.ohos_id_corner_radius_button'))
.backgroundColor($r('app.color.button_background'))
.fontColor($r('sys.color.ohos_id_color_foreground_contrary'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.onClick(() => {
this.message = 'result: ' + nativeAdd(1, 2);
})
}
.width('100%')
.backgroundColor($r('app.color.page_background'))
.height('100%')
}
}
引用HAR的资源
通过$r引用HAR中的资源,例如在HAR模块的src/main/resources里添加字符串资源(在string.json中定义,name:hello_har)和图片资源(icon_har.png),然后在Entry模块中引用该字符串和图片资源的示例如下所示:
// entry/src/main/ets/pages/Index.ets
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column() {
// 引用HAR的字符串资源
Text($r('app.string.hello_har'))
.id('stringHar')
.fontFamily('HarmonyHeiTi')
.fontColor($r('app.color.text_color'))
.fontSize(24)
.fontWeight(500)
.margin({ top: '40%' })
List() {
ListItem() {
// 引用HAR的图片资源
Image($r('app.media.icon_har'))
.id('iconHar')
.borderRadius('48px')
}
.margin({ top: '5%' })
.width('312px')
}
.alignListItem(ListItemAlign.Center)
}
.width('100%')
.backgroundColor($r('app.color.page_background'))
.height('100%')
}
}
编译
HAR可以作为二方库和三方库提供给其他应用使用,如果需要对代码资产进行保护时,建议开启混淆能力。
混淆能力开启后,DevEco Studio在构建HAR时,会对代码进行编译、混淆及压缩处理,保护代码资产。
HAR模块原先默认开启混淆能力,会对API 10及以上的HAR模块,且编译模块为release时,自动进行简单的代码混淆;从DevEco Studio 5.0.3.600开始,新建工程默认关闭代码混淆功能,可以在HAR模块的build-profile.json5文件中的ruleOptions字段下的enable进行开启混淆,详情请见代码混淆,配置如下所示:
{
"apiType": "stageMode",
"buildOption": {
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
},
"consumerFiles": [
"./consumer-rules.txt"
]
}
}
},
],
"targets": [
{
"name": "default"
}
]
}
编译生成TS文件
说明
在HAR中使用Sendable时,开启该配置。
使用限制
在依赖TS HAR时,禁止引用TS HAR中的ArkUI组件。
HAR模块中arkts文件编译后,默认产物为js文件,想要将产物修改为ts文件,可以在HAR模块下的module.json5文件中将"metadata"字段下的"name"设置为“UseTsHar”,配置如下所示:
{
"module": {
"name": "TsClosedHar",
"type": "har",
"deviceTypes": [
"default",
"tablet",
"2in1"
],
"metadata": [
{
"name": "UseTsHar",
"value": "true"
}
]
}
}
发布
详见发布HAR。