1# 建立应用侧与前端页面数据通道(C/C++)
2
3前端页面和应用侧之间可以使用Native方法实现两端通信(以下简称Native PostWebMessage),可解决ArkTS环境的冗余切换,同时允许发送消息、回调在非UI线程上运行,避免造成UI阻塞。当前只支持string和buffer数据类型。
4
5## 适用的应用架构
6
7应用使用ArkTS、C++语言混合开发,或本身应用架构较贴近于小程序架构,自带C++侧环境,推荐使用ArkWeb在Native侧提供的[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)、[ArkWeb_WebMessagePortAPI](../reference/apis-arkweb/_ark_web___web_message_port_a_p_i.md#arkweb_webmessageportapi)实现PostWebMessage功能。
8
9  ![arkweb_jsbridge_arch](figures/arkweb_jsbridge_arch.png)
10
11  上图展示了具有普遍适用性的小程序的通用架构。在这一架构中,逻辑层依赖于应用程序自带的JavaScript运行时,该运行时在一个已有的C++环境中运行。通过Native接口,逻辑层能够直接在C++环境中与视图层(其中ArkWeb充当渲染器)进行通信,无需回退至ArkTS环境使用ArkTS PostWebMessage接口。
12
13  左图是使用ArkTS PostWebMessage接口构建小程序的方案,,如红框所示,应用需要先调用到ArkTS环境,再调用到C++环境。右图是使用Native PostWebMessage接口构建小程序的方案,不需要ArkTS环境和C++环境的切换,执行效率更高。
14
15  ![arkweb_postwebmessage_diff](figures/arkweb_postwebmessage_diff.png)
16
17## 使用Native接口实现PostWebMessage通信
18
19### 使用Native接口绑定ArkWeb
20
21- ArkWeb组件声明在ArkTS侧,需要用户自定义一个标识webTag,并将webTag通过Node-API传至应用C++侧。后续ArkWeb Native接口使用时,均需webTag作为对应组件的唯一标识。
22
23- ArkTS侧
24
25  ```ts
26  import { webview } from '@kit.ArkWeb';
27  // 自定义webTag,在WebviewController创建时作为入参传入,建立controller与webTag的映射关系
28  webTag: string = 'ArkWeb1';
29  controller: webview.WebviewController = new webview.WebviewController(this.webTag);
30  ...
31  // aboutToAppear中将webTag通过Node-API接口传入C++侧,作为C++侧ArkWeb组件的唯一标识
32  aboutToAppear() {
33    console.info("aboutToAppear")
34    // 初始化web ndk
35    testNapi.nativeWebInit(this.webTag);
36  }
37  ...
38  ```
39
40### 使用Native接口获取API结构体
41
42ArkWeb Native侧得先获取API结构体,才能调用结构体里的Native API。ArkWeb Native侧API通过函数[OH_ArkWeb_GetNativeAPI](../reference/apis-arkweb/_web.md#oh_arkweb_getnativeapi())获取,根据入参type不同,可获取对应的函数指针结构体。其中本指导涉及[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)、[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### 完整示例
56
57在调用API前建议通过[ARKWEB_MEMBER_MISSING](../reference/apis-arkweb/_web.md#arkweb_member_missing)校验该函数结构体是否有对应函数指针,避免SDK与设备ROM不匹配导致crash问题。[createWebMessagePorts](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#createwebmessageports)、[postWebMessage](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#postwebmessage)、[close](../reference/apis-arkweb/_ark_web___web_message_port_a_p_i.md#close)需运行在UI线程。
58
59* 前端页面代码
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测试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. 保存从应用侧发送过来的端口。
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. 接收应用侧发送过来的消息.
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 = "执行函数失败"
116  };
117
118  // 3. 使用h5Port向应用侧发送消息。
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      // 构造器
164      this.myProperty = 'Hello, World!';
165    }
166
167    myMethod() {
168      // 实例方法
169      console.log(this.myProperty);
170    }
171
172    static myStaticMethod() {
173      // 静态方法
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侧代码
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      // 初始化web ndk
207      testNapi.nativeWebInit(this.webTag);
208    }
209
210    aboutToDisAppear() {
211      console.error("aboutToDisAppear")
212    }
213
214    build() {
215      Scroll() {
216        Column({ space: 10 }) {
217          // 展示H5接收到的内容
218          Text("H5侧接收到应用侧发送消息展示")
219          TextArea({text: this.h5Log})
220            .id("log_area")
221            .width("100%")
222            .height(100)
223            .border({ width: 1 })
224          Text("应用侧按钮")
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("H5侧发送按钮")
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* Node-API侧暴露ArkTS接口
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* 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层代码
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      // 获取第一个参数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      // 获取第一个参数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      // 初始化端口
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      // 把其中一个端口发送给HTML
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      // 获取第一个参数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      // 发送消息
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  // 在线程中发消息
611  void sendMessage(const char *webTag, const ArkWeb_WebMessagePtr message) {
612      // 发送1000次
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      // 获取第一个参数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      // 构造消息
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      // 创建线程
648      for (int i = 0; i < numThreads; ++i) {
649          threads[i] = std::thread(sendMessage, webTagValue, message);
650      }
651
652      // 等待所有线程完成
653      for (int i = 0; i < numThreads; ++i) {
654          threads[i].detach();
655      }
656      return nullptr;
657  }
658
659  // 在线程中注册回调
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      // 获取第一个参数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      // 注册回调
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      // 获取第一个参数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      // 发送消息
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      // 获取第一个参数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      // 发送消息
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      // 获取第一个参数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      // 注册回调
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      // 获取第一个参数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      // 关闭端口,先调用close,再调用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      // 获取第一个参数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      // 释放内存,先调用close,再调用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      // 获取第一个参数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      // 释放内存,先调用close,再调用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  ```