找回密码
 立即注册
首页 业界区 业界 聚焦应用常用功能,提升用户体验与分发效率 ...

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

俏挺喳 2025-6-2 00:33:28
随着HarmonyOS应用的持续发展,应用的功能将越来越丰富,实际上80%的用户使用时长都会集中在20%的特性上,其余的功能可能也仅仅是面向部分用户。
用户在下载应用时,如果应用包含大量的功能和资源,可能会导致下载时间过长;应用如果包含许多不常用或特定用户群体才需要的功能,这些功能会占用用户设备的存储空间;如果应用体积庞大,启动和运行速度可能会受到影响。
为了避免用户首次下载应用耗时过长,及过多占用用户空间,HarmonyOS SDK 应用市场服务(Store Kit)提供 产品特性按需分发的能力,能够提供动态分发和资源拆分,支持用户按需动态下载自己所需的增强特性,减少开发者应用的分发成本,将精力放在维护和分发用户实际需要的功能模块,帮助提高分发效率。
基本概念

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

获取模块安装信息

1.导入moduleInstallManager模块及相关公共模块。
  1. import { moduleInstallManager } from '@kit.StoreKit';
复制代码
2.构造参数。
入参为需要查询的模块名称。
  1. const moduleName: string = 'AModule';
复制代码
3.调用getInstalledModule方法,将步骤2中构造的参数传入模块中的getInstalledModule方法。
  1. const moduleInfo: moduleInstallManager.InstalledModule = moduleInstallManager.getInstalledModule(moduleName);
复制代码
创建按需加载的请求实例

1.导入moduleInstallManager模块及相关公共模块。
  1. import { moduleInstallManager } from '@kit.StoreKit';
  2. import type { common } from '@kit.AbilityKit';
复制代码
2.构造参数。
入参为当前应用的上下文context,只支持UIAbilityContext和ExtensionContext类型的上下文,其中UIAbilityContext类型的上下文是要校验当前应用是否在前台,如果不在前台,则会被拒绝调用。
  1. const context: common.UIAbilityContext | common.ExtensionContext = getContext(this) as common.UIAbilityContext;
复制代码
3.调用createModuleInstallRequest方法,将步骤2中构造的参数依次传入模块中的createModuleInstallRequest方法。
  1. const myModuleInstallProvider: moduleInstallManager.ModuleInstallProvider = new moduleInstallManager.ModuleInstallProvider();
  2. const myModuleInstallRequest: moduleInstallManager.ModuleInstallRequest = myModuleInstallProvider.createModuleInstallRequest(context);
复制代码
请求按需加载的接口

1.导入moduleInstallManager模块及相关公共模块。
  1. import type { common } from '@kit.AbilityKit';
  2. import { hilog } from '@kit.PerformanceAnalysisKit';
  3. import { moduleInstallManager } from '@kit.StoreKit';
复制代码
2.构造参数。
入参为当前要按需加载的模块名。
  1. const moduleNameA: string = 'AModule';
  2. const moduleNameB: string = 'BModule';
复制代码
3.调用ModuleInstallRequest中的addModule方法,将步骤2中构造的参数依次传入模块中的addModule方法。
  1. let myModuleInstallRequest: moduleInstallManager.ModuleInstallRequest;
  2. try {
  3.   const myModuleInstallProvider: moduleInstallManager.ModuleInstallProvider = new moduleInstallManager.ModuleInstallProvider();
  4.   const context: common.UIAbilityContext | common.ExtensionContext = getContext(this) as common.UIAbilityContext;
  5.   myModuleInstallRequest = myModuleInstallProvider.createModuleInstallRequest(context);
  6.   const aResult: moduleInstallManager.ReturnCode = myModuleInstallRequest.addModule(moduleNameA);
  7.   const bResult: moduleInstallManager.ReturnCode = myModuleInstallRequest.addModule(moduleNameB);
  8.   hilog.info(0, 'TAG', 'aResult:' + aResult + ' bResult:' + bResult);
  9. } catch (error) {
  10.   hilog.error(0, 'TAG', `addModule onError.code is ${error.code}, message is ${error.message}`);
  11. }
复制代码
4.调用fetchModules方法,将步骤三中的myModuleInstallRequest传入模块中的fetchModules方法。
  1. try {
  2.   moduleInstallManager.fetchModules(myModuleInstallRequest)
  3.     .then((data: moduleInstallManager.ModuleInstallSessionState) => {
  4.       hilog.info(0, 'TAG', 'Succeeded in fetching Modules data.');
  5.     })
  6. } catch (error) {
  7.   hilog.error(0, 'TAG', `fetching Modules onError.code is ${error.code}, message is ${error.message}`);
  8. }
复制代码
使用动态模块

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

  • 在动态模块AModulelib中定义add方法和DateComponent组件。其中add方法用于计算加法,DateComponent用于显示文本。
Calc.ets定义如下:
  1. export function add(a:number, b:number) {
  2.   return a + b;
  3. }
复制代码
DateComponent.ets定义如下:
  1. @Component
  2. struct DateComponent {
  3.   build() {
  4.     Column() {
  5.       Text('我是AModulelib中的组件')
  6.         .margin(10);
  7.     }
  8.     .width(300).backgroundColor(Color.Yellow);
  9.   }
  10. }
  11. @Builder
  12. export function showDateComponent() {
  13.   DateComponent()
  14. }
复制代码

  • 在AModulelib的AModulelib/Index.ets中导出add方法和showDateComponent方法。
  1. export { add } from './src/main/ets/utils/Calc';
  2. export { showDateComponent } from './src/main/ets/components/DateComponent';
复制代码
entry中主要实现如下:

  • 在entry基础模块中,增加动态依赖配置。entry的oh-package.json5中使用dynamicDependencies来动态依赖AModulelib模块。
  1. {
  2.   "dynamicDependencies": {
  3.     "AModulelib": "file:../AModulelib"
  4.   }
  5. }
复制代码

  • 在entry中使用动态模块AModulelib模块里面的方法和组件。在调用AModulelib中的功能前需要判断AModulelib是否已经加载,未加载时请参考请求按需加载的接口完成加载。
  1. import { moduleInstallManager } from '@kit.StoreKit';
  2. import { hilog } from '@kit.PerformanceAnalysisKit';
  3. import { BusinessError, Callback } from '@kit.BasicServicesKit';
  4. import { common } from '@kit.AbilityKit';
  5. import { promptAction } from '@kit.ArkUI';
  6. const TAG: string = 'TAG';
  7. @Entry
  8. @Component
  9. struct Index {
  10.   @BuilderParam AModulelibComponent: Function;
  11.   @State countTotal: number = 0;
  12.   @State isShow: boolean = false;
  13.   build() {
  14.     Row() {
  15.       Column() {
  16.         Button(`调用增量模块中的add功能:3+6`)
  17.           .onClick(() => {
  18.             this.initAModulelib(() => {
  19.               import('AModulelib').then((ns: ESObject) => {
  20.                 this.countTotal = ns.add(3, 6);
  21.               }).catch((error: BusinessError) => {
  22.                 hilog.error(0, 'TAG', `add onError.code is ${error.code}, message is ${error.message}`);
  23.               })
  24.             })
  25.           });
  26.         Text('计算结果:' + this.countTotal)
  27.           .margin(10);
  28.         Button(`调用增量模块中的showDateComponent功能`)
  29.           .onClick(() => {
  30.             this.initAModulelib(() => {
  31.               import('AModulelib').then((ns: ESObject) => {
  32.                 this.AModulelibComponent = ns.showDateComponent;
  33.                 this.isShow = true;
  34.               }).catch((error: BusinessError) => {
  35.                 hilog.error(0, 'TAG', `showDateComponent onError.code is ${error.code}, message is ${error.message}`);
  36.               })
  37.             })
  38.           }).margin({
  39.           top: 10, bottom: 10
  40.         });
  41.         if (this.isShow) {
  42.           this.AModulelibComponent()
  43.         }
  44.       }
  45.       .width('100%')
  46.     }
  47.     .height('100%')
  48.   }
  49.   private showToastInfo(msg: string) {
  50.     promptAction.showToast({
  51.       message: msg,
  52.       duration: 2000
  53.     });
  54.   }
  55.   /**
  56.    * 检查是否已加载AModulelib包
  57.    *
  58.    * @param successCallBack 回调
  59.    */
  60.   private initAModulelib(successCallBack: Callback<void>): void {
  61.     try {
  62.       const result: moduleInstallManager.InstalledModule = moduleInstallManager.getInstalledModule('AModulelib');
  63.       if (result?.installStatus === moduleInstallManager.InstallStatus.INSTALLED) {
  64.         hilog.info(0, TAG, 'AModulelib installed');
  65.         successCallBack && successCallBack();
  66.       } else {
  67.         // AModulelib模块未安装, 需要调用fetchModules下载AModulelib模块。
  68.         hilog.info(0, TAG, 'AModulelib not installed');
  69.         this.fetchModule('AModulelib', successCallBack)
  70.       }
  71.     } catch (error) {
  72.       hilog.error(0, 'TAG', `getInstalledModule onError.code is ${error.code}, message is ${error.message}`);
  73.     }
  74.   }
  75.   /**
  76.    * 添加监听事件
  77.    *
  78.    * @param successCallBack 回调
  79.    */
  80.   private onListenEvents(successCallBack: Callback<void>): void {
  81.     const timeout = 3 * 60; //单位秒, 默认最大监听时间为30min(即30*60秒)
  82.     moduleInstallManager.on('moduleInstallStatus', (data: moduleInstallManager.ModuleInstallSessionState) => {
  83.       // 返回成功
  84.       if (data.taskStatus === moduleInstallManager.TaskStatus.INSTALL_SUCCESSFUL) {
  85.         successCallBack && successCallBack();
  86.         this.showToastInfo('install success');
  87.       }
  88.     }, timeout)
  89.   }
  90.   /**
  91.    * 加载指定包
  92.    *
  93.    * @param moduleName 需要加载的安装包名称
  94.    * @param successCallBack 回调
  95.    */
  96.   private fetchModule(moduleName: string, successCallBack: Callback<void>) {
  97.     try {
  98.       hilog.info(0, TAG, 'handleFetchModules start');
  99.       const context = getContext(this) as common.UIAbilityContext;
  100.       const moduleInstallProvider: moduleInstallManager.ModuleInstallProvider =
  101.         new moduleInstallManager.ModuleInstallProvider();
  102.       const moduleInstallRequest: moduleInstallManager.ModuleInstallRequest =
  103.         moduleInstallProvider.createModuleInstallRequest(context);
  104.       if (!moduleInstallRequest) {
  105.         hilog.warn(0, TAG, 'moduleInstallRequest is empty');
  106.         return;
  107.       }
  108.       moduleInstallRequest.addModule(moduleName);
  109.       moduleInstallManager.fetchModules(moduleInstallRequest)
  110.         .then((data: moduleInstallManager.ModuleInstallSessionState) => {
  111.           hilog.info(0, TAG, 'Succeeded in fetching Modules result.');
  112.           if (data.code === moduleInstallManager.RequestErrorCode.SUCCESS) {
  113.             this.onListenEvents(successCallBack)
  114.           } else {
  115.             hilog.info(0, TAG, 'fetchModules failure');
  116.           }
  117.         })
  118.         .catch((error: BusinessError) => {
  119.           hilog.error(0, 'TAG', `fetchModules onError.code is ${error.code}, message is ${error.message}`);
  120.         })
  121.     } catch (error) {
  122.       hilog.error(0, 'TAG', `handleFetchModules onError.code is ${error.code}, message is ${error.message}`);
  123.     }
  124.   }
  125. }
复制代码
了解更多详情>>
访问应用市场服务联盟官网
获取产品特性按需分发开发指导文档

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册