鸿蒙 Stege模型 多模块应用
模块
一个鸿蒙应用可能包含一个或者多个功能模块,在 DevEcoStudio 工程中可以创建对应的一个或多个 Module。Module 又分为 “Ability” 和 “Library”两种类型,“Ability”类型的 Module 对应于编译后的 HAP(Harmony Ability Package);“Library” 类型的 Module 对应于 HAR (Harmony Archive),或者 HSP (Harmony Shared Package)
三类模块
HAP (Harmony Ability Package) | HAR (Harmony Archive) | HSP (Harmony Shared Package) | |
---|---|---|---|
功能说明及适用场合 | 分为 entry 和 feature;应用的功能模块,可以独立安装和运行 | 静态共享包,编译态复用。- 多包(HAP/HSP)引用相同的 HAR 时,会造成多包间代码和资源的重复拷贝,从而导致应用包膨大 | 动态共享包,运行时复用。- 当多包(HAP/HSP)同时引用同一个共享包时,可以避免 HAR 造成的多包间代码和资源的重复拷贝,从而减少小应用包大小 |
支持在配置文件中声明 UIAbility 组件与 ExtensionAbility 组件 | ✅ | ❎ | ❎ |
支持在配置文件中声明 pages 页面 | ✅ | ❎ | ✅ |
支持包含资源文件与.so 文件 | ✅ | ✅ | ✅ |
支持依赖其他 HAR 文件 | ✅ | ✅ | ✅ |
支持依赖其他 HSP 文件 | ✅ | ✅ | ✅ |
支持在设备上独立安装运行 | ✅ | ❎ | ❎ |
HAP
HAP(Harmony Ability Package)是应用安装和运行的基本单元。HAP 包是由代码、资源、第三方库、配置文件等打包生成的模块包;主要分为两种类型:entry 和 feature:
- entry:应用的主模块,作为应用的入口,提供了应用的基础功能;
- feature:应用的动态特性模块,作为应用能力的扩展,可以根据用户的需求和设备类型进行选择性安装;
应用程序包可以只包含一个基础的 entry 包,也可以包含一个基础的 entry 包和多个功能性的 feature 包
//module.json5
{"module": {"name": "video","type": "entry","mainElement": "VideoAbility"}
}
//module.json5
{"module": {"name": "mall","type": "feature","mainElement": "MallAbility"}
}
注意:不支持导出 HAP 中的接口和 ArkUI 组件,供其他 HAR/HSP 模块使用!!
HSP
HSP(Harmony Shared Package)是动态共享包,可以包含代码、C++库、资源和配置文件,通过 HSP 可以实现代码和资源的共享。HSP 不支持独立发布,而是跟随其宿主应用的 APP 包一起发布,与宿主应用同进程,具有相同的包名和生命周期。主要使用场景:
- 多 HAP 或者 HSP 共用的代码、资源可以使用 HSP,提高代码的可重用性和可维护性;
- 按需加载,HSP 包在运行时再按需加载;
- 元服务分包及预加载;
//module.json5
{"module": {"name": "mylib01","type": "shared","deviceTypes": ["phone", "tablet"],"deliveryWithInstall": true,"pages": "$profile:main_pages"}
}
HAR
HAR(Harmony Archive)是静态共享包,可以包含代码、C++库、资源和配置文件。通过 HAR 可以实现多个模块或多个工程共享 ArkUI 组件、资源等相关代码。使用场景:
- 导出公共 ArkUI 组件或 ts 类/方法供当前应用的其它 HAP 和 HSP 使用;
- 作为二方库,发布到 OHPM 私仓,供公司内部其他应用使用;
- 作为三方库,发布到 OHPM 中心仓,供其他应用使用;
//module.json5
{"module": {"name": "mylib02","type": "har","deviceTypes": ["default", "tablet"]}
}
注意:HAR 模块默认不提供 pages,也没有 UIAbility
HAP 模块跳转
模块内跳转
在同一个 HAP 中的多个 Page 间跳转:多个页面共用同一个窗口
//模块内多个页面间跳转
router.pushUrl({url: "pages/Details",
});
在同一个 HAP 中的多个 UIAbility 间跳转:每个页面都有独立的窗口
//模块内多个UIAbility间跳转
const want: Want = {deviceId: "", //可选,传空表示本设备bundleName: "cn.baidu.myapp", //必需,应用唯一标识moduleName: "entry", //可选,模块名称abilityName: "ChatAbility", //必需,UIAbility名称
};
let ctx = getContext(this) as common UIAbilityContext
ctx.startAbility(want)
跨 HAP 模块跳转
每个 HAP 上架到应用商店都是可以根据客户端设备情况独立安装的,如果希望跳转到其它模块,必须在当前模块的编译配置中声明“多 Hap 同时部署(Deploy Multi Hap)”
//跨多个HAP模块跳转
let want: Want = {deviceId: "", //传空表示本设备bundleName: "cn.baidu.myapp", //应用唯一标识moduleName: "mall", // *******模块名称*********abilityName: "MallAbility", //UIAbility名称
};let ctx = getContext(this) as common.UIAbilityContext;
ctx.startAbility(want);
跨模块的多个页面也都有各自的运行时窗口
使用 HSP
导出公共页面
HSP 模块中可以创建公共页面,并导出,从而供多个 HAP 来使用
//mylib01/src/main/ets/pages/Login.ets
@Entry
@Component
export struct Login {build() {Row() {Column() {Text('Library Page')}.width('100%')}.height('100%')}
}
//entry/src/main/ets/pages/Index.ets
router.pushUrl({url: "@bundle:cn.baidu.myapp/mylib01/ets/pages/Login",
});
URL 格式为:
@bundle:包名/模块名/路径/页面所在的文件名(不加.ets 后缀)
且“路径”中没有 src/main (部署态不存在这两个目录)!
注意:
必须在 HAP 模块的编译配置中声明“多 Hap 同时部署(Deploy Multi Hap)”,其中勾选 HSP 模块
说明:HSP 模块中是没有 UIAbility 的!只能运行在 HAP 提供的窗口中
导出公共组件
HSP 模块中可以创建公共组件,并导出,从而供多个 HAP 来使用
//mylib01/src/main/ets/components/TitleBar.ets
@Preview
@Component
export struct TitleBar {build() {Row() {Text('Title Bar')}.width('100%').height(45)}
}
//mylib01/Index.ets
export { TitleBar } from "./src/main/ets/components/TitleBar";
//entry/oh-package.json5
{"dependencies": {"mylib01": "file:../mylib01"}
}
//entry/src/main/ets/pages/Index.ets
import { TitleBar } from 'mylib01'@Entry
@Component
struct Index {build() {Column() {TitleBar()}}
}
导出公共对象和方法
HSP 模块中可以创建公共对象和方法,并导出,从而供多个 HAP 来使用
//mylib01/src/main/ets/util/Calc.ets
export function add(a: number, b: number) {return a + b;
}export function sub(a: number, b: number) {return a - b;
}
//mylib01/Index.ets
export { add, sub } from "./src/main/ets/utils/Calc";
//entry/oh-package.json5
{"dependencies": {"mylib01": "file:../mylib01"}
}
//entry/src/main/ets/pages/Index.ets
import { add } from 'mylib01'build() {Column() {Button('相加').onClick(_ => {add(10, 20)})}
}
使用 HAR
导出 pages 页面
HAR 不支持在配置文件中声明 pages 页面,但是可以包含 pages 页面,并通过命名路由的方式进行跳转
//mylib02/src/main/ets/pages/MyPage.ets
@Entry({ routeName: 'myPage' })
@Component
export struct MyPage {build() {Row() {Text('My Page')}.width('100%').height('100%')}
}
//mylib02/Index.ets
//命名路由页面无需导出
//entry/oh-package.json5
{"dependencies": {"mylib02": "file:../mylib02"}
}
//entry/src/main/ets/pages/Index.ets
import('mylib02/src/main/ets/pages/MyPage')@Entry
@Component
struct Index {build() {Button('跳转到HAR中的页面').onClick(_ => {router.pushNamedRoute({name: 'myPage', //页面名称params: {} //自定义的路由参数})})}
}
导出公共组件
HAR 模块中可以创建公共组件,并导出,从而供多个 HAP 来使用
//mylib02/src/main/ets/components/TitleBar.ets
@Preview
@Component
export struct TitleBar {build() {Row() {Text('Title Bar')}.width('100%').height(45)}
}
//mylib02/Index.ets
export { TitleBar } from "./src/main/ets/components/TitleBar";
//entry/oh-package.json5
{"dependencies": {"mylib02": "file:../mylib02"}
}
//entry/src/main/ets/pages/Index.ets
import { TitleBar } from 'mylib02'@Entry
@Component
struct Index {build() {Column() {TitleBar()}}
}
导出公共对象和方法
HAR 模块中可以创建公共对象和方法,并导出,从而供多个 HAP 来使用
//mylib02/src/main/ets/util/Calc.ets
export function add(a: number, b: number) {return a + b;
}export function sub(a: number, b: number) {return a - b;
}
//mylib02/Index.ets
export { add, sub } from "./src/main/ets/utils/Calc";
//entry/oh-package.json5
{"dependencies": {"mylib02": "file:../mylib02"}
}
//entry/src/main/ets/pages/Index.ets
import { add } from 'mylib02'build() {Column() {Button('相加').onClick(_ => {add(10, 20)})}
}