IsolatedComponent (系统接口)

IsolatedComponent用于支持在本页面内嵌入显示独立Abc(.abc文件)提供的UI,展示的内容在受限worker线程中运行。

通常用于有Abc热更新诉求的模块化开发场景。

说明:

该组件从API Version 12开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。

本模块为系统接口。

本模块仅适用于ArkTS1.1。

使用约束

规格约束

1、本组件不支持预览。

2、Abc需要VerifyAbc校验通过之后才可以使用于当前组件。

3、不支持构造参数更新,仅首次传入有效。

4、不支持IsolatedComponent组件嵌套场景。

体验约束

1、创建IsolatedComponent组件时,受限worker线程加载Abc布局渲染存在一定耗时,在此等待期间显示IsolatedComponent组件的背景色。

2、主线程与受限worker线程之间布局渲染是异步处理,布局变化、旋转等导致的页面变化存在不同步现象。

3、主线程与受限worker线程之间事件传递是异步处理,不支持线程之间的事件冒泡,线程之间的UI交互存在事件冲突现象。

安全约束

1、独立Abc通过IsolatedComponent组件嵌入式显示在宿主进程,即可说明其Abc内容完全向宿主开放,宿主有权操作独立Abc的内容,对此安全敏感场景禁用。

2、独立Abc运行在受限worker可保证相对安全,独立Abc内容不影响主线程。

子组件

接口

IsolatedComponent(options: IsolatedOptions)

创建IsolatedComponent组件,用于显示受限worker运行的Abc。

参数:

参数名 参数类型 必填 参数描述
options IsolatedOptions 需要传递的构造项。

IsolatedOptions

用于在IsolatedComponent进行构造的时候,传递可选的构造参数。

参数:

参数名 参数类型 必填 参数描述
want Want 要加载的Abc信息。
worker RestrictedWorker 运行Abc的受限worker。

属性

仅支持widthheightbackgroundColor通用属性。

事件

不支持通用事件

将事件经过坐标转换后异步传递给受限worker线程处理。

支持以下事件:

onError

onError(callback:ErrorCallback)

被拉起的Ability扩展在运行过程中发生异常时触发本回调。可通过回调参数中的code、name和message获取错误信息并做处理。

参数:

参数名 类型 说明
callback ErrorCallback 报错信息。

示例(加载IsolatedComponent)

本示例展示IsolatedComponent组件的基础使用方式,示例应用的bundleName为"com.example.isolateddemo",并使用本应用的Abc文件和extension页面作为嵌入展示的内容。构建应用项目后,具体测试步骤如下:

  1. 在DevEco Studio上编译构建生成hap包,并安装到设备上;
  2. 将本应用构建生成的modules.abc文件通过DevEco Studio或hdc工具上传至应用沙箱路径/data/app/el2/100/base/com.example.isolateddemo/haps/entry/files下;
  3. 打开应用页面,点击"verifyAbc"按钮进行校验,输出"VerifyAbc successfully"日志;
  4. 点击"showIsolatedComponent"按钮,显示IsolatedComponent组件,内容为"Hello World"。
  • 受限worker脚本ets/workers/OhCardWorker.ets的内容如下:

    // OhCardWorker.ets
    import { worker, ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@kit.ArkTS';
    const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
    
    workerPort.onmessage = (e: MessageEvents) => {}
    workerPort.onmessageerror = (e: MessageEvents) => {}
    workerPort.onerror = (e: ErrorEvent) => {}
    
  • 示例应用中EntryAbility(UIAbility)加载首页文件ets/pages/Index.ets的内容如下:

    import { worker } from '@kit.ArkTS';
    import { bundleManager } from '@kit.AbilityKit';
    import { BusinessError } from '@kit.BasicServicesKit';
    
    // 对abc文件进行校验,并拷贝到指定沙箱路径下
    function VerifyAbc(abcPaths: Array<string>, deleteOriginalFiles: boolean) {
      try {
        bundleManager.verifyAbc(abcPaths, deleteOriginalFiles, (err) => {
          if (err) {
            console.error("VerifyAbc failed, error message: " + err.message);
          } else {
            console.info("VerifyAbc successfully.");
          }
        });
      } catch (err) {
        let message = (err as BusinessError).message;
        console.error("VerifyAbc failed, error message: " + message);
      }
    }
    
    @Entry
    @Component
    struct Index {
      @State isShow: boolean = false;
      @State resourcePath: string = "";
      @State abcPath: string = "";
      @State entryPoint: string = "";
      // abc文件名
      private fileName: string = "modules";
      // abc文件所属应用的bundleName
      private bundleName: string = "com.example.isolateddemo";
      // 受限worker
      private worker ?: worker.RestrictedWorker = new worker.RestrictedWorker("entry/ets/workers/OhCardWorker.ets");
    
      build() {
        Row() {
          Column() {
            // 1.调用verifyAbc接口校验abc文件
            Button("verifyAbc").onClick(() => {
              let abcFilePath = `${getContext(this).filesDir}/${this.fileName}.abc`;
              console.log("abcFilePath: " + abcFilePath);
              VerifyAbc([abcFilePath], false);
            }).height(100).width(100)
    
            // 2.显示IsolatedComponent
            Button("showIsolatedComponent").onClick(() => {
              if (!this.isShow) {
                // 资源路径
                this.resourcePath = `${getContext(this).filesDir}/${this.fileName}.hap`;
                // abc文件校验后的沙箱路径
                this.abcPath = `/abcs${getContext(this).filesDir}/${this.fileName}`;
                // 需要显示页面的入口路径
                this.entryPoint = `${this.bundleName}/entry/ets/pages/extension`;
                this.isShow = true;
              }
            }).height(100).width(100)
    
            if (this.isShow) {
              IsolatedComponent({
                want: {
                  "parameters": {
                    "resourcePath": this.resourcePath,
                    "abcPath": this.abcPath,
                    "entryPoint": this.entryPoint
                  }
                },
                worker: this.worker
              })
                .width(300)
                .height(300)
                .onError((err) => {
                  console.info("onError : " + JSON.stringify(err));
                })
            }
          }
          .width('100%')
        }
        .height('100%')
      }
    }
    
  • 在受限worker线程中运行的入口页面文件ets/pages/extension.ets,需要在resources/base/profile/main_pages.json文件中配置该页面路径,其中内容如下:

    @Entry
    @Component
    struct Extension {
      @State message: string = 'Hello World';
    
      build() {
        RelativeContainer() {
          Text(this.message)
            .id('HelloWorld')
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
            .alignRules({
              center: { anchor: '__container__', align: VerticalAlign.Center },
              middle: { anchor: '__container__', align: HorizontalAlign.Center }
            })
        }
        .height('100%')
        .width('100%')
      }
    }
    
  • module.json5配置文件中增加requestPermissions标签,允许在受限模式下执行动态下发的方舟字节码:

    "requestPermissions": [
      {
        "name": "ohos.permission.RUN_DYN_CODE",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
        }
      }
    ]