聚焦应用常用功能,提升用户体验与分发效率

随着HarmonyOS应用的持续发展,应用的功能将越来越丰富,实际上80%的用户使用时长都会集中在20%的特性上,其余的功能可能也仅仅是面向部分用户。

用户在下载应用时,如果应用包含大量的功能和资源,可能会导致下载时间过长;应用如果包含许多不常用或特定用户群体才需要的功能,这些功能会占用用户设备的存储空间;如果应用体积庞大,启动和运行速度可能会受到影响。

为了避免用户首次下载应用耗时过长,及过多占用用户空间,HarmonyOS SDK 应用市场服务(Store Kit)提供 产品特性按需分发的能力,能够提供动态分发和资源拆分,支持用户按需动态下载自己所需的增强特性,减少开发者应用的分发成本,将精力放在维护和分发用户实际需要的功能模块,帮助提高分发效率。

基本概念

按需分发:一个应用程序被打包成多个安装包,安装包包含了所有的应用程序代码和静态资源。用户从应用市场下载的应用只包含基本功能的安装包,当用户需要使用增强功能时,相应安装包将会从服务器下载到设备上。

开发步骤

获取模块安装信息

1.导入moduleInstallManager模块及相关公共模块。

javascript 复制代码
import { moduleInstallManager } from '@kit.StoreKit';

2.构造参数。

入参为需要查询的模块名称。

ini 复制代码
const moduleName: string = 'AModule';

3.调用getInstalledModule方法,将步骤2中构造的参数传入模块中的getInstalledModule方法。

ini 复制代码
const moduleInfo: moduleInstallManager.InstalledModule = moduleInstallManager.getInstalledModule(moduleName);

创建按需加载的请求实例

1.导入moduleInstallManager模块及相关公共模块。

python 复制代码
import { moduleInstallManager } from '@kit.StoreKit';
import type { common } from '@kit.AbilityKit';

2.构造参数。

入参为当前应用的上下文context,只支持UIAbilityContext和ExtensionContext类型的上下文,其中UIAbilityContext类型的上下文是要校验当前应用是否在前台,如果不在前台,则会被拒绝调用。

kotlin 复制代码
const context: common.UIAbilityContext | common.ExtensionContext = getContext(this) as common.UIAbilityContext;

3.调用createModuleInstallRequest方法,将步骤2中构造的参数依次传入模块中的createModuleInstallRequest方法。

ini 复制代码
const myModuleInstallProvider: moduleInstallManager.ModuleInstallProvider = new moduleInstallManager.ModuleInstallProvider();
const myModuleInstallRequest: moduleInstallManager.ModuleInstallRequest = myModuleInstallProvider.createModuleInstallRequest(context);

请求按需加载的接口

1.导入moduleInstallManager模块及相关公共模块。

python 复制代码
import type { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { moduleInstallManager } from '@kit.StoreKit';

2.构造参数。

入参为当前要按需加载的模块名。

ini 复制代码
const moduleNameA: string = 'AModule';
const moduleNameB: string = 'BModule';

3.调用ModuleInstallRequest中的addModule方法,将步骤2中构造的参数依次传入模块中的addModule方法。

ini 复制代码
let myModuleInstallRequest: moduleInstallManager.ModuleInstallRequest;
try {
  const myModuleInstallProvider: moduleInstallManager.ModuleInstallProvider = new moduleInstallManager.ModuleInstallProvider();
  const context: common.UIAbilityContext | common.ExtensionContext = getContext(this) as common.UIAbilityContext;
  myModuleInstallRequest = myModuleInstallProvider.createModuleInstallRequest(context);
  const aResult: moduleInstallManager.ReturnCode = myModuleInstallRequest.addModule(moduleNameA);
  const bResult: moduleInstallManager.ReturnCode = myModuleInstallRequest.addModule(moduleNameB);
  hilog.info(0, 'TAG', 'aResult:' + aResult + ' bResult:' + bResult);
} catch (error) {
  hilog.error(0, 'TAG', `addModule onError.code is ${error.code}, message is ${error.message}`);
}

4.调用fetchModules方法,将步骤三中的myModuleInstallRequest传入模块中的fetchModules方法。

javascript 复制代码
try {
  moduleInstallManager.fetchModules(myModuleInstallRequest)
    .then((data: moduleInstallManager.ModuleInstallSessionState) => {
      hilog.info(0, 'TAG', 'Succeeded in fetching Modules data.');
    })
} catch (error) {
  hilog.error(0, 'TAG', `fetching Modules onError.code is ${error.code}, message is ${error.message}`);
}

使用动态模块

假如应用A由entry.hap、AModulelib.hsp两个包组成,其中entry是基础包,AModulelib扩展是功能包(创建方式请参考应用程序包开发与使用)。通过应用市场下载安装只会下载安装entry包,在entry包里面可以通过fetchModules接口动态下载AModulelib包,并使用动态import技术调用AModulelib里的方法和组件。

AModulelib中主要实现如下:

  • 在动态模块AModulelib中定义add方法和DateComponent组件。其中add方法用于计算加法,DateComponent用于显示文本。

Calc.ets定义如下:

typescript 复制代码
export function add(a:number, b:number) {
  return a + b;
}

DateComponent.ets定义如下:

scss 复制代码
@Component
struct DateComponent {
  build() {
    Column() {
      Text('我是AModulelib中的组件')
        .margin(10);
    }
    .width(300).backgroundColor(Color.Yellow);
  }
}


@Builder
export function showDateComponent() {
  DateComponent()
}
  • 在AModulelib的AModulelib/Index.ets中导出add方法和showDateComponent方法。

    export { add } from './src/main/ets/utils/Calc'; export { showDateComponent } from './src/main/ets/components/DateComponent';

entry中主要实现如下:

  • 在entry基础模块中,增加动态依赖配置。entry的oh-package.json5中使用dynamicDependencies来动态依赖AModulelib模块。

    { "dynamicDependencies": { "AModulelib": "file:../AModulelib" } }

  • 在entry中使用动态模块AModulelib模块里面的方法和组件。在调用AModulelib中的功能前需要判断AModulelib是否已经加载,未加载时请参考请求按需加载的接口完成加载。

    import { moduleInstallManager } from '@kit.StoreKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { BusinessError, Callback } from '@kit.BasicServicesKit'; import { common } from '@kit.AbilityKit'; import { promptAction } from '@kit.ArkUI';

    const TAG: string = 'TAG';

    @Entry @Component struct Index { @BuilderParam AModulelibComponent: Function; @State countTotal: number = 0; @State isShow: boolean = false;

    build() { Row() { Column() { Button(调用增量模块中的add功能:3+6) .onClick(() => { this.initAModulelib(() => { import('AModulelib').then((ns: ESObject) => { this.countTotal = ns.add(3, 6); }).catch((error: BusinessError) => { hilog.error(0, 'TAG', add onError.code is ${error.code}, message is ${error.message}); }) }) }); Text('计算结果:' + this.countTotal) .margin(10); Button(调用增量模块中的showDateComponent功能) .onClick(() => { this.initAModulelib(() => { import('AModulelib').then((ns: ESObject) => { this.AModulelibComponent = ns.showDateComponent; this.isShow = true; }).catch((error: BusinessError) => { hilog.error(0, 'TAG', showDateComponent onError.code is ${error.code}, message is ${error.message}); }) }) }).margin({ top: 10, bottom: 10 }); if (this.isShow) { this.AModulelibComponent() } } .width('100%') } .height('100%') }

    private showToastInfo(msg: string) { promptAction.showToast({ message: msg, duration: 2000 }); }

    /**

    • 检查是否已加载AModulelib包
    • @param successCallBack 回调 */ private initAModulelib(successCallBack: Callback): void { try { const result: moduleInstallManager.InstalledModule = moduleInstallManager.getInstalledModule('AModulelib'); if (result?.installStatus === moduleInstallManager.InstallStatus.INSTALLED) { hilog.info(0, TAG, 'AModulelib installed'); successCallBack && successCallBack(); } else { // AModulelib模块未安装, 需要调用fetchModules下载AModulelib模块。 hilog.info(0, TAG, 'AModulelib not installed'); this.fetchModule('AModulelib', successCallBack) } } catch (error) { hilog.error(0, 'TAG', getInstalledModule onError.code is ${error.code}, message is ${error.message}); } }

    /**

    • 添加监听事件
    • @param successCallBack 回调 / private onListenEvents(successCallBack: Callback): void { const timeout = 3 * 60; //单位秒, 默认最大监听时间为30min(即3060秒) moduleInstallManager.on('moduleInstallStatus', (data: moduleInstallManager.ModuleInstallSessionState) => { // 返回成功 if (data.taskStatus === moduleInstallManager.TaskStatus.INSTALL_SUCCESSFUL) { successCallBack && successCallBack(); this.showToastInfo('install success'); } }, timeout) }

    /**

    • 加载指定包
    • @param moduleName 需要加载的安装包名称
    • @param successCallBack 回调 */ private fetchModule(moduleName: string, successCallBack: Callback) { try { hilog.info(0, TAG, 'handleFetchModules start'); const context = getContext(this) as common.UIAbilityContext; const moduleInstallProvider: moduleInstallManager.ModuleInstallProvider = new moduleInstallManager.ModuleInstallProvider(); const moduleInstallRequest: moduleInstallManager.ModuleInstallRequest = moduleInstallProvider.createModuleInstallRequest(context); if (!moduleInstallRequest) { hilog.warn(0, TAG, 'moduleInstallRequest is empty'); return; } moduleInstallRequest.addModule(moduleName); moduleInstallManager.fetchModules(moduleInstallRequest) .then((data: moduleInstallManager.ModuleInstallSessionState) => { hilog.info(0, TAG, 'Succeeded in fetching Modules result.'); if (data.code === moduleInstallManager.RequestErrorCode.SUCCESS) { this.onListenEvents(successCallBack) } else { hilog.info(0, TAG, 'fetchModules failure'); } }) .catch((error: BusinessError) => { hilog.error(0, 'TAG', fetchModules onError.code is ${error.code}, message is ${error.message}); }) } catch (error) { hilog.error(0, 'TAG', handleFetchModules onError.code is ${error.code}, message is ${error.message}); } } }

行业拓展

分享一个面向研发人群使用的前后端分离的低代码软件------JNPF

基于 Java Boot/.Net Core双引擎,它适配国产化,支持主流数据库和操作系统,提供五十几种高频预制组件,内置了常用的后台管理系统使用场景和实用模版,通过简单的拖拉拽操作,开发者能够高效完成软件开发,提高开发效率,减少代码编写工作。

JNPF基于SpringBoot+Vue.js,提供了一个适合所有水平用户的低代码学习平台,无论是有经验的开发者还是编程新手,都可以在这里找到适合自己的学习路径。

此外,JNPF支持全源码交付,完全支持根据公司、项目需求、业务需求进行二次改造开发或内网部署,具备多角色门户、登录认证、组织管理、角色授权、表单设计、流程设计、页面配置、报表设计、门户配置、代码生成工具等开箱即用的在线服务。

相关推荐
巴巴_羊几秒前
React Redux
开发语言·前端·javascript
Mintopia1 分钟前
Node.js 中的this
前端·javascript·node.js
Mike_jia2 分钟前
一篇文章带你了解一款强大的开源跨平台远程桌面管理工具---XPipe
前端·开源
._Ha!n.4 分钟前
React基础知识一
前端·react.js
Mintopia7 分钟前
深入理解 Three.js 中 Shader 的使用及示例
前端·javascript·three.js
睡觉zzz8 分钟前
React写ai聊天对话,如何实现聊天makedown输出转化
前端·人工智能·react.js
iOS阿玮9 分钟前
截止目前已有15.6w应用惨遭下架,你的应用还好么?
前端·app·apple
半旧51810 分钟前
【重构谷粒商城12】npm快速入门
前端·重构·npm
snakeshe101012 分钟前
剖析 React Commit 阶段:详解工作流程与三大核心模块
前端
爱生活的前端狗13 分钟前
一次大批量处理视频文件的性能优化记录
前端·javascript·vue.js