1# 建立应用侧与前端页面数据通道(C/C++) 2 3前端页面和应用侧之间可以使用Native方法实现两端通信(以下简称Native PostWebMessage),可解决ArkTS环境的冗余切换,同时允许发送消息、回调在非UI线程上运行,避免造成UI阻塞。当前只支持string和buffer数据类型。 4 5## 适用的应用架构 6 7应用使用ArkTS、C++语言混合开发,或本身应用架构较贴近于小程序架构,自带C++侧环境,推荐使用ArkWeb在Native侧提供的[ArkWeb_ControllerAPI](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#arkweb_controllerapi)、[ArkWeb_WebMessageAPI](../reference/apis-arkweb/_ark_web___web_message_a_p_i.md#arkweb_webmessageapi)、[ArkWeb_WebMessagePortAPI](../reference/apis-arkweb/_ark_web___web_message_port_a_p_i.md#arkweb_webmessageportapi)实现PostWebMessage功能。 8 9  10 11 上图展示了具有普遍适用性的小程序的通用架构。在这一架构中,逻辑层依赖于应用程序自带的JavaScript运行时,该运行时在一个已有的C++环境中运行。通过Native接口,逻辑层能够直接在C++环境中与视图层(其中ArkWeb充当渲染器)进行通信,无需回退至ArkTS环境使用ArkTS PostWebMessage接口。 12 13 左图是使用ArkTS PostWebMessage接口构建小程序的方案,,如红框所示,应用需要先调用到ArkTS环境,再调用到C++环境。右图是使用Native PostWebMessage接口构建小程序的方案,不需要ArkTS环境和C++环境的切换,执行效率更高。 14 15  16 17## 使用Native接口实现PostWebMessage通信 18 19### 使用Native接口绑定ArkWeb 20 21- ArkWeb组件声明在ArkTS侧,需要用户自定义一个标识webTag,并将webTag通过Node-API传至应用C++侧。后续ArkWeb Native接口使用时,均需webTag作为对应组件的唯一标识。 22 23- ArkTS侧 24 25 ```ts 26 import { webview } from '@kit.ArkWeb'; 27 // 自定义webTag,在WebviewController创建时作为入参传入,建立controller与webTag的映射关系 28 webTag: string = 'ArkWeb1'; 29 controller: webview.WebviewController = new webview.WebviewController(this.webTag); 30 ... 31 // aboutToAppear中将webTag通过Node-API接口传入C++侧,作为C++侧ArkWeb组件的唯一标识 32 aboutToAppear() { 33 console.info("aboutToAppear") 34 // 初始化web ndk 35 testNapi.nativeWebInit(this.webTag); 36 } 37 ... 38 ``` 39 40### 使用Native接口获取API结构体 41 42ArkWeb Native侧得先获取API结构体,才能调用结构体里的Native API。ArkWeb Native侧API通过函数[OH_ArkWeb_GetNativeAPI](../reference/apis-arkweb/_web.md#oh_arkweb_getnativeapi())获取,根据入参type不同,可获取对应的函数指针结构体。其中本指导涉及[ArkWeb_ControllerAPI](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#arkweb_controllerapi)、[ArkWeb_WebMessageAPI](../reference/apis-arkweb/_ark_web___web_message_a_p_i.md#arkweb_webmessageapi)、[ArkWeb_WebMessagePortAPI](../reference/apis-arkweb/_ark_web___web_message_port_a_p_i.md#arkweb_webmessageportapi)。 43 44 ```c++ 45 static ArkWeb_ControllerAPI *controller = nullptr; 46 static ArkWeb_WebMessagePortAPI *webMessagePort = nullptr; 47 static ArkWeb_WebMessageAPI *webMessage = nullptr; 48 ... 49 controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER)); 50 webMessagePort = 51 reinterpret_cast<ArkWeb_WebMessagePortAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_WEB_MESSAGE_PORT)); 52 webMessage = reinterpret_cast<ArkWeb_WebMessageAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_WEB_MESSAGE)); 53 ``` 54 55### 完整示例 56 57在调用API前建议通过[ARKWEB_MEMBER_MISSING](../reference/apis-arkweb/_web.md#arkweb_member_missing)校验该函数结构体是否有对应函数指针,避免SDK与设备ROM不匹配导致crash问题。[createWebMessagePorts](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#createwebmessageports)、[postWebMessage](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#postwebmessage)、[close](../reference/apis-arkweb/_ark_web___web_message_port_a_p_i.md#close)需运行在UI线程。 58 59* 前端页面代码 60 61 ```html 62 <!-- entry/src/main/resources/rawfile/index.html --> 63 <!-- index.html --> 64 <!DOCTYPE html> 65 <html lang="en-gb"> 66 <body> 67 <h1>etsRunJavaScriptExt测试demo</h1> 68 <h1 id="h1"></h1> 69 <h3 id="msg">Receive string:</h3> 70 <h3 id="msg2">Receive arraybuffer:</h3> 71 72 </body> 73 <script type="text/javascript"> 74 var h5Port; 75 76 window.addEventListener('message', function (event) { 77 if (event.data == 'init_web_messageport') { 78 const port = event.ports.at(0); // 1. 保存从应用侧发送过来的端口。 79 if (port) { 80 console.log("hwd In html got message"); 81 h5Port = port; 82 port.onmessage = function (event) { 83 console.log("hwd In html got message"); 84 // 2. 接收应用侧发送过来的消息. 85 var result = event.data; 86 var type_s = typeof (result) 87 switch (type_s) { 88 case "object": 89 if (result instanceof ArrayBuffer) { 90 type_s = "ArrayBuffer"; 91 var view = new Uint8Array(result); 92 const decoder = new TextDecoder('utf-8'); 93 result = decoder.decode(result); 94 } else if (result instanceof Error) { 95 type_s = "Error"; 96 } else if (result instanceof Array) { 97 type_s = "Array"; 98 } 99 break; 100 default: 101 break; 102 } 103 console.log("H5 recv type: " + type_s + "\nH5 recv result: " + result) 104 document.getElementById("msg").innerHTML = "recv type: " + type_s; 105 document.getElementById("msg2").innerHTML = "recv value: " + result; 106 } 107 h5Port.onmessageerror = (event) => { 108 console.error(`hwd In html Error receiving message: ${event}`); 109 }; 110 } 111 } 112 }) 113 window.onerror = function(message, url, line, column, error) { 114 console.log("JavaScript Error: " + message + " on line " + line + " in " + url); 115 document.getElementById("h1").innerHTML = "执行函数失败" 116 }; 117 118 // 3. 使用h5Port向应用侧发送消息。 119 function postStringToApp() { 120 if (h5Port) { 121 h5Port.postMessage("send string from H5"); 122 } else { 123 console.error("In html h5port is null, please init first"); 124 } 125 } 126 function postBufferToApp() { 127 if (h5Port) { 128 const str = "Hello, World!"; 129 const encoder = new TextEncoder(); 130 const uint8Array = encoder.encode(str); 131 h5Port.postMessage(uint8Array.buffer); 132 } else { 133 console.error("In html h5port is null, please init first"); 134 } 135 } 136 137 function postJsonToApp() { 138 if (h5Port) { 139 var e = {"json": "json"}; 140 h5Port.postMessage(e); 141 } else { 142 console.error("In html h5port is null, please init first"); 143 } 144 } 145 146 function postArrayStringToApp() { 147 if (h5Port) { 148 h5Port.postMessage(["1", "2", "3"]); 149 } else { 150 console.error("In html h5port is null, please init first"); 151 } 152 } 153 154 function postNumberToApp() { 155 if (h5Port) { 156 h5Port.postMessage(123); 157 } else { 158 console.error("In html h5port is null, please init first"); 159 } 160 } 161 class MyClass { 162 constructor() { 163 // 构造器 164 this.myProperty = 'Hello, World!'; 165 } 166 167 myMethod() { 168 // 实例方法 169 console.log(this.myProperty); 170 } 171 172 static myStaticMethod() { 173 // 静态方法 174 console.log('This is a static method.'); 175 } 176 } 177 function postObjectToApp() { 178 if (h5Port) { 179 h5Port.postMessage(new MyClass()); 180 } else { 181 console.error("In html h5port is null, please init first"); 182 } 183 } 184 185 </script> 186 </html> 187 ``` 188 189* ArkTS侧代码 190 191 ```javascript 192 // entry/src/main/ets/pages/Index.ets 193 import testNapi from 'libentry.so' 194 import web_webview from '@ohos.web.webview'; 195 import { BusinessError } from '@ohos.base'; 196 197 @Entry 198 @Component 199 struct Index { 200 @State webTag: string = 'postMessage'; 201 controller: web_webview.WebviewController = new web_webview.WebviewController(this.webTag); 202 @State h5Log: string = 'Display received message send from HTML'; 203 204 aboutToAppear() { 205 web_webview.WebviewController.setWebDebuggingAccess(true); 206 // 初始化web ndk 207 testNapi.nativeWebInit(this.webTag); 208 } 209 210 aboutToDisAppear() { 211 console.error("aboutToDisAppear") 212 } 213 214 build() { 215 Scroll() { 216 Column({ space: 10 }) { 217 // 展示H5接收到的内容 218 Text("H5侧接收到应用侧发送消息展示") 219 TextArea({text: this.h5Log}) 220 .id("log_area") 221 .width("100%") 222 .height(100) 223 .border({ width: 1 }) 224 Text("应用侧按钮") 225 Row() { 226 Button('createNoControllerTagPort') 227 .id("create_no_tag_btn") 228 .onClick(() => { 229 try { 230 testNapi.createWebMessagePorts("noTag"); 231 } catch (error) { 232 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 233 } 234 }) 235 Button('createPort') 236 .id("create_port_btn") 237 .onClick(() => { 238 try { 239 testNapi.createWebMessagePorts(this.webTag); 240 } catch (error) { 241 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 242 } 243 }) 244 } 245 246 Row({ space: 10 }) { 247 248 Button('setHandler') 249 .id("set_handler_btn") 250 .onClick(() => { 251 try { 252 testNapi.setMessageEventHandler(this.webTag); 253 } catch (error) { 254 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 255 } 256 }) 257 258 Button('setHandlerThread') 259 .id("set_handler_thread_btn") 260 .onClick(() => { 261 try { 262 testNapi.setMessageEventHandlerThread(this.webTag); 263 } catch (error) { 264 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 265 } 266 }) 267 } 268 269 Row({ space: 10 }) { 270 Button('SendString') 271 .id("send_string_btn") 272 .onClick(() => { 273 try { 274 this.h5Log = "" 275 testNapi.postMessage(this.webTag); 276 } catch (error) { 277 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 278 } 279 }) 280 Button('SendStringThread') 281 .id("send_string_thread_btn") 282 .onClick(() => { 283 try { 284 this.h5Log = "" 285 testNapi.postMessageThread(this.webTag); 286 } catch (error) { 287 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 288 } 289 }) 290 } 291 292 Row({ space: 10 }) { 293 Button('SendBuffer') 294 .id("send_buffer_btn") 295 .onClick(() => { 296 try { 297 this.h5Log = "" 298 testNapi.postBufferMessage(this.webTag); 299 } catch (error) { 300 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 301 } 302 }) 303 Button('SendNone') 304 .id("send_none_btn") 305 .onClick(() => { 306 try { 307 this.h5Log = "" 308 testNapi.postNoneMessage(this.webTag); 309 } catch (error) { 310 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 311 } 312 }) 313 } 314 315 Row({ space: 10 }) { 316 317 Button('closePort') 318 .id("close_port_btn") 319 .onClick(() => { 320 try { 321 testNapi.closeMessagePort(this.webTag); 322 } catch (error) { 323 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 324 } 325 }) 326 Button('destroyNullPort') 327 .id("destroy_null_btn") 328 .onClick(() => { 329 try { 330 testNapi.destroyNullMessagePort(this.webTag); 331 } catch (error) { 332 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 333 } 334 }) 335 Button('destroyPort') 336 .id("destroy_port_btn") 337 .onClick(() => { 338 try { 339 testNapi.destroyMessagePort(this.webTag); 340 } catch (error) { 341 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 342 } 343 }) 344 } 345 .width("100%") 346 .padding(10) 347 .border({ width: 1 }) 348 349 Column({ space: 10 }) { 350 Text("H5侧发送按钮") 351 Row({ space: 10 }) { 352 Button('H5String') 353 .id("h5_send_string_btn") 354 .onClick(() => { 355 try { 356 this.controller.runJavaScript("for(var i = 0; i < 2000; i++) postStringToApp()") 357 } catch (error) { 358 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 359 } 360 }) 361 Button('H5Buffer') 362 .id("h5_send_buffer_btn") 363 .onClick(() => { 364 try { 365 this.controller.runJavaScript("postBufferToApp()") 366 } catch (error) { 367 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 368 } 369 }) 370 Button('H5Number') 371 .id("h5_send_number_btn") 372 .onClick(() => { 373 try { 374 this.controller.runJavaScript("postNumberToApp()") 375 } catch (error) { 376 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 377 } 378 }) 379 } 380 381 Row({ space: 10 }) { 382 Button('H5Json') 383 .id("h5_send_json_btn") 384 .onClick(() => { 385 try { 386 this.controller.runJavaScript("postJsonToApp()") 387 } catch (error) { 388 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 389 } 390 }) 391 Button('H5Array') 392 .id("h5_send_array_btn") 393 .onClick(() => { 394 try { 395 this.controller.runJavaScript("postArrayStringToApp()") 396 } catch (error) { 397 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 398 } 399 }) 400 Button('H5Object') 401 .id("h5_send_object_btn") 402 .onClick(() => { 403 try { 404 this.controller.runJavaScript("postObjectToApp()") 405 } catch (error) { 406 console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`); 407 } 408 }) 409 } 410 } 411 .width("100%") 412 .margin(10) 413 .padding(10) 414 .border({ width: 1 }) 415 416 Web({ src: $rawfile('index.html'), controller: this.controller }) 417 .onConsole((event) => { 418 if (event) { 419 let msg = event.message.getMessage() 420 if (msg.startsWith("H5")) { 421 this.h5Log = event.message.getMessage() + "\n" + this.h5Log 422 } 423 } 424 return false; 425 }) 426 } 427 }.height('100%') 428 .scrollable(ScrollDirection.Vertical) 429 .scrollBar(BarState.Off) 430 .edgeEffect(EdgeEffect.Spring) 431 } 432 } 433 ``` 434 435* Node-API侧暴露ArkTS接口 436 437 ```javascript 438 // entry/src/main/cpp/types/libentry/index.d.ts 439 export const nativeWebInit: (webName: string) => void; 440 export const createWebMessagePorts: (webName: string) => void; 441 export const postMessage: (webName: string) => void; 442 export const postNoneMessage: (webName: string) => void; 443 export const setMessageEventHandler: (webName: string) => void; 444 export const closeMessagePort: (webName: string) => void; 445 export const destroyMessagePort: (webName: string) => void; 446 export const postBufferMessage: (webName: string) => void; 447 export const destroyNullMessagePort: (webName: string) => void; 448 export const setMessageEventHandlerThread: (webName: string) => void; 449 export const postMessageThread: (webName: string) => void; 450 ``` 451 452* Node-API侧编译配置 453 454 ```c++ 455 # entry/src/main/cpp/CMakeLists.txt 456 # the minimum version of CMake. 457 cmake_minimum_required(VERSION 3.4.1) 458 project(NDKPostMessage) 459 460 set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 461 462 if(DEFINED PACKAGE_FIND_FILE) 463 include(${PACKAGE_FIND_FILE}) 464 endif() 465 466 include_directories(${NATIVERENDER_ROOT_PATH} 467 ${NATIVERENDER_ROOT_PATH}/include) 468 469 add_library(entry SHARED hello.cpp) 470 471 find_library( 472 # Sets the name of the path variable. 473 hilog-lib 474 # Specifies the name of the NDK library that 475 # you want CMake to locate. 476 hilog_ndk.z 477 ) 478 479 target_link_libraries(entry PUBLIC libace_napi.z.so ${hilog-lib} libohweb.so) 480 ``` 481 482* Node-API层代码 483 484 ```c++ 485 // entry/src/main/cpp/hello.cpp 486 #include "napi/native_api.h" 487 #include <bits/alltypes.h> 488 #include <memory> 489 #include <string> 490 #include <sys/types.h> 491 #include <iostream> 492 #include <map> 493 #include "hilog/log.h" 494 #include "web/arkweb_interface.h" 495 #include <thread> 496 497 constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00; 498 ArkWeb_ControllerAPI *controller = nullptr; 499 500 ArkWeb_WebMessagePortAPI *webMessagePort = nullptr; 501 ArkWeb_WebMessageAPI *webMessage = nullptr; 502 size_t web_message_port_size = 0; 503 ArkWeb_WebMessagePortPtr *g_web_message_port_arr = nullptr; 504 505 static void WebMessagePortCallback(const char *webTag, const ArkWeb_WebMessagePortPtr port, 506 const ArkWeb_WebMessagePtr message, void *userData) { 507 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 508 "ndk WebMesagePortCallback webTag:%{public}s,messageType:%{public}d", webTag, 509 webMessage->getType(message)); 510 size_t len = 0; 511 void *back = webMessage->getData(message, &len); 512 if (webMessage->getType(message) == ArkWeb_WebMessageType::ARKWEB_STRING) { 513 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 514 "ndk WebMesagePortCallback message:%{public}s,messageSize:%{public}d", back, len); 515 } else if (webMessage->getType(message) == ArkWeb_WebMessageType::ARKWEB_BUFFER) { 516 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 517 "ndk WebMesagePortCallback messageSize:%{public}d", len); 518 } 519 } 520 521 static napi_value NativeWebInit(napi_env env, napi_callback_info info) { 522 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start"); 523 size_t argc = 1; 524 napi_value args[1] = {nullptr}; 525 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 526 // 获取第一个参数webTag 527 size_t webTagSize = 0; 528 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 529 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 530 size_t webTagLength = 0; 531 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 532 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue); 533 534 controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER)); 535 if (controller) 536 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_ControllerAPI success"); 537 538 webMessagePort = 539 reinterpret_cast<ArkWeb_WebMessagePortAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_WEB_MESSAGE_PORT)); 540 if (webMessagePort) 541 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_WebMessagePortAPI success"); 542 543 webMessage = reinterpret_cast<ArkWeb_WebMessageAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_WEB_MESSAGE)); 544 if (webMessage) 545 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_WebMessageAPI success"); 546 547 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit end"); 548 549 return nullptr; 550 } 551 552 static napi_value createWebMessagePorts(napi_env env, napi_callback_info info) { 553 size_t argc = 2; 554 napi_value args[2] = {nullptr}; 555 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 556 557 // 获取第一个参数webTag 558 size_t webTagSize = 0; 559 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 560 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 561 size_t webTagLength = 0; 562 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 563 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 564 565 // 初始化端口 566 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk createWebMessagePorts begin"); 567 g_web_message_port_arr = controller->createWebMessagePorts(webTagValue, &web_message_port_size); 568 // 把其中一个端口发送给HTML 569 ArkWeb_ErrorCode code = 570 controller->postWebMessage(webTagValue, "init_web_messageport", g_web_message_port_arr, 1, "*"); 571 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postWebMessage ArkWeb_ErrorCode:%{public}d", code); 572 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 573 "ndk createWebMessagePorts end, web message port size:%{public}d", web_message_port_size); 574 return nullptr; 575 } 576 577 static napi_value postMessage(napi_env env, napi_callback_info info) { 578 size_t argc = 2; 579 napi_value args[2] = {nullptr}; 580 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 581 582 // 获取第一个参数webTag 583 size_t webTagSize = 0; 584 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 585 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 586 size_t webTagLength = 0; 587 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 588 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 589 590 // 发送消息 591 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin"); 592 593 if (g_web_message_port_arr == nullptr) { 594 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 595 return nullptr; 596 } 597 ArkWeb_WebMessagePtr message = webMessage->createWebMessage(); 598 webMessage->setType(message, ArkWeb_WebMessageType::ARKWEB_STRING); 599 std::string str = "send string from native"; 600 webMessage->setData(message, (void *)str.c_str(), str.length() + 1); 601 ArkWeb_ErrorCode code = webMessagePort->postMessage(g_web_message_port_arr[1], webTagValue, message); 602 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage ArkWeb_ErrorCode:%{public}d", code); 603 webMessage->destroyWebMessage(&message); 604 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage end, web message port size:%{public}d", 605 web_message_port_size); 606 return nullptr; 607 } 608 609 610 // 在线程中发消息 611 void sendMessage(const char *webTag, const ArkWeb_WebMessagePtr message) { 612 // 发送1000次 613 for (int i = 0; i < 1000; i++) { 614 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "sendMessage in thread %{public}d", i); 615 if (g_web_message_port_arr && webTag && message) { 616 webMessagePort->postMessage(g_web_message_port_arr[1], webTag, message); 617 } 618 } 619 } 620 static napi_value postMessageThread(napi_env env, napi_callback_info info) { 621 size_t argc = 2; 622 napi_value args[2] = {nullptr}; 623 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 624 625 // 获取第一个参数webTag 626 size_t webTagSize = 0; 627 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 628 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 629 size_t webTagLength = 0; 630 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 631 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 632 633 // 构造消息 634 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin"); 635 636 if (g_web_message_port_arr == nullptr) { 637 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 638 return nullptr; 639 } 640 ArkWeb_WebMessagePtr message = webMessage->createWebMessage(); 641 webMessage->setType(message, ArkWeb_WebMessageType::ARKWEB_STRING); 642 std::string str = "thread message"; 643 webMessage->setData(message, (void *)str.c_str(), str.length() + 1); 644 const int numThreads = 5; 645 std::thread threads[numThreads]; 646 647 // 创建线程 648 for (int i = 0; i < numThreads; ++i) { 649 threads[i] = std::thread(sendMessage, webTagValue, message); 650 } 651 652 // 等待所有线程完成 653 for (int i = 0; i < numThreads; ++i) { 654 threads[i].detach(); 655 } 656 return nullptr; 657 } 658 659 // 在线程中注册回调 660 void setHandler(const char *webTag) { 661 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "setMessageEventHandler in thread"); 662 webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTag, WebMessagePortCallback, NULL); 663 } 664 665 static napi_value setMessageEventHandlerThread(napi_env env, napi_callback_info info) { 666 size_t argc = 2; 667 napi_value args[2] = {nullptr}; 668 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 669 670 // 获取第一个参数webTag 671 size_t webTagSize = 0; 672 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 673 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 674 size_t webTagLength = 0; 675 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 676 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 677 678 // 注册回调 679 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 680 if (g_web_message_port_arr == nullptr) { 681 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 682 return nullptr; 683 } 684 std::thread thread(setHandler, webTagValue); 685 thread.detach(); 686 webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTagValue, WebMessagePortCallback, NULL); 687 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 688 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 689 return nullptr; 690 } 691 static napi_value postNoneMessage(napi_env env, napi_callback_info info) { 692 size_t argc = 2; 693 napi_value args[2] = {nullptr}; 694 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 695 696 // 获取第一个参数webTag 697 size_t webTagSize = 0; 698 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 699 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 700 size_t webTagLength = 0; 701 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 702 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 703 704 // 发送消息 705 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin"); 706 707 if (g_web_message_port_arr == nullptr) { 708 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 709 return nullptr; 710 } 711 ArkWeb_WebMessagePtr message = webMessage->createWebMessage(); 712 webMessage->setType(message, ArkWeb_WebMessageType::ARKWEB_NONE); 713 std::string str = "send string from native"; 714 webMessage->setData(message, (void *)str.c_str(), str.length() + 1); 715 webMessagePort->postMessage(g_web_message_port_arr[1], webTagValue, message); 716 webMessage->destroyWebMessage(&message); 717 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage end, web message port size:%{public}d", 718 web_message_port_size); 719 return nullptr; 720 } 721 722 static napi_value postBufferMessage(napi_env env, napi_callback_info info) { 723 size_t argc = 2; 724 napi_value args[2] = {nullptr}; 725 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 726 727 // 获取第一个参数webTag 728 size_t webTagSize = 0; 729 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 730 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 731 size_t webTagLength = 0; 732 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 733 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 734 735 // 发送消息 736 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin"); 737 738 if (g_web_message_port_arr == nullptr) { 739 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 740 return nullptr; 741 } 742 ArkWeb_WebMessagePtr message1 = webMessage->createWebMessage(); 743 webMessage->setType(message1, ArkWeb_WebMessageType::ARKWEB_BUFFER); 744 std::string str1 = "send buffer from native"; 745 webMessage->setData(message1, (void *)str1.c_str(), str1.length()); 746 webMessagePort->postMessage(g_web_message_port_arr[1], webTagValue, message1); 747 webMessage->destroyWebMessage(&message1); 748 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage end, web message port size:%{public}d", 749 web_message_port_size); 750 return nullptr; 751 } 752 753 static napi_value setMessageEventHandler(napi_env env, napi_callback_info info) { 754 size_t argc = 2; 755 napi_value args[2] = {nullptr}; 756 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 757 758 // 获取第一个参数webTag 759 size_t webTagSize = 0; 760 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 761 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 762 size_t webTagLength = 0; 763 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 764 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 765 766 // 注册回调 767 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 768 if (g_web_message_port_arr == nullptr) { 769 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 770 return nullptr; 771 } 772 webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTagValue, WebMessagePortCallback, NULL); 773 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 774 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 775 return nullptr; 776 } 777 778 static napi_value closeMessagePort(napi_env env, napi_callback_info info) { 779 size_t argc = 2; 780 napi_value args[2] = {nullptr}; 781 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 782 783 // 获取第一个参数webTag 784 size_t webTagSize = 0; 785 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 786 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 787 size_t webTagLength = 0; 788 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 789 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 790 791 // 关闭端口,先调用close,再调用destroyWebMessagePorts 792 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 793 if (g_web_message_port_arr == nullptr) { 794 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 795 return nullptr; 796 } 797 webMessagePort->close(g_web_message_port_arr[0], webTagValue); 798 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 799 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 800 controller->refresh(webTagValue); 801 return nullptr; 802 } 803 804 static napi_value destroyMessagePort(napi_env env, napi_callback_info info) { 805 size_t argc = 2; 806 napi_value args[2] = {nullptr}; 807 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 808 809 // 获取第一个参数webTag 810 size_t webTagSize = 0; 811 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 812 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 813 size_t webTagLength = 0; 814 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 815 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 816 817 // 释放内存,先调用close,再调用destroyWebMessagePorts 818 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 819 if (g_web_message_port_arr == nullptr) { 820 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 821 return nullptr; 822 } 823 controller->destroyWebMessagePorts(&g_web_message_port_arr, web_message_port_size); 824 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 825 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 826 return nullptr; 827 } 828 829 static napi_value destroyNullMessagePort(napi_env env, napi_callback_info info) { 830 size_t argc = 2; 831 napi_value args[2] = {nullptr}; 832 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 833 834 // 获取第一个参数webTag 835 size_t webTagSize = 0; 836 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 837 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 838 size_t webTagLength = 0; 839 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 840 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 841 842 // 释放内存,先调用close,再调用destroyWebMessagePorts 843 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 844 845 controller->destroyWebMessagePorts(&g_web_message_port_arr, web_message_port_size); 846 847 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 848 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 849 return nullptr; 850 } 851 852 EXTERN_C_START 853 static napi_value Init(napi_env env, napi_value exports) { 854 napi_property_descriptor desc[] = { 855 {"nativeWebInit", nullptr, NativeWebInit, nullptr, nullptr, nullptr, napi_default, nullptr}, 856 {"createWebMessagePorts", nullptr, createWebMessagePorts, nullptr, nullptr, nullptr, napi_default, nullptr}, 857 {"postMessage", nullptr, postMessage, nullptr, nullptr, nullptr, napi_default, nullptr}, 858 {"postNoneMessage", nullptr, postNoneMessage, nullptr, nullptr, nullptr, napi_default, nullptr}, 859 {"postBufferMessage", nullptr, postBufferMessage, nullptr, nullptr, nullptr, napi_default, nullptr}, 860 {"setMessageEventHandler", nullptr, setMessageEventHandler, nullptr, nullptr, nullptr, napi_default, nullptr}, 861 {"closeMessagePort", nullptr, closeMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr}, 862 {"destroyMessagePort", nullptr, destroyMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr}, 863 {"postMessageThread", nullptr, postMessageThread, nullptr, nullptr, nullptr, napi_default, nullptr}, 864 {"setMessageEventHandlerThread", nullptr, setMessageEventHandlerThread, nullptr, nullptr, nullptr, napi_default, 865 nullptr}, 866 {"destroyNullMessagePort", nullptr, destroyNullMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr}, 867 }; 868 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 869 return exports; 870 } 871 EXTERN_C_END 872 873 static napi_module demoModule = { 874 .nm_version = 1, 875 .nm_flags = 0, 876 .nm_filename = nullptr, 877 .nm_register_func = Init, 878 .nm_modname = "entry", 879 .nm_priv = ((void *)0), 880 .reserved = {0}, 881 }; 882 883 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } 884 ```