隨著HarmonyOS應用的持續發展,應用的功能將越來越豐富,實際上80%的用戶使用時長都會集中在20%的特性上,其余的功能可能也僅僅是面向部分用戶。
用戶在下載應用時,如果應用包含大量的功能和資源,可能會導致下載時間過長;應用如果包含許多不常用或特定用戶群體才需要的功能,這些功能會占用用戶設備的存儲空間;如果應用體積龐大,啟動和運行速度可能會受到影響。
為了避免用戶首次下載應用耗時過長,及過多占用用戶空間,HarmonyOS SDK 應用市場服務(Store Kit)提供 產品特性按需分發的能力,能夠提供動態分發和資源拆分,支持用戶按需動態下載自己所需的增強特性,減少開發者應用的分發成本,將精力放在維護和分發用戶實際需要的功能模塊,幫助提高分發效率。
基本概念
按需分發:一個應用程序被打包成多個安裝包,安裝包包含了所有的應用程序代碼和靜態資源。用戶從應用市場下載的應用只包含基本功能的安裝包,當用戶需要使用增強功能時,相應安裝包將會從服務器下載到設備上。
開發步驟
獲取模塊安裝信息
1.導入moduleInstallManager模塊及相關公共模塊。
import { moduleInstallManager } from '@kit.StoreKit';
2.構造參數。
入參為需要查詢的模塊名稱。
const moduleName: string = 'AModule';
3.調用getInstalledModule方法,將步驟2中構造的參數傳入模塊中的getInstalledModule方法。
const moduleInfo: moduleInstallManager.InstalledModule = moduleInstallManager.getInstalledModule(moduleName);
創建按需加載的請求實例
1.導入moduleInstallManager模塊及相關公共模塊。
import { moduleInstallManager } from '@kit.StoreKit';
import type { common } from '@kit.AbilityKit';
2.構造參數。
入參為當前應用的上下文context,只支持UIAbilityContext和ExtensionContext類型的上下文,其中UIAbilityContext類型的上下文是要校驗當前應用是否在前臺,如果不在前臺,則會被拒絕調用。
const context: common.UIAbilityContext | common.ExtensionContext = getContext(this) as common.UIAbilityContext;
3.調用createModuleInstallRequest方法,將步驟2中構造的參數依次傳入模塊中的createModuleInstallRequest方法。
const myModuleInstallProvider: moduleInstallManager.ModuleInstallProvider = new moduleInstallManager.ModuleInstallProvider();
const myModuleInstallRequest: moduleInstallManager.ModuleInstallRequest = myModuleInstallProvider.createModuleInstallRequest(context);
請求按需加載的接口
1.導入moduleInstallManager模塊及相關公共模塊。
import type { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { moduleInstallManager } from '@kit.StoreKit';
2.構造參數。
入參為當前要按需加載的模塊名。
const moduleNameA: string = 'AModule';
const moduleNameB: string = 'BModule';
3.調用ModuleInstallRequest中的addModule方法,將步驟2中構造的參數依次傳入模塊中的addModule方法。
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方法。
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定義如下:
export function add(a:number, b:number) {return a + b;
}
DateComponent.ets定義如下:
@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>): 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>): void {const timeout = 3 * 60; //單位秒, 默認最大監聽時間為30min(即30*60秒)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<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) => {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}`);}}
}
了解更多詳情>>
訪問應用市場服務聯盟官網
獲取產品特性按需分發開發指導文檔