• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 跨线程嵌入式组件 (IsolatedComponent,仅对系统应用开放)
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @dutie123-->
5<!--Designer: @lmleon-->
6<!--Tester: @fredyuan0912-->
7<!--Adviser: @HelloCrease-->
8
9IsolatedComponent组件是构建隔离组件的工具,能够帮助开发者创建独立且可重用的组件。这些组件可在不同应用程序中使用,不会与其他组件产生冲突。
10
11每个IsolatedComponent组件独立存在,具有专属的作用域和生命周期,不与其他组件共享状态或数据,能够方便地在不同应用程序中重用,降低重复开发的工作量。
12
13## 基本概念
14
15[IsolatedComponent](../reference/apis-arkui/arkui-ts/ts-container-isolated-component-sys.md)旨在在本页面中嵌入并展示由独立Abc(即.abc文件)所提供的UI,其展示内容在受限的worker线程中执行。
16
17该组件通常用于有Abc热更新(可动态替换Isolated加载的abc文件,无需通过重新安装应用的方式实现内容更新)诉求的模块化开发场景。
18
19## 约束与限制
20
211. Abc需要[bundleManager.verifyAbc](../reference/apis-ability-kit/js-apis-bundleManager-sys.md#bundlemanagerverifyabc11)校验通过之后才可以使用于当前组件。
22
232. 不支持构造参数更新,仅首次传入有效。
24
253. 不支持IsolatedComponent组件嵌套场景。
26
274. 主线程与受限worker线程之间布局渲染是异步处理,布局变化、旋转等导致的页面变化存在不同步现象。
28
295. 主线程与受限worker线程之间事件传递是异步处理,不支持线程之间的事件冒泡,线程之间的UI交互存在事件冲突现象。
30
316. 当独立Abc通过IsolatedComponent组件嵌入到宿主进程中显示时,即表明其内容完全向宿主开放,宿主可对独立Abc的内容进行操作。因此,涉及安全敏感的场景应禁用此功能。
32
337. 独立Abc运行在受限worker线程中可保证相对安全,并且不会影响主线程。
34
35## 场景示例
36
37该场景展示IsolatedComponent组件的基础使用方式,示例应用的bundleName为"com.example.isolateddemo",并使用本应用的Abc文件和extension页面作为嵌入展示的内容。
38
39**导入核心模块**
40
41在使用IsolatedComponent组件时,首先需要导入@kit.AbilityKit模块,该模块提供了构建隔离组件所需的必要功能,包括bundleManager等关键API。
42
43bundleManager作为AbilityKit的核心组件,提供了管理应用包的能力,是构建IsolatedComponent的基础。通过导入此模块,能够使用其提供的API来创建和管理隔离组件,确保不同组件之间的数据和资源隔离,从而提高应用的安全性。
44
45```ts
46import { bundleManager } from '@kit.AbilityKit';
47```
48
49**权限管理**
50
51使用IsolatedComponent组件时,合理配置[requestPermissions标签](../security/AccessToken/declare-permissions.md)是保障组件在受限环境中安全运行的关键步骤。通过此配置,能够准确指定组件所需的权限,实现权限的精细化管理。
52
53在受限模式下,IsolatedComponent组件默认不具备执行动态代码的能力。通过在module.json5配置文件中添加requestPermissions标签,可以授权组件在特定条件下执行动态下发的方舟字节码。
54
55```json
56"requestPermissions": [
57  {
58    "name": "ohos.permission.RUN_DYN_CODE",
59    "usedScene": {
60      "abilities": [
61        "EntryAbility"
62      ],
63      "when": "inuse"
64    }
65  }
66]
67```
68
69**受限worker**
70
71受限[worker](../reference/apis-arkts/js-apis-worker.md)是一个在隔离环境中运行的worker线程。这种隔离特性确保了受限worker与其他线程或组件之间实现内存隔离,避免它们之间的相互干扰或安全问题。
72
73在IsolatedComponent场景中,组件常需动态加载外部hap资源。受限worker通过以下机制保障安全:
74
75- [沙箱路径](../file-management/app-sandbox-directory.md)校验
76
77  abcPath指向经系统校验的安全目录,防止恶意代码注入。
78
79- 通信管控
80
81  主线程与worker间仅允许通过规范化的消息事件通信,禁止直接数据共享。
82
83- 异常隔离
84
85  worker内错误不会导致主应用崩溃,通过onerror事件可控处理。
86
87```ts
88// OhCardWorker.ets
89import { worker, ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@kit.ArkTS';
90
91const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
92
93workerPort.onmessage = (e: MessageEvents) => {}
94workerPort.onmessageerror = (e: MessageEvents) => {}
95workerPort.onerror = (e: ErrorEvent) => {}
96```
97<!--deprecated_code_no_check-->
98```ts
99IsolatedComponent({
100  want: {
101    "parameters": {
102      // 资源路径
103      "resourcePath": `${getContext(this).filesDir}/${this.fileName}.hap`,
104      // Abc文件校验后的沙箱路径
105      "abcPath": `/abcs${getContext(this).filesDir}/${this.fileName}`,
106      // 需要显示页面的入口路径
107      "entryPoint": `${this.bundleName}/entry/ets/pages/extension`,
108    }
109  },
110  // 受限worker
111  worker: new worker.RestrictedWorker("entry/ets/workers/OhCardWorker.ets")
112})
113```
114
115IsolatedComponent通过want和worker属性实现动态组件加载与隔离执行,二者共同构成安全边界。合理设置这些属性是确保组件能够安全运行的关键。
116
117其中,在受限worker线程中运行的入口页面文件ets/pages/extension.ets参考内容如下:
118
119```ts
120@Entry
121@Component
122struct Extension {
123  @State message: string = 'Hello World';
124
125  build() {
126    RelativeContainer() {
127      Text(this.message)
128        .id('HelloWorld')
129        .fontSize(50)
130        .fontWeight(FontWeight.Bold)
131        .alignRules({
132          center: { anchor: '__container__', align: VerticalAlign.Center },
133          middle: { anchor: '__container__', align: HorizontalAlign.Center }
134        })
135    }
136    .height('100%')
137    .width('100%')
138  }
139}
140```
141
142**示例应用代码**
143
144以下示例是在应用中,EntryAbility(UIAbility)加载首页文件ets/pages/Index.ets的内容。
145
146```ts
147import { worker } from '@kit.ArkTS';
148import { bundleManager, common } from '@kit.AbilityKit';
149import { BusinessError } from '@kit.BasicServicesKit';
150
151// 对Abc文件进行校验,并拷贝到指定沙箱路径下
152function VerifyAbc(abcPaths: Array<string>, deleteOriginalFiles: boolean) {
153  try {
154    bundleManager.verifyAbc(abcPaths, deleteOriginalFiles, (err) => {
155      if (err) {
156        console.error("VerifyAbc failed, error message: " + err.message);
157      } else {
158        console.info("VerifyAbc successfully.");
159      }
160    });
161  } catch (err) {
162    let message = (err as BusinessError).message;
163    console.error("VerifyAbc failed, error message: " + message);
164  }
165}
166
167@Entry
168@Component
169struct Index {
170  @State isShow: boolean = false;
171  @State resourcePath: string = "";
172  @State abcPath: string = "";
173  @State entryPoint: string = "";
174  @State context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
175  // Abc文件名
176  private fileName: string = "modules";
177  // Abc文件所属应用的bundleName
178  private bundleName: string = "com.example.isolateddemo";
179  // 受限worker
180  private worker ?: worker.RestrictedWorker = new worker.RestrictedWorker("entry/ets/workers/OhCardWorker.ets");
181
182  build() {
183    Row() {
184      Column({ space: 20 }) {
185        // 1.调用verifyAbc接口校验Abc文件
186        Button("verifyAbc").onClick(() => {
187          let abcFilePath = `${this.context.filesDir}/${this.fileName}.abc`;
188          console.info("abcFilePath: " + abcFilePath);
189          VerifyAbc([abcFilePath], false);
190        }).height(100).width(200)
191
192        // 2.显示IsolatedComponent
193        Button("showIsolatedComponent").onClick(() => {
194          if (!this.isShow) {
195            // 资源路径
196            this.resourcePath = `${this.context.filesDir}/${this.fileName}.hap`;
197            // Abc文件校验后的沙箱路径
198            this.abcPath = `/abcs${this.context.filesDir}/${this.fileName}`;
199            // 需要显示页面的入口路径
200            this.entryPoint = `${this.bundleName}/entry/ets/pages/extension`;
201            this.isShow = true;
202          }
203        }).height(100).width(200)
204
205        if (this.isShow) {
206          IsolatedComponent({
207            want: {
208              "parameters": {
209                "resourcePath": this.resourcePath,
210                "abcPath": this.abcPath,
211                "entryPoint": this.entryPoint
212              }
213            },
214            worker: this.worker
215          })
216            .width(300)
217            .height(300)
218            .onError((err) => {
219              console.info("onError : " + JSON.stringify(err));
220            })
221        }
222      }
223      .width('100%')
224    }
225    .height('100%')
226  }
227}
228```
229
230**预期效果**
231
2321. 在DevEco Studio上编译构建生成hap包,并安装到设备上;
233
2342. 将本应用构建生成的modules.abc文件通过DevEco Studio或hdc工具上传至应用沙箱路径/data/app/el2/100/base/com.example.isolateddemo/haps/entry/files下,其中,hdc工具参考命令如下:
235
236```bash
237hdc file send modules.abc /data/app/el2/100/base/com.example.isolateddemo/haps/entry/files/
238```
239
2403. 打开应用页面,点击"verifyAbc"按钮进行校验,输出"VerifyAbc successfully"日志;
241
242![zh-cn_image_0000001746521386](figures/zh-cn_image_0000001746521386.jpg)
243
244![zh-cn_image_0000001502381065](figures/zh-cn_image_0000001502381065.png)
245
2464. 点击"showIsolatedComponent"按钮,显示IsolatedComponent组件,内容为"Hello World"。
247