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 ArkTS and C++ language, or if its architecture is close to that of an applet and has a built-in C++ environment, you are advised to use the [ArkWeb_ControllerAPI](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md), [ArkWeb_WebMessageAPI](../reference/apis-arkweb/capi-web-arkweb-webmessageapi.md) and [ArkWeb_WebMessagePortAPI](../reference/apis-arkweb/capi-web-arkweb-webmessageportapi.md) 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 is 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 Structs Using the Native API 41 42To call the native APIs, 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/capi-arkweb-interface-h.md#oh_arkweb_getnativeapi) function to obtain the corresponding function pointer structs. This topic involves the obtaining of [ArkWeb_ControllerAPI](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md), [ArkWeb_WebMessageAPI](../reference/apis-arkweb/capi-web-arkweb-webmessageapi.md) and [ArkWeb_WebMessagePortAPI](../reference/apis-arkweb/capi-web-arkweb-webmessageportapi.md). 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/capi-arkweb-type-h.md#enums) 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. [createWebMessagePorts](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#createwebmessageports), [postWebMessage](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#postwebmessage) and [close](../reference/apis-arkweb/capi-web-arkweb-webmessageportapi.md#close) must run 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 610 // Send a message in the thread. 611 void sendMessage(const char *webTag, const ArkWeb_WebMessagePtr message) { 612 // Send the message for 1000 times. 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 // Obtain the first parameter 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 // Construct a message. 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 // Create the threads. 648 for (int i = 0; i < numThreads; ++i) { 649 threads[i] = std::thread(sendMessage, webTagValue, message); 650 } 651 652 // Wait until all threads are detached. 653 for (int i = 0; i < numThreads; ++i) { 654 threads[i].detach(); 655 } 656 return nullptr; 657 } 658 659 // Register a callback in the thread. 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 // Obtain the first parameter 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 // Register a callback. 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 // Obtain the first parameter 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 // Send a message. 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 // Obtain the first parameter 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 // Send a message. 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 // Obtain the first parameter 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 // Register a callback. 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 // Obtain the first parameter 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 // Disable the port by calling close() and then 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 // Obtain the first parameter 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 // Release the memory by calling close() and then 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 // Obtain the first parameter 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 // Release the memory by calling close() and then 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 ``` 885