1# Mutual Invoking Between the Application and the Frontend Page (C/C++)
2
3This guide applies to the communication between ArkWeb applications and frontend pages. You can use the ArkWeb native APIs to conduct the service communication mechanism (native JSBridge for short) based on the application architecture.
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 [ArkWeb_ControllerAPI](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#arkweb_controllerapi) and [ArkWeb_ComponentAPI](../reference/apis-arkweb/_ark_web___component_a_p_i.md#arkweb_componentapi) provided by ArkWeb on the native side to implement the JSBridge capabilities.
8
9  ![arkweb_jsbridge_arch](figures/arkweb_jsbridge_arch.png)
10
11  The preceding figure shows a general architecture of applets with universal applicability. In this architecture, the logical layer depends on a JavaScript runtime built in an application, and the runtime runs in an existing C++ environment. The logic layer can communicate with the view layer (in which ArkWeb as the renderer) in the C++ environment through the native API, instead of using the ArkTS **JSBridge** 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 **JSBridge** API. Using the native **JSBridge** API is more efficient because the switching between the ArkTS and C++ environments is not required, as shown in the figure on the right.
14
15  ![arkweb_jsbridge_diff](figures/arkweb_jsbridge_diff.png)
16
17  The native JSBridge APIs are provided to avoid unnecessary switching to the ArkTS environment and allow callback to run in non-UI threads to avoid UI blocking.
18
19## Using the Native API to Implement JSBridge
20
21### Binding the Native API to ArkWeb
22
23* The **ArkWeb** component is declared on the ArkTS side. You need to define a **webTag** and transfer it to the native application side using Node-API. The **webTag** is used as a unique identifier of the corresponding component when an ArkWeb native API is used.
24
25* ArkTS side:
26
27  ```js
28  // Define a webTag and transfer it as an input parameter when WebviewController is created to establish the mapping between controller and webTag.
29  webTag: string = 'ArkWeb1';
30  controller: web_webview.WebviewController = new web_webview.WebviewController(this.webTag);
31  ...
32  // Use aboutToAppear() to pass webTag to C++ through Node-API. The webTag uniquely identifies the C++ ArkWeb component.
33  aboutToAppear() {
34    console.info("aboutToAppear")
35    // Initialize the web NDK.
36    testNapi.nativeWebInit(this.webTag);
37  }
38  ...
39  ```
40
41* C++ Side:
42
43  ```c++
44  // Parse and store the webTag.
45  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
46      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
47      size_t argc = 1;
48      napi_value args[1] = {nullptr};
49      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
50      // Obtain the first parameter webTag.
51      size_t webTagSize = 0;
52      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
53      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
54      size_t webTagLength = 0;
55      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
56      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
57
58      // Save the webTag in the instance object.
59      jsbridge_object_ptr = std::make_shared<JSBridgeObject>(webTagValue);
60      // ...
61  ```
62
63### Obtaining API Struct Using the Native API
64
65To invoke the native APIs, obtain the API structs on the ArkWeb native side first. You can use [OH_ArkWeb_GetNativeAPI](../reference/apis-arkweb/_web.md#oh_arkweb_getnativeapi()) to obtain the native ArkWeb API, and use [ArkWeb_ControllerAPI](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#arkweb_controllerapi) and [ArkWeb_ComponentAPI](../reference/apis-arkweb/_ark_web___component_a_p_i.md#arkweb_componentapi) to obtain function pointer structs based on the input parameter type. The [ArkWeb_ControllerAPI](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#arkweb_controllerapi) corresponds to the [web_webview.WebviewController API](../reference/apis-arkweb/js-apis-webview.md) on ArkTS, and the [ArkWeb_ComponentAPI](../reference/apis-arkweb/_ark_web___component_a_p_i.md#arkweb_componentapi) corresponds to the [ArkWeb component API](../reference/apis-arkweb/ts-basic-components-web.md) on ArkTS.
66
67  ```c++
68  static ArkWeb_ControllerAPI *controller = nullptr;
69  static ArkWeb_ComponentAPI *component = nullptr;
70  ...
71  controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
72  component = reinterpret_cast<ArkWeb_ComponentAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_COMPONENT));
73  ```
74
75### Registering Component Lifecycle Callback on the Native Side
76
77Use [ArkWeb_ComponentAPI](../reference/apis-arkweb/_ark_web___component_a_p_i.md#arkweb_componentapi) to register the component lifecycle callback. To avoid crash caused by mismatch between SDK and device ROM, you are advised to use [ARKWEB_MEMBER_MISSING](../reference/apis-arkweb/_web.md#arkweb_member_missing) to check whether there is a pointer to the function struct before calling an API.
78
79  ```c++
80  if (!ARKWEB_MEMBER_MISSING(component, onControllerAttached)) {
81      component->onControllerAttached(webTagValue, ValidCallback,
82                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
83  } else {
84      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onControllerAttached func not exist");
85  }
86
87  if (!ARKWEB_MEMBER_MISSING(component, onPageBegin)) {
88      component->onPageBegin(webTagValue, LoadStartCallback,
89                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
90  } else {
91      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageBegin func not exist");
92  }
93
94  if (!ARKWEB_MEMBER_MISSING(component, onPageEnd)) {
95      component->onPageEnd(webTagValue, LoadEndCallback,
96                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
97  } else {
98      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageEnd func not exist");
99  }
100
101  if (!ARKWEB_MEMBER_MISSING(component, onDestroy)) {
102      component->onDestroy(webTagValue, DestroyCallback,
103                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
104  } else {
105      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onDestroy func not exist");
106  }
107  ```
108
109### Invoking Application Functions on the Frontend Page
110
111Use [registerJavaScriptProxy](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#registerjavascriptproxy) to register the application function in the frontend page. You are advised to register the function in [onControllerAttached](../reference/apis-arkweb/_ark_web___component_a_p_i.md#oncontrollerattached). In other cases, you need to call [refresh](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#refresh) for the registration.
112
113  ```c++
114  // Register an object.
115  OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy begin");
116  ArkWeb_ProxyMethod method1 = {"method1", ProxyMethod1, static_cast<void *>(jsbridge_object_ptr->GetWeakPt  ())};
117  ArkWeb_ProxyMethod method2 = {"method2", ProxyMethod2, static_cast<void *>(jsbridge_object_ptr->GetWeakPt  ())};
118  ArkWeb_ProxyMethod methodList[2] = {method1, method2};
119  // Call the NDK API to register an object.
120  // In this case, you can use proxy.method1 and proxy.method2 to call ProxyMethod1 and ProxyMethod2 in this file on HTML5 pages.
121  ArkWeb_ProxyObject proxyObject = {"ndkProxy", methodList, 2};
122  controller->registerJavaScriptProxy(webTag, &proxyObject);
123  ```
124
125### Invoking Frontend Page Functions on the Application
126
127Use [runJavaScript](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#runjavascript) to invoke frontend page functions.
128
129  ```c++
130  // Construct a struct executed in runJS.
131  char* jsCode = "runJSRetStr()";
132  ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode, bufferSize, &JSBridgeObject::StaticRunJavaScriptCallback,
133                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
134  // Call runJSRetStr() of the frontend page.
135  controller->runJavaScript(webTagValue, &object);
136  ```
137
138### Sample Code
139
140* Frontend page code:
141
142  ```html
143  <!-- entry/src/main/resources/rawfile/runJS.html -->
144  <!-- runJS.html -->
145  <!DOCTYPE html>
146  <html lang="en-gb">
147  <head>
148      <meta name="viewport" content="width=device-width, initial-scale=1.0">
149      <title>run javascript demo</title>
150  </head>
151  <body>
152  <h1>run JavaScript Ext demo</h1>
153  <p id="webDemo"></p>
154  <br>
155  <button type="button" style="height:30px;width:200px" onclick="testNdkProxyObjMethod1()">test ndk method1 ! </button>
156  <br>
157  <br>
158  <button type="button" style="height:30px;width:200px" onclick="testNdkProxyObjMethod2()">test ndk method2 ! </button>
159  <br>
160
161  </body>
162  <script type="text/javascript">
163
164  function testNdkProxyObjMethod1() {
165        if (window.ndkProxy == undefined) {
166              document.getElementById("webDemo").innerHTML = "ndkProxy undefined"
167              return "objName undefined"
168        }
169
170        if (window.ndkProxy.method1 == undefined) {
171              document.getElementById("webDemo").innerHTML = "ndkProxy method1 undefined"
172              return "objName  test undefined"
173        }
174
175        if (window.ndkProxy.method2 == undefined) {
176              document.getElementById("webDemo").innerHTML = "ndkProxy method2 undefined"
177              return "objName  test undefined"
178        }
179        window.ndkProxy.method1("hello", "world", [1.2, -3.4, 123.456], ["Saab", "Volvo", "BMW", undefined], 1.23456, 123789, true, false, 0,  undefined);
180  }
181
182  function testNdkProxyObjMethod2() {
183        if (window.ndkProxy == undefined) {
184              document.getElementById("webDemo").innerHTML = "ndkProxy undefined"
185              return "objName undefined"
186        }
187
188        if (window.ndkProxy.method1 == undefined) {
189              document.getElementById("webDemo").innerHTML = "ndkProxy method1 undefined"
190              return "objName  test undefined"
191        }
192
193        if (window.ndkProxy.method2 == undefined) {
194              document.getElementById("webDemo").innerHTML = "ndkProxy method2 undefined"
195              return "objName  test undefined"
196        }
197
198      var student = {
199              name:"zhang",
200              sex:"man",
201              age:25
202      };
203      var cars = [student, 456, false, 4.567];
204      let params = "[\"{\\\"scope\\\"]";
205
206      window.ndkProxy.method2("hello", "world", false, cars, params);
207  }
208
209  function runJSRetStr(data) {
210      const d = new Date();
211      let time = d.getTime();
212      return JSON.stringify(time)
213  }
214  </script>
215  </html>
216  ```
217
218* Code in ArkTS:
219
220  ```javascript
221  // entry/src/main/ets/pages/Index.ets
222  import testNapi from 'libentry.so';
223  import { webview } from '@kit.ArkWeb';
224
225  class testObj {
226    constructor() {
227    }
228
229    test(): string {
230      console.log('ArkUI Web Component');
231      return "ArkUI Web Component";
232    }
233
234    toString(): void {
235      console.log('Web Component toString');
236    }
237  }
238
239  @Entry
240  @Component
241  struct Index {
242    webTag: string = 'ArkWeb1';
243    controller: webview.WebviewController = new webview.WebviewController(this.webTag);
244    @State testObjtest: testObj = new testObj();
245
246    aboutToAppear() {
247      console.info("aboutToAppear")
248      // Initialize the web NDK.
249      testNapi.nativeWebInit(this.webTag);
250    }
251
252    build() {
253      Column() {
254        Row() {
255          Button('runJS hello')
256            .fontSize(12)
257            .onClick(() => {
258              testNapi.runJavaScript(this.webTag, "runJSRetStr(\"" + "hello" + "\")");
259            })
260        }.height('20%')
261
262        Row() {
263          Web({ src: $rawfile('runJS.html'), controller: this.controller })
264            .javaScriptAccess(true)
265            .fileAccess(true)
266            .onControllerAttached(() => {
267              console.error("ndk onControllerAttached webId: " + this.controller.getWebId());
268            })
269        }.height('80%')
270      }
271    }
272  }
273  ```
274
275* ArkTS APIs exposed on the Node-API side:
276
277  ```javascript
278  // entry/src/main/cpp/types/libentry/index.d.ts
279  export const nativeWebInit: (webName: string) => void;
280  export const runJavaScript: (webName: string, jsCode: string) => void;
281  ```
282
283* Compilation configuration on the Node-API side in **entry/src/main/cpp/CMakeLists.txt**.
284
285  ```c++
286  # the minimum version of CMake.
287  cmake_minimum_required(VERSION 3.4.1)
288  project(NDKJSBridg)
289
290  set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
291
292  if(DEFINED PACKAGE_FIND_FILE)
293      include(${PACKAGE_FIND_FILE})
294  endif()
295
296  include_directories(${NATIVERENDER_ROOT_PATH}
297                      ${NATIVERENDER_ROOT_PATH}/include)
298
299  add_library(entry SHARED hello.cpp jsbridge_object.cpp)
300
301  find_library(
302      # Sets the name of the path variable.
303      hilog-lib
304      # Specifies the name of the NDK library that
305      # you want CMake to locate.
306      hilog_ndk.z
307  )
308
309  target_link_libraries(entry PUBLIC libace_napi.z.so ${hilog-lib} libohweb.so)
310  ```
311
312* Node-API layer code:
313
314  ```c++
315  // entry/src/main/cpp/hello.cpp
316  #include "napi/native_api.h"
317  #include <bits/alltypes.h>
318  #include <memory>
319  #include <string>
320  #include <sys/types.h>
321  #include <thread>
322
323  #include "hilog/log.h"
324  #include "web/arkweb_interface.h"
325  #include "jsbridge_object.h"
326
327  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
328  std::shared_ptr<JSBridgeObject> jsbridge_object_ptr = nullptr;
329  static ArkWeb_ControllerAPI *controller = nullptr;
330  static ArkWeb_ComponentAPI *component = nullptr;
331
332  // Send the JS script to the HTML5 side for execution. This method is a callback of the execution result.
333  static void RunJavaScriptCallback(const char *webTag, const char *result, void *userData) {
334      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RunJavaScriptCallback webTag:%{public}s", webTag);
335      if (!userData) {
336          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RunJavaScriptCallback userData is nullptr");
337          return;
338      }
339      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
340      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
341          jsb_ptr->RunJavaScriptCallback(result);
342      } else {
343          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
344                       "ndk RunJavaScriptCallback jsb_weak_ptr lock failed");
345      }
346  }
347
348  // This example registers one object and two methods.
349  static void ProxyMethod1(const char *webTag, const ArkWeb_JavaScriptBridgeData *dataArray, size_t arraySize, void *userData) {
350      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 webTag:%{public}s", webTag);
351      if (!userData) {
352          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 userData is nullptr");
353          return;
354      }
355      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
356      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
357          jsb_ptr->ProxyMethod1(dataArray, arraySize);
358      } else {
359          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 jsb_weak_ptr lock failed");
360      }
361  }
362
363  static void ProxyMethod2(const char *webTag, const ArkWeb_JavaScriptBridgeData *dataArray, size_t arraySize, void *userData) {
364      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 webTag:%{public}s", webTag);
365      if (!userData) {
366          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 userData is nullptr");
367          return;
368      }
369      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
370
371      std::string jsCode = "runJSRetStr()";
372      ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode.c_str(), jsCode.size(),
373                                       &JSBridgeObject::StaticRunJavaScriptCallback,
374                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
375      controller->runJavaScript(webTag, &object);
376
377      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
378          jsb_ptr->ProxyMethod2(dataArray, arraySize);
379      } else {
380          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 jsb_weak_ptr lock failed");
381      }
382  }
383
384  void ValidCallback(const char *webTag, void *userData) {
385      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback webTag: %{public}s", webTag);
386      if (!userData) {
387          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback userData is nullptr");
388          return;
389      }
390      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
391      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
392          jsb_ptr->SaySomething("ValidCallback");
393      } else {
394          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback jsb_weak_ptr lock failed");
395      }
396
397      // Register an object.
398      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy begin");
399      ArkWeb_ProxyMethod method1 = {"method1", ProxyMethod1, static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
400      ArkWeb_ProxyMethod method2 = {"method2", ProxyMethod2, static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
401      ArkWeb_ProxyMethod methodList[2] = {method1, method2};
402      // Call the NDK API to register an object.
403      // In this case, you can use proxy.method1 and proxy.method2 to call ProxyMethod1 and ProxyMethod2 in this file on HTML5 pages.
404      ArkWeb_ProxyObject proxyObject = {"ndkProxy", methodList, 2};
405      controller->registerJavaScriptProxy(webTag, &proxyObject);
406
407      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy end");
408  }
409
410  void LoadStartCallback(const char *webTag, void *userData) {
411      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback webTag: %{public}s", webTag);
412      if (!userData) {
413          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback userData is nullptr");
414          return;
415      }
416      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
417      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
418          jsb_ptr->SaySomething("LoadStartCallback");
419      } else {
420          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback jsb_weak_ptr lock failed");
421      }
422  }
423
424  void LoadEndCallback(const char *webTag, void *userData) {
425      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback webTag: %{public}s", webTag);
426      if (!userData) {
427          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback userData is nullptr");
428          return;
429      }
430      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
431      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
432          jsb_ptr->SaySomething("LoadEndCallback");
433      } else {
434          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback jsb_weak_ptr lock failed");
435      }
436  }
437
438  void DestroyCallback(const char *webTag, void *userData) {
439      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestoryCallback webTag: %{public}s", webTag);
440      if (!userData) {
441          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestroyCallback userData is nullptr");
442          return;
443      }
444      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
445      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
446          jsb_ptr->SaySomething("DestroyCallback");
447      } else {
448          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestroyCallback jsb_weak_ptr lock failed");
449      }
450  }
451
452  void SetComponentCallback(ArkWeb_ComponentAPI * component, const char* webTagValue) {
453      if (!ARKWEB_MEMBER_MISSING(component, onControllerAttached)) {
454          component->onControllerAttached(webTagValue, ValidCallback,
455                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
456      } else {
457          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onControllerAttached func not exist");
458      }
459
460      if (!ARKWEB_MEMBER_MISSING(component, onPageBegin)) {
461          component->onPageBegin(webTagValue, LoadStartCallback,
462                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
463      } else {
464          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageBegin func not exist");
465      }
466
467      if (!ARKWEB_MEMBER_MISSING(component, onPageEnd)) {
468          component->onPageEnd(webTagValue, LoadEndCallback,
469                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
470      } else {
471          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageEnd func not exist");
472      }
473
474      if (!ARKWEB_MEMBER_MISSING(component, onDestroy)) {
475          component->onDestroy(webTagValue, DestroyCallback,
476                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
477      } else {
478          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onDestroy func not exist");
479      }
480  }
481
482  // Parse and store the webTag.
483  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
484      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
485      size_t argc = 1;
486      napi_value args[1] = {nullptr};
487      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
488      // Obtain the first parameter webTag.
489      size_t webTagSize = 0;
490      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
491      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
492      size_t webTagLength = 0;
493      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
494      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
495
496      // Save the webTag in the instance object.
497      jsbridge_object_ptr = std::make_shared<JSBridgeObject>(webTagValue);
498      if (jsbridge_object_ptr)
499          jsbridge_object_ptr->Init();
500
501      controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
502      component = reinterpret_cast<ArkWeb_ComponentAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_COMPONENT));
503      SetComponentCallback(component, webTagValue);
504
505      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit end");
506      return nullptr;
507  }
508
509  // Send the JS script to the HTML5 side for execution.
510  static napi_value RunJavaScript(napi_env env, napi_callback_info info) {
511      size_t argc = 2;
512      napi_value args[2] = {nullptr};
513      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
514
515      // Obtain the first parameter webTag.
516      size_t webTagSize = 0;
517      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
518      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
519      size_t webTagLength = 0;
520      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
521      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk OH_NativeArkWeb_RunJavaScript webTag:%{public}s",
522                   webTagValue);
523
524      // Obtain the second parameter jsCode.
525      size_t bufferSize = 0;
526      napi_get_value_string_utf8(env, args[1], nullptr, 0, &bufferSize);
527      char *jsCode = new (std::nothrow) char[bufferSize + 1];
528      size_t byteLength = 0;
529      napi_get_value_string_utf8(env, args[1], jsCode, bufferSize + 1, &byteLength);
530
531      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
532                   "ndk OH_NativeArkWeb_RunJavaScript jsCode len:%{public}zu", strlen(jsCode));
533
534      // Construct a struct executed in runJS.
535      ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode, bufferSize, &JSBridgeObject::StaticRunJavaScriptCallback,
536                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
537      controller->runJavaScript(webTagValue, &object);
538      return nullptr;
539  }
540
541  EXTERN_C_START
542  static napi_value Init(napi_env env, napi_value exports) {
543      napi_property_descriptor desc[] = {
544          {"nativeWebInit", nullptr, NativeWebInit, nullptr, nullptr, nullptr, napi_default, nullptr},
545          {"runJavaScript", nullptr, RunJavaScript, nullptr, nullptr, nullptr, napi_default, nullptr},
546      };
547      napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
548      return exports;
549  }
550  EXTERN_C_END
551
552  static napi_module demoModule = {
553      .nm_version = 1,
554      .nm_flags = 0,
555      .nm_filename = nullptr,
556      .nm_register_func = Init,
557      .nm_modname = "entry",
558      .nm_priv = ((void *)0),
559      .reserved = {0},
560  };
561
562  extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
563  ```
564
565* Native service code:
566
567  ```c++
568  // entry/src/main/cpp/jsbridge_object.h
569  #include "web/arkweb_type.h"
570  #include <string>
571
572  class JSBridgeObject : public std::enable_shared_from_this<JSBridgeObject> {
573  public:
574      JSBridgeObject(const char* webTag);
575      ~JSBridgeObject() = default;
576      void Init();
577      std::weak_ptr<JSBridgeObject>* GetWeakPtr();
578      static void StaticRunJavaScriptCallback(const char *webTag, const ArkWeb_JavaScriptBridgeData *data, void *userData);
579      void RunJavaScriptCallback(const char *result);
580      void ProxyMethod1(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize);
581      void ProxyMethod2(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize);
582      void SaySomething(const char* say);
583
584  private:
585      std::string webTag_;
586      std::weak_ptr<JSBridgeObject> weak_ptr_;
587  };
588  ```
589
590  ```c++
591  // entry/src/main/cpp/jsbridge_object.cpp
592  #include "jsbridge_object.h"
593
594  #include "hilog/log.h"
595
596  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
597
598  JSBridgeObject::JSBridgeObject(const char *webTag) : webTag_(webTag) {}
599
600  void JSBridgeObject::Init() { weak_ptr_ = shared_from_this(); }
601
602  std::weak_ptr<JSBridgeObject> *JSBridgeObject::GetWeakPtr() { return &weak_ptr_; }
603
604  void JSBridgeObject::StaticRunJavaScriptCallback(const char *webTag, const ArkWeb_JavaScriptBridgeData *data,
605                                                   void *userData) {
606      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
607                   "JSBridgeObject StaticRunJavaScriptCallback webTag:%{public}s", webTag);
608      if (!userData) {
609          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
610                       "JSBridgeObject StaticRunJavaScriptCallback userData is nullptr");
611          return;
612      }
613      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
614      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
615          std::string result((char *)data->buffer, data->size);
616          jsb_ptr->RunJavaScriptCallback(result.c_str());
617      } else {
618          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
619                       "JSBridgeObject StaticRunJavaScriptCallback jsb_weak_ptr lock failed");
620      }
621  }
622
623  void JSBridgeObject::RunJavaScriptCallback(const char *result) {
624      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
625                   "JSBridgeObject OH_NativeArkWeb_RunJavaScript result:%{public}s", result);
626  }
627
628  void JSBridgeObject::ProxyMethod1(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize) {
629      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject ProxyMethod1 argc:%{public}d",
630                   arraySize);
631      for (int i = 0; i < arraySize; i++) {
632          std::string result((char *)dataArray[i].buffer, dataArray[i].size);
633          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
634                       "JSBridgeObject ProxyMethod1 argv[%{public}d]:%{public}s, size:%{public}d", i, result.c_str(),
635                       dataArray[i].size);
636      }
637  }
638
639  void JSBridgeObject::ProxyMethod2(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize) {
640      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject ProxyMethod2 argc:%{public}d",
641                   arraySize);
642      for (int i = 0; i < arraySize; i++) {
643          std::string result((char *)dataArray[i].buffer, dataArray[i].size);
644          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
645                       "JSBridgeObject ProxyMethod2 argv[%{public}d]:%{public}s, size:%{public}d", i, result.c_str(),
646                       dataArray[i].size);
647      }
648  }
649
650  void JSBridgeObject::SaySomething(const char *say) {
651      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject SaySomething argc:%{public}s", say);
652  }
653  ```
654