三层工程结构
项目里采用的工程结构是官方推荐的“三层工程结构”,本质上和Android工程里的结构是类似的。如下图HMOSWorld里的工程结构:
1、common(公共能力层):
该路径下的各个module是一些公共基础能力,比如工具库、公共配置、通用常量、自定义基础组件等。
common路径下的各个module可以根据具体的module设计需求,在创建时可以选择Shared Library或Static Library,选择了Static Library创建的后续需编译成一个HAR包。该路径下的module们只可以被products或features路径下的module依赖,不可以反向依赖。该路径下的module之间是可以横向调用的。
注意:a、选择Shared Library创建的module,在后续编译时,会生成一个.hsp文件,同时其内部的使用export关键字修饰的class、interface、function等可导出项还会被组合一起打一个.har包。各个宿主module通过该.har来引用HSP里的导出项,但是在进程中该HSP的代码只有一份,大家共享。
b、选择Static Library创建的module,在后续编译时,该module会被打成一个har包,凡是引用了该module里的可导出项或资源的宿主module,在后续打出的hap包里都会拥有该har包。要注意避免引入过多的无用代码。
2、features(基础特性层/业务模块层):
该路径下一般是各个业务模块,各个module高内聚、低耦合,可以供products层的各个entry选择性地引用,以实现灵活地部署。不需要单独部署的module通常会被编译为HAR包,供products层或features层的其它module使用。需要单独部署的module通常会被编译为Feature类型的HAP包,和products下Entry类型的HAP包进行组合部署。features层里的各个module可以横向调用及依赖common层,同时可以被products层里的不同设备形态的HAP(可以认为是不同的项目)所依赖,但是不能反向依赖products层里的entry module。
在创建时,选择前面图中的Empty Ability,选择feature。
3、products(产品定制层):
该路径下的各个entry module是在不同的设备情况下app应用的入口,每个module会针对不同的设备形态进行不同的功能和特性集成。
它们各自被编译为一个Entry类型的HAP包,作为应用主入口。products层不可以横向调用。
注意:整个代码工程最终会构建出一个APP包,应用以APP包的形式发布到应用市场中。
引用module
在工程内上层引用下层的module时
有两种简单的操作方式:
a、在Terminal窗口中,执行如下命令进行安装,IDE会在引用方module里的oh-package.json5中自动添加依赖。
比如entry要引用不同路径下的utils,utils要引用同路径下的constants:
cd entry 或 cd ../common/utils// 切到entry module目录下 或 切到common路径下的utils module目录下
ohpm install ../common/utils 或 ohpm install ../constants// 把utils module引用到entry module中 或 把同为common路径下的constants module引用到utils module中
结果如下,在oh-package.json5文件中的dependencies里会生成依赖项:
{
"name": "entry",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "",
"author": "",
"license": "",
"dependencies": {
"@ohos/utils": "file:../common/utils" // key为utils module的name,value是utils module的路径
},
"devDependencies": {},
"dynamicDependencies": {}
}
// 或者
{
"name": "@ohos/utils",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "Index.ets",
"author": "",
"license": "Apache-2.0",
"dependencies": {
"constants": "file:../constants" // key为同路径下的constants module的name,value是constants module的路径
},
"devDependencies": {},
"dynamicDependencies": {}
}
b、直接在entry或utils下的oh-package.json5文件中手动添加依赖项,然后sync project。
引用社区库时
社区库是指由代码贡献者已经上架到ohpm中心供其他开发者下载使用的库,可以通过如下两种方式设置对ohpm仓三方包的依赖信息,这里推荐第一种。
(下面步骤以@ohos/lottie三方库举例):
方式一:在Terminal窗口中,执行如下命令安装三方包,DevEco Studio会自动在当前module中的oh-package.json5中自动添加三方包依赖。
ohpm install @ohos/lottie
结果示例:
{
"name": "entry",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "",
"author": "",
"license": "",
"dependencies": {
"@ohos/utils": "file:../common/utils",
"@ohos/lottie": "^2.0.12" // 注意:value里版本号前面有个符合^
},
"devDependencies": {},
"dynamicDependencies": {}
}
方式二:在工程的某个module中的oh-package.json5文件中设置三方包依赖,配置示例如下:
"dependencies": {
"@ohos/lottie": "^2.0.12"
}
其实是跟上面的步骤一样的,只是手动处理下而已。
module的name里包含@ohos
在一个module里的oh-package.json5文件中,name字段对应的字符串值是用于设置该module的名称的。如果名称中包含了@ohos/这样的字样,表明这是一个属于鸿蒙操作系统生态里(ohpm仓库)提供的可供三方应用使用的库。‘@ohos’命名标识是用于区分是社区库提供的模块还是用户工程里自定义的其他模块。
例如,我们想要引用一个社区库时,如网络模块axios。在提供方工程的axios module里,它的oh-package.json5中的name应该这样写:
{
"name": "@ohos/axios",
"description": "Axios ,是一个基于 promise 的网络请求库。本库。。。",
// ....
}
在我们的代码中就可以通过@ohos/axios来引用这个模块了,这有助于避免与我们自己工程里的同名模块发生冲突,我们工程里引用axios模块的module里的oh-package.json5文件如下:
{
"name": "entry",
// ...
"dependencies": {
"constants": "file:../constants", // 自己工程里的constants module
"@ohos/axios": "^2.2.3" // 发布到ohos社区库里的开源库axios
}
}
应用程序包的结构
工程里的多module机制
在进行应用开发时,一个应用工程中通常包含一个或多个Module。Module中包含了源代码、资源文件、第三方库及应用/服务配置文件,每一个Module都可以独立进行编译和运行。
Module分为“Ability”和“Library”两种类型:
“Ability”类型的Module编译后生成HAP包,type为entry或feature。
“Library”类型的Module编译后生成HAR包,type为har或shared,shared的同时还生成hsp包。
不同类型的hap包
HarmonyOS应用是以APP Pack的形式发布的,app包里包含了一个或多个hap包。HAP是HarmonyOS应用在安装时的基本单位,HAP可以分为Entry和Feature两种类型:
1、Entry类型的HAP:即应用的主模块。在同一个应用中,同一设备类型只支持一个Entry类型的HAP,通常用于实现应用的入口界面、入口图标、主特性功能等。
注意:不同的设备形态,比如手机(phone)和平板(tablet)属于不同的形态,是分别有不同的Entry类型的hap包的,但是它们都在同一个app pack中,应用是以pack上架应用市场的,在不同的设备形态上的应用市场中可以分别下载安装各自对应的Entry类型的hap包。
2、Feature类型的HAP:应用的动态特性模块。Feature类型的HAP通常用于实现应用的特性功能,一个应用程序包可以包含一个或多个Feature类型的HAP,也可以不包含。
编译态的包结构
不同类型的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中。
发布态的包结构
每个应用(app pack)中至少包含了一个.hap文件,同时可能包含若干个.hsp文件,也可能不含。一个应用中的所有的.hap与.hsp文件合在一起称为Bundle,它的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等信息。
所以,发布态的包结构里包含了:1个entry.hap、0个或多个feature.hap、0个或多个library.hsp、pack.info。
打包-上架-下载安装的流程如下:
注意:
1、App Pack是发布上架到应用市场的基本单元,但是不能在设备上直接安装和运行。
2、在应用签名、云端分发、端侧安装时,都是以HAP/HSP为单位进行签名、分发和安装的。
结语:希望每一次梳理-总结都能带给你我一定的收获。。。