• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  ![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 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  ![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 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