首页
社区
课程
招聘
[原创]聚焦应用常用功能,提升用户体验与分发效率
发表于: 2025-3-28 16:15 2352

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

2025-3-28 16:15
2352

随着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
2
import { moduleInstallManager } from '@kit.StoreKit';
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
2
const myModuleInstallProvider: moduleInstallManager.ModuleInstallProvider = new moduleInstallManager.ModuleInstallProvider();
const myModuleInstallRequest: moduleInstallManager.ModuleInstallRequest = myModuleInstallProvider.createModuleInstallRequest(context);

请求按需加载的接口

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

1
2
3
import type { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { moduleInstallManager } from '@kit.StoreKit';

2.构造参数。

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

1
2
const moduleNameA: string = 'AModule';
const moduleNameB: string = 'BModule';

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

1
2
3
4
5
6
7
8
9
10
11
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方法。

1
2
3
4
5
6
7
8
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定义如下:

1
2
3
export function add(a:number, b:number) {
  return a + b;
}

DateComponent.ets定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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方法。
1
2
export { add } from './src/main/ets/utils/Calc';
export { showDateComponent } from './src/main/ets/components/DateComponent';

entry中主要实现如下:

  • 在entry基础模块中,增加动态依赖配置。entry的oh-package.json5中使用dynamicDependencies来动态依赖AModulelib模块。
1
2
3
4
5
{
  "dynamicDependencies": {
    "AModulelib": "file:../AModulelib"
  }
}
  • 在entry中使用动态模块AModulelib模块里面的方法和组件。在调用AModulelib中的功能前需要判断AModulelib是否已经加载,未加载时请参考请求按需加载的接口完成加载。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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>): void {
    try {
      const result: moduleInstallManager.InstalledModule = moduleInstallManager.getInstalledModule('AModulelib');
      if (result?.installStatus === moduleInstallManager.InstallStatus.INSTALLED) {
        hilog.info(0, TAG, 'AModulelib installed');
        successCallBack &amp;&amp; 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>): void {
    const timeout = 3 * 60; //单位秒, 默认最大监听时间为30min(即30*60秒)
    moduleInstallManager.on('moduleInstallStatus', (data: moduleInstallManager.ModuleInstallSessionState) =&gt; {
      // 返回成功
      if (data.taskStatus === moduleInstallManager.TaskStatus.INSTALL_SUCCESSFUL) {
        successCallBack &amp;&amp; successCallBack();
        this.showToastInfo('install success');
      }
    }, timeout)
  }
 
  /**
   * 加载指定包
   *
   * @param moduleName 需要加载的安装包名称
   * @param successCallBack 回调
   */
  private fetchModule(moduleName: string, successCallBack: Callback<void>) {
    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) =&gt; {
          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) =&gt; {
          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}`);
    }
  }
}

了解更多详情>>

访问应用市场服务联盟官网

获取产品特性按需分发开发指导文档


[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!

收藏
免费
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册