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  ![arkweb_jsbridge_arch](figures/arkweb_jsbridge_arch.png)
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  ![arkweb_postwebmessage_diff](figures/arkweb_postwebmessage_diff.png)
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