1# Establishing a Data Channel Between the Application and the Frontend Page (C/C++) 2 3The native **PostWebMessage** is provided to implement communication between the frontend page and the application, which reduces unnecessary switching to the ArkTS environment and allows messages and callbacks to be reported in non-UI threads to avoid UI blocking. Currently, only the string and buffer can be sent. 4 5## Applicable Application Architecture 6 7If an application is developed using both ArkTS and C++, or the application architecture is close to the applet architecture and has a built-in C++ environment, you are advised to use [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) and [ArkWeb_WebMessagePortAPI](../reference/apis-arkweb/_ark_web___web_message_port_a_p_i.md#arkweb_webmessageportapi) provided by ArkWeb on the native side to implement the **PostWebMessage** feature. 8 9  10 11 The preceding figure shows a general architecture of applets with universal applicability. In this architecture, the logical layer depends on a JavaScript runtime built in an application, and the runtime runs in an existing C++ environment. The logic layer can communicate with the view layer (in which ArkWeb as the renderer) in the C++ environment through the native API, instead of using the ArkTS **PostWebMessage** API in the ArkTS environment. 12 13 The figure on the left shows that the application needs to invoke the ArkTS environment and then the C++ environment to build an applet using the ArkTS **PostWebMessage** API. Using the native **PostWebMessage** API is more efficient because the switch between the ArkTS and C++ environments is not required, as shown in the figure on the right. 14 15  16 17## Using the Native API to Implement PostWebMessage 18 19### Binding the Native API to ArkWeb 20 21- The ArkWeb component is declared on the ArkTS side. You need to define a **webTag** and pass it to the C++ side of the application through the Node-API. When the ArkWeb native API is called, **webTag** uniquely identifies the corresponding component. 22 23- ArkTS side: 24 25 ```ts 26 import { webview } from '@kit.ArkWeb'; 27 // Define a webTag and pass it to WebviewController when it is created to establish the mapping between controller and webTag. 28 webTag: string = 'ArkWeb1'; 29 controller: webview.WebviewController = new webview.WebviewController(this.webTag); 30 ... 31 // Use aboutToAppear() to pass webTag to C++ through the Node-API. The webTag uniquely identifies the C++ ArkWeb component. 32 aboutToAppear() { 33 console.info("aboutToAppear") 34 // Initialize the NDK API of the Web component. 35 testNapi.nativeWebInit(this.webTag); 36 } 37 ... 38 ``` 39 40### Obtaining API Struct Using the Native API 41 42To invoke the native APIs in the API structs, obtain the API structs on the ArkWeb native side first. You can pass different types of parameters in the [OH_ArkWeb_GetNativeAPI](../reference/apis-arkweb/_web.md#oh_arkweb_getnativeapi()) function to obtain the corresponding function pointer structs. The following APIs are provided: [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) and [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### Sample Code 56 57Use [ARKWEB_MEMBER_MISSING](../reference/apis-arkweb/_web.md#arkweb_member_missing) to check whether the function struct has the corresponding pointer before calling an API to avoid crash caused by mismatch between the SDK and the device ROM. You must use [createWebMessagePorts](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#createwebmessageports), [postWebMessage](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#postwebmessage) and [close](../reference/apis-arkweb/_ark_web___web_message_port_a_p_i.md#close) in the UI thread. 58 59* Frontend page code: 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 test 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. Save the port sent from the application. 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. Receive the message sent from the application. 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 = "Failed to execute the function." 116 }; 117 118 // 3. Use h5Port to send messages to the application. 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 // Constructor. 164 this.myProperty = 'Hello, World!'; 165 } 166 167 myMethod() { 168 // Instance method. 169 console.log(this.myProperty); 170 } 171 172 static myStaticMethod() { 173 // Static method. 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 code: 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 // Initialize the NDK API of the Web component. 207 testNapi.nativeWebInit(this.webTag); 208 } 209 210 aboutToDisAppear() { 211 console.error("aboutToDisAppear") 212 } 213 214 build() { 215 Scroll() { 216 Column({ space: 10 }) { 217 // Display the content received by the HTML5 page. 218 Text ("The message received by the HTML5 page from the application") 219 TextArea({text: this.h5Log}) 220 .id("log_area") 221 .width("100%") 222 .height(100) 223 .border({ width: 1 }) 224 Text ("Button on the application") 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 ("The Send button on the HTML5 page") 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* ArkTS APIs exposed on the Node-API side: 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* Compilation configuration on 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 layer code: 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 // Obtain the first parameter 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 // Obtain the first parameter 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 // Initialize the ports. 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 // Send one of the ports to the HTML page. 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 // Obtain the first parameter 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 // Send a message. 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 // Send a message in the thread. 610 void sendMessage(const char *webTag, const ArkWeb_WebMessagePtr message) { 611 // Send the message for 1000 times. 612 for (int i = 0; i < 1000; i++) { 613 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "sendMessage in thread %{public}d", i); 614 if (g_web_message_port_arr && webTag && message) { 615 webMessagePort->postMessage(g_web_message_port_arr[1], webTag, message); 616 } 617 } 618 } 619 static napi_value postMessageThread(napi_env env, napi_callback_info info) { 620 size_t argc = 2; 621 napi_value args[2] = {nullptr}; 622 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 623 624 // Obtain the first parameter webTag. 625 size_t webTagSize = 0; 626 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 627 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 628 size_t webTagLength = 0; 629 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 630 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 631 632 // Construct a message. 633 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin"); 634 635 if (g_web_message_port_arr == nullptr) { 636 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 637 return nullptr; 638 } 639 ArkWeb_WebMessagePtr message = webMessage->createWebMessage(); 640 webMessage->setType(message, ArkWeb_WebMessageType::ARKWEB_STRING); 641 std::string str = "thread message"; 642 webMessage->setData(message, (void *)str.c_str(), str.length() + 1); 643 const int numThreads = 5; 644 std::thread threads[numThreads]; 645 646 // Create the threads. 647 for (int i = 0; i < numThreads; ++i) { 648 threads[i] = std::thread(sendMessage, webTagValue, message); 649 } 650 651 // Wait until all threads are detached. 652 for (int i = 0; i < numThreads; ++i) { 653 threads[i].detach(); 654 } 655 return nullptr; 656 } 657 658 // Register a callback in the thread. 659 void setHandler(const char *webTag) { 660 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "setMessageEventHandler in thread"); 661 webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTag, WebMessagePortCallback, NULL); 662 } 663 664 static napi_value setMessageEventHandlerThread(napi_env env, napi_callback_info info) { 665 size_t argc = 2; 666 napi_value args[2] = {nullptr}; 667 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 668 669 // Obtain the first parameter webTag. 670 size_t webTagSize = 0; 671 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 672 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 673 size_t webTagLength = 0; 674 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 675 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 676 677 // Register a callback. 678 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 679 if (g_web_message_port_arr == nullptr) { 680 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 681 return nullptr; 682 } 683 std::thread thread(setHandler, webTagValue); 684 thread.detach(); 685 webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTagValue, WebMessagePortCallback, NULL); 686 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 687 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 688 return nullptr; 689 } 690 static napi_value postNoneMessage(napi_env env, napi_callback_info info) { 691 size_t argc = 2; 692 napi_value args[2] = {nullptr}; 693 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 694 695 // Obtain the first parameter webTag. 696 size_t webTagSize = 0; 697 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 698 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 699 size_t webTagLength = 0; 700 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 701 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 702 703 // Send a message. 704 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin"); 705 706 if (g_web_message_port_arr == nullptr) { 707 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 708 return nullptr; 709 } 710 ArkWeb_WebMessagePtr message = webMessage->createWebMessage(); 711 webMessage->setType(message, ArkWeb_WebMessageType::ARKWEB_NONE); 712 std::string str = "send string from native"; 713 webMessage->setData(message, (void *)str.c_str(), str.length() + 1); 714 webMessagePort->postMessage(g_web_message_port_arr[1], webTagValue, message); 715 webMessage->destroyWebMessage(&message); 716 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage end, web message port size:%{public}d", 717 web_message_port_size); 718 return nullptr; 719 } 720 721 static napi_value postBufferMessage(napi_env env, napi_callback_info info) { 722 size_t argc = 2; 723 napi_value args[2] = {nullptr}; 724 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 725 726 // Obtain the first parameter webTag. 727 size_t webTagSize = 0; 728 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 729 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 730 size_t webTagLength = 0; 731 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 732 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 733 734 // Send a message. 735 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin"); 736 737 if (g_web_message_port_arr == nullptr) { 738 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 739 return nullptr; 740 } 741 ArkWeb_WebMessagePtr message1 = webMessage->createWebMessage(); 742 webMessage->setType(message1, ArkWeb_WebMessageType::ARKWEB_BUFFER); 743 std::string str1 = "send buffer from native"; 744 webMessage->setData(message1, (void *)str1.c_str(), str1.length()); 745 webMessagePort->postMessage(g_web_message_port_arr[1], webTagValue, message1); 746 webMessage->destroyWebMessage(&message1); 747 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage end, web message port size:%{public}d", 748 web_message_port_size); 749 return nullptr; 750 } 751 752 static napi_value setMessageEventHandler(napi_env env, napi_callback_info info) { 753 size_t argc = 2; 754 napi_value args[2] = {nullptr}; 755 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 756 757 // Obtain the first parameter webTag. 758 size_t webTagSize = 0; 759 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 760 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 761 size_t webTagLength = 0; 762 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 763 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 764 765 // Register a callback. 766 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 767 if (g_web_message_port_arr == nullptr) { 768 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 769 return nullptr; 770 } 771 webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTagValue, WebMessagePortCallback, NULL); 772 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 773 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 774 return nullptr; 775 } 776 777 static napi_value closeMessagePort(napi_env env, napi_callback_info info) { 778 size_t argc = 2; 779 napi_value args[2] = {nullptr}; 780 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 781 782 // Obtain the first parameter webTag. 783 size_t webTagSize = 0; 784 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 785 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 786 size_t webTagLength = 0; 787 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 788 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 789 790 // Disable the port by calling close() and then destroyWebMessagePorts(). 791 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 792 if (g_web_message_port_arr == nullptr) { 793 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 794 return nullptr; 795 } 796 webMessagePort->close(g_web_message_port_arr[0], webTagValue); 797 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 798 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 799 controller->refresh(webTagValue); 800 return nullptr; 801 } 802 803 static napi_value destroyMessagePort(napi_env env, napi_callback_info info) { 804 size_t argc = 2; 805 napi_value args[2] = {nullptr}; 806 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 807 808 // Obtain the first parameter webTag. 809 size_t webTagSize = 0; 810 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 811 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 812 size_t webTagLength = 0; 813 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 814 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 815 816 // Release the memory by calling close() and then destroyWebMessagePorts(). 817 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 818 if (g_web_message_port_arr == nullptr) { 819 OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr"); 820 return nullptr; 821 } 822 controller->destroyWebMessagePorts(&g_web_message_port_arr, web_message_port_size); 823 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 824 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 825 return nullptr; 826 } 827 828 static napi_value destroyNullMessagePort(napi_env env, napi_callback_info info) { 829 size_t argc = 2; 830 napi_value args[2] = {nullptr}; 831 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 832 833 // Obtain the first parameter webTag. 834 size_t webTagSize = 0; 835 napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize); 836 char *webTagValue = new (std::nothrow) char[webTagSize + 1]; 837 size_t webTagLength = 0; 838 napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength); 839 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue); 840 841 // Release the memory by calling close() and then destroyWebMessagePorts(). 842 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin"); 843 844 controller->destroyWebMessagePorts(&g_web_message_port_arr, web_message_port_size); 845 846 OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", 847 "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size); 848 return nullptr; 849 } 850 851 EXTERN_C_START 852 static napi_value Init(napi_env env, napi_value exports) { 853 napi_property_descriptor desc[] = { 854 {"nativeWebInit", nullptr, NativeWebInit, nullptr, nullptr, nullptr, napi_default, nullptr}, 855 {"createWebMessagePorts", nullptr, createWebMessagePorts, nullptr, nullptr, nullptr, napi_default, nullptr}, 856 {"postMessage", nullptr, postMessage, nullptr, nullptr, nullptr, napi_default, nullptr}, 857 {"postNoneMessage", nullptr, postNoneMessage, nullptr, nullptr, nullptr, napi_default, nullptr}, 858 {"postBufferMessage", nullptr, postBufferMessage, nullptr, nullptr, nullptr, napi_default, nullptr}, 859 {"setMessageEventHandler", nullptr, setMessageEventHandler, nullptr, nullptr, nullptr, napi_default, nullptr}, 860 {"closeMessagePort", nullptr, closeMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr}, 861 {"destroyMessagePort", nullptr, destroyMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr}, 862 {"postMessageThread", nullptr, postMessageThread, nullptr, nullptr, nullptr, napi_default, nullptr}, 863 {"setMessageEventHandlerThread", nullptr, setMessageEventHandlerThread, nullptr, nullptr, nullptr, napi_default, 864 nullptr}, 865 {"destroyNullMessagePort", nullptr, destroyNullMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr}, 866 }; 867 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); 868 return exports; 869 } 870 EXTERN_C_END 871 872 static napi_module demoModule = { 873 .nm_version = 1, 874 .nm_flags = 0, 875 .nm_filename = nullptr, 876 .nm_register_func = Init, 877 .nm_modname = "entry", 878 .nm_priv = ((void *)0), 879 .reserved = {0}, 880 }; 881 882 extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } 883 ``` 884