鸿蒙6.0应用开发面试——应用程序包问题
用户应用程序是指运行在设备操作系统之上,为用户提供特定服务的程序,简称“应用”。一个应用所对应的软件包文件,称为“应用程序包”。
【高心星出品】
文章目录
鸿蒙6.0应用开发面试——应用程序包问题
HAR与HSP包的区别是什么?
HAR(静态共享包)
编译时打包:代码和资源在构建阶段被完整复制到每个依赖它的HAP中。
启动即加载:随应用启动直接载入内存,调用时无额外开销。
适用场景:少量模块引用、对加载速度敏感的场景(如基础工具库)。
HSP(动态共享包)
运行时共享:仅存储一份实例,多个HAP在运行时动态加载同一份HSP。
按需加载:首次调用需查找、初始化,有性能损耗但避免重复拷贝。
适用场景:被大量HAP引用的公共模块(如UI组件库),可显著减少包体积。
HSP打包后,为什么会生成HAR包,它是否会导致App包大小膨胀?
HSP编译生成的HAR包仅包含配置文件和接口定义,不包含代码逻辑。该HAR包仅用于开发阶段,不会影响App包的大小。
从包管理的角度,保证代码安全的措施有哪些?
编译:编译时,HAR和HSP支持代码混淆。
打包:打包时为每个HSP/HAP单独签名,签名后的应用才允许安装。
安装:终端设备上的应用市场用于安装和卸载应用,不支持其他安装方式。
运行时:提供应用沙箱机制,这是一种以安全防护为目的的隔离机制,防止数据遭受恶意路径穿越访问。
HSP/HAR包中如何引用外部编译的so库文件?
-
libxxx.so库文件放入HAR或HSP的libs/arm64-v8a目录。设备类型不同时,需添加对应子目录。新版的arm64为libs/arm64-v8a,老版的arm64为libs/armeabi-v7a,x86模拟器为libs/x86_64。

-
在src/main/cpp/CMakeLists.txt文件中链接so库文件。例如:target_link_libraries(entry PUBLIC libxxx)
如何判断应用可被卸载?
1.使用bundleManager.getApplicationInfo获取应用程序信息。
2.ApplicationInfo具有removable属性,可用于判断应用是否可卸载。
Entry模块的HAP和Feature模块的HAP在使用和功能上的区别是什么?
1.Entry类型的HAP:是应用的主模块,在module.json5配置文件中的type标签配置为“entry”类型。在同一个应用中,同一设备类型只支持一 个Entry类型的HAP,通常用于实现应用的入口界面、入口图标、主特性功能等。
2.Feature类型的HAP:是应用的动态特性模块,在module.json5配置文件中的type标签配置为“feature”类型。一个应用程序包可以包含一个或多个Feature类型的HAP,也可以不包含;Feature类型的HAP通常用于实现应用的特性功能,可以配置成按需下载安装,也可以配置成随Entry类型的HAP一起下载安装。
HSP包编译之后会生成什么文件?
HSP包编译后会生成.hsp文件和.har文件。.hsp文件用于安装,.har文件仅暴露接口,不包含具体实现。
HSP包中导出的方法头文件位于.har文件中,实现在.hsp文件中。
HAR如何转换为HSP?
HAR转为HSP主要是通过修改配置文件实现。具体步骤如下:
- 在HAR的module.json5中,将type字段的值改为“shared”,并配置deliveryWithInstall字段为“true”。
- 若HSP需要对外声明可跳转的页面,在module.json5文件中添加pages字段,并在“resources/base”目录下创建“profile/main_pages.json”文件,配置“src”。
- 将HAR的hvigorfile.ts文件中的“harTasks”更改为“hspTasks”。
- HAR的build-profile.json5文件中默认生成consumerFiles字段,该项字段HAR可配置,为默认导出的混淆加固规则,需要删除。
一个HSP模块如何快速切换成HAR模块?
1.在HSP下的module.json5中,把"type": “shared"修改为"type”: “har”,删除"deliveryWithInstall"、"pages"字段;
2.删除HSP下的oh-package.json5中"packageType"字段;
3.删除HSP中的页面,如果要以页面的形式使用到的话,就需要改为命名路由的写法;
4.然后再找到HSP下的hvigorfile.ts文件,将里面的hspTasks改为harTasks;
5.最后编译该模块即可。
编译过程中遇到其他错误时,根据提示找到对应位置并进行修改。
如何实现跨模块的页面跳转功能?
在业务体系庞大或复杂的情况下,会将业务拆分成多个子业务模块,每个子业务模块为一个HAR/HSP。在该场景下,存在从主业务入口跳转到不同子页面模块,或从一个子业务模块A页面跳转到另一个子业务模块B页面的需求。例如,从应用首页跳转到登录子业务模块页面。针对该场景,有以下三种解决方案:
-
方案一:使用router的命名路由接口router.pushNamedRoute()跳转。
-
方案二:使用navigation组件跳转。
以从应用入口模块的页面NavigationPage跳转到Login子业务模块页面LoginPage为例。主要包含以下步骤:
-
在Login模块中开发自定义组件LoginPage作为路由跳转目的地,并对外导出。
@Component export struct LoginPage { @Consume('pathStack') pathStack: NavPathStack; @State message: string = 'Login Page'; build() { NavDestination() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) } .width('100%') .height('100%') } .onBackPressed(() => { this.pathStack.pop(); return true; }) } }代码逻辑走读:
- 组件定义:使用
@Component装饰器定义了一个名为LoginPage的结构体组件。 - 依赖注入:通过
@Consume('pathStack')注解,组件从其父组件中获取NavPathStack实例,用于页面导航。 - 状态声明:使用
@State声明了一个字符串类型的状态变量message,初始值为'Login Page'。 - UI构建:在
build方法中,使用NavDestination构建导航目标,内部包含一个Column布局。 - 文本显示:在
Column中,使用Text组件显示message变量的值,并设置字体大小为50,字体加粗。 - 布局设置:设置
Column的宽度和高度为100%。 - 返回按钮处理:使用
.onBackPressed方法注册返回按钮的事件处理函数,当返回按钮被按下时,调用pathStack.pop()方法返回到上一个页面,并返回true表示事件已被处理。
- 组件定义:使用
-
在Login模块的入口文件Index.ets中导出自定义组件。
export { LoginPage } from './src/main/ets/pages/loginPage'; -
在入口模块的oh-package.json5文件中添加对Login模块的依赖项。
{ // ... "dependencies": { "@ohos/login": "file:../LoginModule" } } -
入口模块导入Login模块的自定义组件,并添加到Navigation组件的路由表中。
// Import a custom component of the Login module import { LoginPage } from '@ohos/login'; @Entry @Component struct NavigationPage { @Provide('pathStack') pathStack: NavPathStack = new NavPathStack(); @Builder pageMap(name: string) { if (name === 'loginPage') { LoginPage() } } build() { Navigation(this.pathStack) { Button('jump to login page') .onClick(() => { // The second parameter of NavPathInfo is a custom parameter that can be used for message transfer let pathInfo: NavPathInfo = new NavPathInfo('loginPage', new Object()); this.pathStack.pushDestination(pathInfo, true); }) } .navDestination(this.pageMap) } }代码逻辑走读:
- 导入自定义组件:
- 代码首先导入了
LoginPage组件,这是从@ohos/login模块中导入的。
- 代码首先导入了
- 定义
NavigationPage组件:- 使用
@Entry和@Component装饰器定义了一个名为NavigationPage的组件。
- 使用
- 提供
pathStack:- 使用
@Provide装饰器定义了一个名为pathStack的NavPathStack实例,用于管理页面导航路径。
- 使用
- 定义
pageMap方法:- 使用
@Builder装饰器定义了一个名为pageMap的方法,该方法根据传入的name参数决定返回哪个组件。如果name是'loginPage',则返回LoginPage组件。
- 使用
- 构建UI:
- 在
build方法中,使用Navigation组件和Button组件构建了一个UI。 Navigation组件使用pathStack来管理导航路径。Button组件显示一个按钮,点击后会创建一个NavPathInfo对象,并使用pathStack.pushDestination方法导航到loginPage。
- 在
- 设置导航目标:
- 使用
.navDestination(this.pageMap)设置导航的目标为pageMap方法返回的组件。
- 使用
- 导入自定义组件:
-
-
方案三:使用基于navigation组件的自定义路由框架跳转。
方案二虽然可以实现跨模块跳转的功能,但当模块间跳转需求增多,各个模块间将存在非常复杂的依赖关系,甚至会导致多个HAR/HSP间循环依赖。为了解决模块间的强耦合关系,并且提升页面加载性能。
如何在应用内共享HSP?
如需在应用内共享HSP,请将HSP共享包上传至私仓。动态共享包HSP不能直接发布在私仓内,需要先转换为.tgz包。请按以下操作编译生成*.tgz包。
-
将编译模式设为release。

-
选中HSP模块的根目录,点击Build > Make Module {libraryName},启动构建。

-
构建完成后,build目录下生成HSP包产物,其中.tgz用来上传至私仓。

- 上传到仓库,然后使用
ohpm install命令将依赖安装到工程的oh-package.json5文件的dependencies字段中,即可查看对外共享的 HSP 方法。
更多推荐



所有评论(0)