• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Establishing a Data Channel Between the Application and the Frontend Page (C/C++)
2
3The following provides native APIs to implement communication between the frontend page and the application, which avoid unnecessary switching to the ArkTS environment and allow callback to be reported in non-UI threads to avoid UI blocking. In addition, messages and callbacks can be reported in non-UI threads to avoid UI blocking. Currently, only the string and buffer can be sent.
4
5## Binding the Native ArkWeb Component
6
7- The ArkWeb component is declared on the ArkTS side. You need to define a **webTag** and pass it to the C++ application through the Node-API. When the ArkWeb native API is called, **webTag** uniquely identifies the corresponding component.
8
9- ArkTS side:
10
11  ```ts
12  import { webview } from '@kit.ArkWeb';
13  // Define a webTag and pass it to WebviewController when it is created to establish the mapping between controller and webTag.
14  webTag: string = 'ArkWeb1';
15  controller: webview.WebviewController = new webview.WebviewController();
16  ...
17  // Use aboutToAppear() to pass the webTag to C++ through the native API. The webTag uniquely identifies the C++ ArkWeb component.
18  aboutToAppear() {
19    console.info("aboutToAppear")
20    // Initialize the NDK API of the Web component.
21    testNapi.nativeWebInit(this.webTag);
22  }
23  ...
24  ```
25
26## Obtaining the Native API Struct
27
28Obtain the ArkWeb native APIs using [OH_ArkWeb_GetNativeAPI](../reference/apis-arkweb/_ark_web___any_native_a_p_i.md#arkweb_anynativeapi). You can pass different parameters 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).
29
30  ```c++
31  static ArkWeb_ControllerAPI *controller = nullptr;
32  static ArkWeb_WebMessagePortAPI *webMessagePort = nullptr;
33  static ArkWeb_WebMessageAPI *webMessage = nullptr;
34  ...
35  controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
36  webMessagePort =
37      reinterpret_cast<ArkWeb_WebMessagePortAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_WEB_MESSAGE_PORT));
38  webMessage = reinterpret_cast<ArkWeb_WebMessageAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_WEB_MESSAGE));
39  ```
40
41## Sample Code
42
43Use [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. [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) must be used in the UI thread.
44
45* Frontend page code:
46
47  ```html
48  <!-- entry/src/main/resources/rawfile/index.html -->
49  <!-- index.html -->
50  <!DOCTYPE html>
51  <html lang="en-gb">
52  <body>
53  <h1>etsRunJavaScriptExt test demo</h1>;
54  <h1 id="h1"></h1>
55  <h3 id="msg">Receive string:</h3>
56  <h3 id="msg2">Receive arraybuffer:</h3>
57
58  </body>
59  <script type="text/javascript">
60  var h5Port;
61
62  window.addEventListener('message', function (event) {
63      if (event.data == 'init_web_messageport') {
64          const port = event.ports.at(0); // 1. Save the port sent from the application.
65          if (port) {
66              console.log("hwd In html got message");
67              h5Port = port;
68              port.onmessage = function (event) {
69                  console.log("hwd In html got message");
70                  // 2. Receive the message sent from the application.
71                  var result = event.data;
72                  var type_s = typeof (result)
73                  switch (type_s) {
74                      case "object":
75                          if (result instanceof ArrayBuffer) {
76                              type_s = "ArrayBuffer";
77                              var view = new Uint8Array(result);
78                              const decoder = new TextDecoder('utf-8');
79                              result = decoder.decode(result);
80                          } else if (result instanceof Error) {
81                              type_s = "Error";
82                          } else if (result instanceof Array) {
83                              type_s = "Array";
84                          }
85                          break;
86                      default:
87                          break;
88                  }
89                  console.log("H5 recv type: " + type_s + "\nH5 recv result: " + result)
90                  document.getElementById("msg").innerHTML = "recv type: " + type_s;
91                  document.getElementById("msg2").innerHTML = "recv value: " + result;
92              }
93              h5Port.onmessageerror = (event) => {
94                  console.error(`hwd In html Error receiving message: ${event}`);
95              };
96          }
97      }
98  })
99  window.onerror = function(message, url, line, column, error) {
100    console.log("JavaScript Error: " + message + " on line " + line + " in " + url);
101    document.getElementById("h1").innerHTML = "Failed to execute the function."
102  };
103
104  // 3. Use h5Port to send messages to the application.
105  function postStringToApp() {
106      if (h5Port) {
107          h5Port.postMessage("send string from H5");
108      } else {
109          console.error("In html h5port is null, please init first");
110      }
111  }
112  function postBufferToApp() {
113      if (h5Port) {
114          const str = "Hello, World!";
115          const encoder = new TextEncoder();
116          const uint8Array = encoder.encode(str);
117          h5Port.postMessage(uint8Array.buffer);
118      } else {
119          console.error("In html h5port is null, please init first");
120      }
121  }
122
123  function postJsonToApp() {
124      if (h5Port) {
125          var e = {"json": "json"};
126          h5Port.postMessage(e);
127      } else {
128          console.error("In html h5port is null, please init first");
129      }
130  }
131
132  function postArrayStringToApp() {
133      if (h5Port) {
134          h5Port.postMessage(["1", "2", "3"]);
135      } else {
136          console.error("In html h5port is null, please init first");
137      }
138  }
139
140  function postNumberToApp() {
141      if (h5Port) {
142          h5Port.postMessage(123);
143      } else {
144          console.error("In html h5port is null, please init first");
145      }
146  }
147  class MyClass {
148    constructor() {
149      // Constructor.
150      this.myProperty = 'Hello, World!';
151    }
152
153    myMethod() {
154      // Instance method.
155      console.log(this.myProperty);
156    }
157
158    static myStaticMethod() {
159      // Static method.
160      console.log('This is a static method.');
161    }
162  }
163  function postObjectToApp() {
164      if (h5Port) {
165          h5Port.postMessage(new MyClass());
166      } else {
167          console.error("In html h5port is null, please init first");
168      }
169  }
170
171  </script>
172  </html>
173  ```
174
175* ArkTS code:
176
177  ```javascript
178  // entry/src/main/ets/pages/Index.ets
179  import testNapi from 'libentry.so'
180  import web_webview from '@ohos.web.webview';
181  import { BusinessError } from '@ohos.base';
182
183  @Entry
184  @Component
185  struct Index {
186    @State webTag: string = 'postMessage';
187    controller: web_webview.WebviewController = new web_webview.WebviewController(this.webTag);
188    @State h5Log: string = 'Display received message send from HTML';
189
190    aboutToAppear() {
191      web_webview.WebviewController.setWebDebuggingAccess(true);
192      // Initialize the NDK API of the Web component.
193      testNapi.nativeWebInit(this.webTag);
194    }
195
196    aboutToDisAppear() {
197      console.error("aboutToDisAppear")
198    }
199
200    build() {
201      Scroll() {
202        Column({ space: 10 }) {
203          // Display the content received by the HTML5 page.
204          Text ("The message received by the HTML5 page from the application")
205          TextArea({text: this.h5Log})
206            .id("log_area")
207            .width("100%")
208            .height(100)
209            .border({ width: 1 })
210          Text ("Button on the application")
211          Row() {
212            Button('createNoControllerTagPort')
213              .id("create_no_tag_btn")
214              .onClick(() => {
215                try {
216                  testNapi.createWebMessagePorts("noTag");
217                } catch (error) {
218                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
219                }
220              })
221            Button('createPort')
222              .id("create_port_btn")
223              .onClick(() => {
224                try {
225                  testNapi.createWebMessagePorts(this.webTag);
226                } catch (error) {
227                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
228                }
229              })
230          }
231
232          Row({ space: 10 }) {
233
234            Button('setHandler')
235              .id("set_handler_btn")
236              .onClick(() => {
237                try {
238                  testNapi.setMessageEventHandler(this.webTag);
239                } catch (error) {
240                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
241                }
242              })
243
244            Button('setHandlerThread')
245              .id("set_handler_thread_btn")
246              .onClick(() => {
247                try {
248                  testNapi.setMessageEventHandlerThread(this.webTag);
249                } catch (error) {
250                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
251                }
252              })
253          }
254
255          Row({ space: 10 }) {
256            Button('SendString')
257              .id("send_string_btn")
258              .onClick(() => {
259                try {
260                  this.h5Log = ""
261                  testNapi.postMessage(this.webTag);
262                } catch (error) {
263                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
264                }
265              })
266            Button('SendStringThread')
267              .id("send_string_thread_btn")
268              .onClick(() => {
269                try {
270                  this.h5Log = ""
271                  testNapi.postMessageThread(this.webTag);
272                } catch (error) {
273                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
274                }
275              })
276          }
277
278          Row({ space: 10 }) {
279            Button('SendBuffer')
280              .id("send_buffer_btn")
281              .onClick(() => {
282                try {
283                  this.h5Log = ""
284                  testNapi.postBufferMessage(this.webTag);
285                } catch (error) {
286                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
287                }
288              })
289            Button('SendNone')
290              .id("send_none_btn")
291              .onClick(() => {
292                try {
293                  this.h5Log = ""
294                  testNapi.postNoneMessage(this.webTag);
295                } catch (error) {
296                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
297                }
298              })
299          }
300
301          Row({ space: 10 }) {
302
303            Button('closePort')
304              .id("close_port_btn")
305              .onClick(() => {
306                try {
307                  testNapi.closeMessagePort(this.webTag);
308                } catch (error) {
309                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
310                }
311              })
312            Button('destroyNullPort')
313              .id("destroy_null_btn")
314              .onClick(() => {
315                try {
316                  testNapi.destroyNullMessagePort(this.webTag);
317                } catch (error) {
318                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
319                }
320              })
321            Button('destroyPort')
322              .id("destroy_port_btn")
323              .onClick(() => {
324                try {
325                  testNapi.destroyMessagePort(this.webTag);
326                } catch (error) {
327                  console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
328                }
329              })
330          }
331          .width("100%")
332          .padding(10)
333          .border({ width: 1 })
334
335          Column({ space: 10 }) {
336            Text ("The Send button on the HTML5 page")
337            Row({ space: 10 }) {
338              Button('H5String')
339                .id("h5_send_string_btn")
340                .onClick(() => {
341                  try {
342                    this.controller.runJavaScript("for(var i = 0; i < 2000; i++) postStringToApp()")
343                  } catch (error) {
344                    console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
345                  }
346                })
347              Button('H5Buffer')
348                .id("h5_send_buffer_btn")
349                .onClick(() => {
350                  try {
351                    this.controller.runJavaScript("postBufferToApp()")
352                  } catch (error) {
353                    console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
354                  }
355                })
356              Button('H5Number')
357                .id("h5_send_number_btn")
358                .onClick(() => {
359                  try {
360                    this.controller.runJavaScript("postNumberToApp()")
361                  } catch (error) {
362                    console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
363                  }
364                })
365            }
366
367            Row({ space: 10 }) {
368              Button('H5Json')
369                .id("h5_send_json_btn")
370                .onClick(() => {
371                  try {
372                    this.controller.runJavaScript("postJsonToApp()")
373                  } catch (error) {
374                    console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
375                  }
376                })
377              Button('H5Array')
378                .id("h5_send_array_btn")
379                .onClick(() => {
380                  try {
381                    this.controller.runJavaScript("postArrayStringToApp()")
382                  } catch (error) {
383                    console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
384                  }
385                })
386              Button('H5Object')
387                .id("h5_send_object_btn")
388                .onClick(() => {
389                  try {
390                    this.controller.runJavaScript("postObjectToApp()")
391                  } catch (error) {
392                    console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
393                  }
394                })
395            }
396          }
397          .width("100%")
398          .margin(10)
399          .padding(10)
400          .border({ width: 1 })
401
402          Web({ src: $rawfile('index.html'), controller: this.controller })
403            .onConsole((event) => {
404              if (event) {
405                let msg = event.message.getMessage()
406                if (msg.startsWith("H5")) {
407                  this.h5Log = event.message.getMessage() + "\n" + this.h5Log
408                }
409              }
410              return false;
411            })
412        }
413      }.height('100%')
414      .scrollable(ScrollDirection.Vertical)
415      .scrollBar(BarState.Off)
416      .edgeEffect(EdgeEffect.Spring)
417    }
418  }
419  ```
420
421* ArkTS APIs exposed on the native APIs:
422
423  ```javascript
424  // entry/src/main/cpp/types/libentry/index.d.ts
425  export const nativeWebInit: (webName: string) => void;
426  export const createWebMessagePorts: (webName: string) => void;
427  export const postMessage: (webName: string) => void;
428  export const postNoneMessage: (webName: string) => void;
429  export const setMessageEventHandler: (webName: string) => void;
430  export const closeMessagePort: (webName: string) => void;
431  export const destroyMessagePort: (webName: string) => void;
432  export const postBufferMessage: (webName: string) => void;
433  export const destroyNullMessagePort: (webName: string) => void;
434  export const setMessageEventHandlerThread: (webName: string) => void;
435  export const postMessageThread: (webName: string) => void;
436  ```
437
438* Compilation configuration of the native APIs:
439
440  ```c++
441  # entry/src/main/cpp/CMakeLists.txt
442  # the minimum version of CMake.
443  cmake_minimum_required(VERSION 3.4.1)
444  project(NDKPostMessage)
445
446  set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
447
448  if(DEFINED PACKAGE_FIND_FILE)
449      include(${PACKAGE_FIND_FILE})
450  endif()
451
452  include_directories(${NATIVERENDER_ROOT_PATH}
453                      ${NATIVERENDER_ROOT_PATH}/include)
454
455  add_library(entry SHARED hello.cpp)
456
457  find_library(
458      # Sets the name of the path variable.
459      hilog-lib
460      # Specifies the name of the NDK library that
461      # you want CMake to locate.
462      hilog_ndk.z
463  )
464
465  target_link_libraries(entry PUBLIC libace_napi.z.so ${hilog-lib} libohweb.so)
466  ```
467
468* Native API code:
469
470  ```c++
471  // entry/src/main/cpp/hello.cpp
472  #include "napi/native_api.h"
473  #include <bits/alltypes.h>
474  #include <memory>
475  #include <string>
476  #include <sys/types.h>
477  #include <iostream>
478  #include <map>
479  #include "hilog/log.h"
480  #include "web/arkweb_interface.h"
481  #include <thread>
482
483  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
484  ArkWeb_ControllerAPI *controller = nullptr;
485
486  ArkWeb_WebMessagePortAPI *webMessagePort = nullptr;
487  ArkWeb_WebMessageAPI *webMessage = nullptr;
488  size_t web_message_port_size = 0;
489  ArkWeb_WebMessagePortPtr *g_web_message_port_arr = nullptr;
490
491  static void WebMessagePortCallback(const char *webTag, const ArkWeb_WebMessagePortPtr port,
492                                    const ArkWeb_WebMessagePtr message, void *userData) {
493      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
494                  "ndk WebMesagePortCallback webTag:%{public}s,messageType:%{public}d", webTag,
495                  webMessage->getType(message));
496      size_t len = 0;
497      void *back = webMessage->getData(message, &len);
498      if (webMessage->getType(message) == ArkWeb_WebMessageType::ARKWEB_STRING) {
499          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
500                      "ndk WebMesagePortCallback message:%{public}s,messageSize:%{public}d", back, len);
501      } else if (webMessage->getType(message) == ArkWeb_WebMessageType::ARKWEB_BUFFER) {
502          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
503                      "ndk WebMesagePortCallback messageSize:%{public}d", len);
504      }
505  }
506
507  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
508      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
509      size_t argc = 1;
510      napi_value args[1] = {nullptr};
511      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
512      // Obtain the first parameter webTag.
513      size_t webTagSize = 0;
514      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
515      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
516      size_t webTagLength = 0;
517      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
518      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
519
520      controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
521      if (controller)
522          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_ControllerAPI success");
523
524      webMessagePort =
525          reinterpret_cast<ArkWeb_WebMessagePortAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_WEB_MESSAGE_PORT));
526      if (webMessagePort)
527          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_WebMessagePortAPI success");
528
529      webMessage = reinterpret_cast<ArkWeb_WebMessageAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_WEB_MESSAGE));
530      if (webMessage)
531          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_WebMessageAPI success");
532
533      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit end");
534
535      return nullptr;
536  }
537
538  static napi_value createWebMessagePorts(napi_env env, napi_callback_info info) {
539      size_t argc = 2;
540      napi_value args[2] = {nullptr};
541      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
542
543      // Obtain the first parameter webTag.
544      size_t webTagSize = 0;
545      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
546      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
547      size_t webTagLength = 0;
548      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
549      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
550
551      // Initialize the ports.
552      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk createWebMessagePorts begin");
553      g_web_message_port_arr = controller->createWebMessagePorts(webTagValue, &web_message_port_size);
554      // Send one of the ports to the HTML page.
555      ArkWeb_ErrorCode code =
556          controller->postWebMessage(webTagValue, "init_web_messageport", g_web_message_port_arr, 1, "*");
557      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postWebMessage ArkWeb_ErrorCode:%{public}d", code);
558      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
559                  "ndk createWebMessagePorts end, web message port size:%{public}d", web_message_port_size);
560      return nullptr;
561  }
562
563  static napi_value postMessage(napi_env env, napi_callback_info info) {
564      size_t argc = 2;
565      napi_value args[2] = {nullptr};
566      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
567
568      // Obtain the first parameter webTag.
569      size_t webTagSize = 0;
570      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
571      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
572      size_t webTagLength = 0;
573      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
574      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
575
576      // Send a message.
577      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin");
578
579      if (g_web_message_port_arr == nullptr) {
580          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr");
581          return nullptr;
582      }
583      ArkWeb_WebMessagePtr message = webMessage->createWebMessage();
584      webMessage->setType(message, ArkWeb_WebMessageType::ARKWEB_STRING);
585      std::string str = "send string from native";
586      webMessage->setData(message, (void *)str.c_str(), str.length() + 1);
587      ArkWeb_ErrorCode code = webMessagePort->postMessage(g_web_message_port_arr[1], webTagValue, message);
588      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage ArkWeb_ErrorCode:%{public}d", code);
589      webMessage->destroyWebMessage(&message);
590      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage end, web message port size:%{public}d",
591                  web_message_port_size);
592      return nullptr;
593  }
594
595  // Send a message in the thread.
596  void sendMessage(const char *webTag, const ArkWeb_WebMessagePtr message) {
597      // Send the message for 1000 times.
598      for (int i = 0; i < 1000; i++) {
599          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "sendMessage in thread %{public}d", i);
600          if (g_web_message_port_arr && webTag && message) {
601            webMessagePort->postMessage(g_web_message_port_arr[1], webTag, message);
602          }
603      }
604  }
605  static napi_value postMessageThread(napi_env env, napi_callback_info info) {
606      size_t argc = 2;
607      napi_value args[2] = {nullptr};
608      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
609
610      // Obtain the first parameter webTag.
611      size_t webTagSize = 0;
612      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
613      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
614      size_t webTagLength = 0;
615      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
616      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
617
618      // Construct a message.
619      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin");
620
621      if (g_web_message_port_arr == nullptr) {
622          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr");
623          return nullptr;
624      }
625      ArkWeb_WebMessagePtr message = webMessage->createWebMessage();
626      webMessage->setType(message, ArkWeb_WebMessageType::ARKWEB_STRING);
627      std::string str = "thread message";
628      webMessage->setData(message, (void *)str.c_str(), str.length() + 1);
629      const int numThreads = 5;
630      std::thread threads[numThreads];
631
632      // Create the threads.
633      for (int i = 0; i < numThreads; ++i) {
634          threads[i] = std::thread(sendMessage, webTagValue, message);
635      }
636
637      // Wait until all threads are detached.
638      for (int i = 0; i < numThreads; ++i) {
639          threads[i].detach();
640      }
641      return nullptr;
642  }
643
644  // Register a callback in the thread.
645  void setHandler(const char *webTag) {
646      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "setMessageEventHandler in thread");
647      webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTag, WebMessagePortCallback, NULL);
648  }
649
650  static napi_value setMessageEventHandlerThread(napi_env env, napi_callback_info info) {
651      size_t argc = 2;
652      napi_value args[2] = {nullptr};
653      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
654
655      // Obtain the first parameter webTag.
656      size_t webTagSize = 0;
657      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
658      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
659      size_t webTagLength = 0;
660      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
661      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
662
663      // Register a callback.
664      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin");
665      if (g_web_message_port_arr == nullptr) {
666          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr");
667          return nullptr;
668      }
669      std::thread thread(setHandler, webTagValue);
670      thread.detach();
671      webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTagValue, WebMessagePortCallback, NULL);
672      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
673                  "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size);
674      return nullptr;
675  }
676  static napi_value postNoneMessage(napi_env env, napi_callback_info info) {
677      size_t argc = 2;
678      napi_value args[2] = {nullptr};
679      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
680
681      // Obtain the first parameter webTag.
682      size_t webTagSize = 0;
683      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
684      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
685      size_t webTagLength = 0;
686      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
687      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
688
689      // Send a message.
690      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin");
691
692      if (g_web_message_port_arr == nullptr) {
693          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr");
694          return nullptr;
695      }
696      ArkWeb_WebMessagePtr message = webMessage->createWebMessage();
697      webMessage->setType(message, ArkWeb_WebMessageType::ARKWEB_NONE);
698      std::string str = "send string from native";
699      webMessage->setData(message, (void *)str.c_str(), str.length() + 1);
700      webMessagePort->postMessage(g_web_message_port_arr[1], webTagValue, message);
701      webMessage->destroyWebMessage(&message);
702      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage end, web message port size:%{public}d",
703                  web_message_port_size);
704      return nullptr;
705  }
706
707  static napi_value postBufferMessage(napi_env env, napi_callback_info info) {
708      size_t argc = 2;
709      napi_value args[2] = {nullptr};
710      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
711
712      // Obtain the first parameter webTag.
713      size_t webTagSize = 0;
714      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
715      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
716      size_t webTagLength = 0;
717      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
718      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
719
720      // Send a message.
721      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage begin");
722
723      if (g_web_message_port_arr == nullptr) {
724          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr");
725          return nullptr;
726      }
727      ArkWeb_WebMessagePtr message1 = webMessage->createWebMessage();
728      webMessage->setType(message1, ArkWeb_WebMessageType::ARKWEB_BUFFER);
729      std::string str1 = "send buffer from native";
730      webMessage->setData(message1, (void *)str1.c_str(), str1.length());
731      webMessagePort->postMessage(g_web_message_port_arr[1], webTagValue, message1);
732      webMessage->destroyWebMessage(&message1);
733      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk postMessage end, web message port size:%{public}d",
734                  web_message_port_size);
735      return nullptr;
736  }
737
738  static napi_value setMessageEventHandler(napi_env env, napi_callback_info info) {
739      size_t argc = 2;
740      napi_value args[2] = {nullptr};
741      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
742
743      // Obtain the first parameter webTag.
744      size_t webTagSize = 0;
745      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
746      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
747      size_t webTagLength = 0;
748      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
749      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
750
751      // Register a callback.
752      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin");
753      if (g_web_message_port_arr == nullptr) {
754          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr");
755          return nullptr;
756      }
757      webMessagePort->setMessageEventHandler(g_web_message_port_arr[1], webTagValue, WebMessagePortCallback, NULL);
758      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
759                  "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size);
760      return nullptr;
761  }
762
763  static napi_value closeMessagePort(napi_env env, napi_callback_info info) {
764      size_t argc = 2;
765      napi_value args[2] = {nullptr};
766      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
767
768      // Obtain the first parameter webTag.
769      size_t webTagSize = 0;
770      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
771      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
772      size_t webTagLength = 0;
773      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
774      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
775
776      // Disable the port by calling close() and then destroyWebMessagePorts().
777      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin");
778      if (g_web_message_port_arr == nullptr) {
779          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr");
780          return nullptr;
781      }
782      webMessagePort->close(g_web_message_port_arr[0], webTagValue);
783      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
784                  "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size);
785      controller->refresh(webTagValue);
786      return nullptr;
787  }
788
789  static napi_value destroyMessagePort(napi_env env, napi_callback_info info) {
790      size_t argc = 2;
791      napi_value args[2] = {nullptr};
792      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
793
794      // Obtain the first parameter webTag.
795      size_t webTagSize = 0;
796      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
797      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
798      size_t webTagLength = 0;
799      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
800      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
801
802      // Release the memory by calling close() and then destroyWebMessagePorts().
803      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin");
804      if (g_web_message_port_arr == nullptr) {
805          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "webMessagePort is nullptr");
806          return nullptr;
807      }
808      controller->destroyWebMessagePorts(&g_web_message_port_arr, web_message_port_size);
809      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
810                  "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size);
811      return nullptr;
812  }
813
814  static napi_value destroyNullMessagePort(napi_env env, napi_callback_info info) {
815      size_t argc = 2;
816      napi_value args[2] = {nullptr};
817      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
818
819      // Obtain the first parameter webTag.
820      size_t webTagSize = 0;
821      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
822      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
823      size_t webTagLength = 0;
824      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
825      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk Refresh webTag:%{public}s", webTagValue);
826
827      // Release the memory by calling close() and then destroyWebMessagePorts().
828      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk SetMessageEventHandler begin");
829
830      controller->destroyWebMessagePorts(&g_web_message_port_arr, web_message_port_size);
831
832      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
833                  "ndk SetMessageEventHandler end, web message port size:%{public}d", web_message_port_size);
834      return nullptr;
835  }
836
837  EXTERN_C_START
838  static napi_value Init(napi_env env, napi_value exports) {
839      napi_property_descriptor desc[] = {
840          {"nativeWebInit", nullptr, NativeWebInit, nullptr, nullptr, nullptr, napi_default, nullptr},
841          {"createWebMessagePorts", nullptr, createWebMessagePorts, nullptr, nullptr, nullptr, napi_default, nullptr},
842          {"postMessage", nullptr, postMessage, nullptr, nullptr, nullptr, napi_default, nullptr},
843          {"postNoneMessage", nullptr, postNoneMessage, nullptr, nullptr, nullptr, napi_default, nullptr},
844          {"postBufferMessage", nullptr, postBufferMessage, nullptr, nullptr, nullptr, napi_default, nullptr},
845          {"setMessageEventHandler", nullptr, setMessageEventHandler, nullptr, nullptr, nullptr, napi_default, nullptr},
846          {"closeMessagePort", nullptr, closeMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr},
847          {"destroyMessagePort", nullptr, destroyMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr},
848          {"postMessageThread", nullptr, postMessageThread, nullptr, nullptr, nullptr, napi_default, nullptr},
849          {"setMessageEventHandlerThread", nullptr, setMessageEventHandlerThread, nullptr, nullptr, nullptr, napi_default,
850          nullptr},
851          {"destroyNullMessagePort", nullptr, destroyNullMessagePort, nullptr, nullptr, nullptr, napi_default, nullptr},
852      };
853      napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
854      return exports;
855  }
856  EXTERN_C_END
857
858  static napi_module demoModule = {
859      .nm_version = 1,
860      .nm_flags = 0,
861      .nm_filename = nullptr,
862      .nm_register_func = Init,
863      .nm_modname = "entry",
864      .nm_priv = ((void *)0),
865      .reserved = {0},
866  };
867
868  extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
869  ```
870
871<!--no_check-->