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