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 243 244 245 2464. 点击"showIsolatedComponent"按钮,显示IsolatedComponent组件,内容为"Hello World"。 247