• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4For details about how to optimize the performance of JSBridge, see [JSBridge Optimization Solution] (https://developer.huawei.com/consumer/en/doc/best-practices/bpta-web-develop-optimization#section58781855115017).
5
6## Applicable Application Architecture
7
8If 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/capi-web-arkweb-controllerapi.md) and [ArkWeb_ComponentAPI](../reference/apis-arkweb/capi-web-arkweb-componentapi.md) provided by ArkWeb on the native side to implement the JSBridge capabilities.
9
10  ![arkweb_jsbridge_arch](figures/arkweb_jsbridge_arch.png)
11
12  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.
13
14  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.
15
16  ![arkweb_jsbridge_diff](figures/arkweb_jsbridge_diff.png)
17
18  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.
19
20## Using Native APIs to Implement JSBridge Communication (Recommended)
21In the previous version, the return value of native synchronization APIs is fixed to void. However, to meet service requirements, alternative APIs are introduced since API version 18 to support return values of the Boolean, string, and buffer types.
22
23In addition, the [permission](#invoking-application-functions-on-the-frontend-page) field is added for the synchronous API [registerJavaScriptProxyEx](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#registerjavascriptproxyex) and asynchronous API [registerAsyncJavaScriptProxyEx](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#registerasyncjavascriptproxyex) to control the invoking permission.
24
25### Substitute APIs
26
27|             Unrecommended API           |               Substitute API               |            Description           |
28| :-----------------------------------: | :-----------------------------------: | :------------------------: |
29|         ArkWeb_OnJavaScriptProxyCallback      |      ArkWeb_OnJavaScriptProxyCallbackWithResult             |      Defines a callback used when the proxy method is executed.     |
30|     ArkWeb_ProxyMethod     |         ArkWeb_ProxyMethodWithResult          |        Defines a proxy method.         |
31|     ArkWeb_ProxyObject     |         ArkWeb_ProxyObjectWithResult          |        Defines a proxy object.         |
32|     registerJavaScriptProxy     |         registerJavaScriptProxyEx    |  Registers a JavaScript object with the window. Synchronous APIs of this object can then be invoked in the window.         |
33|     registerAsyncJavaScriptProxy     |         registerAsyncJavaScriptProxyEx    |  Registers a JavaScript object with the window. Asynchronous APIs of this object can then be invoked in the window.         |
34
35### Binding the Native API to ArkWeb
36
37* 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.
38
39* ArkTS side:
40
41  ```js
42  // Define a webTag and transfer it as an input parameter when WebviewController is created to establish the mapping between controller and webTag.
43  webTag: string = 'ArkWeb1';
44  controller: web_webview.WebviewController = new web_webview.WebviewController(this.webTag);
45
46  // In the aboutToAppear method, pass webTag to the C++ side through the Node-API. The C++ side uses webTag to uniquely identify the Web component.
47  aboutToAppear() {
48    console.info("aboutToAppear")
49    // Initialize the web NDK.
50    testNapi.nativeWebInit(this.webTag);
51  }
52  ```
53
54* C++ Side:
55
56  ```c++
57  // Parse and store the webTag.
58  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
59      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
60      size_t argc = 1;
61      napi_value args[1] = {nullptr};
62      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
63      // Obtain the first parameter webTag.
64      size_t webTagSize = 0;
65      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
66      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
67      size_t webTagLength = 0;
68      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
69      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
70
71      // Save the webTag in the instance object.
72      jsbridge_object_ptr = std::make_shared<JSBridgeObject>(webTagValue);
73      // ...
74  ```
75
76### Obtaining API Struct Using the Native API
77
78On the ArkWeb native side, you need to obtain the API struct before invoking the native API in the struct. Through [OH_ArkWeb_GetNativeAPI](../reference/apis-arkweb/capi-arkweb-interface-h.md#oh_arkweb_getnativeapi), you can obtain the structs of [ArkWeb_ControllerAPI](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md) and [ArkWeb_ComponentAPI](../reference/apis-arkweb/capi-web-arkweb-componentapi.md) based on the input parameter **type**. [ArkWeb_ControllerAPI](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md) corresponds to [web_webview.WebviewController API](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md) on the ArkTS side, and [ArkWeb_ComponentAPI](../reference/apis-arkweb/capi-web-arkweb-componentapi.md) corresponds to [ArkWeb Component API](../reference/apis-arkweb/arkts-basic-components-web.md) on the ArkTS side.
79
80  ```c++
81  static ArkWeb_ControllerAPI *controller = nullptr;
82  static ArkWeb_ComponentAPI *component = nullptr;
83  // ...
84  controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
85  component = reinterpret_cast<ArkWeb_ComponentAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_COMPONENT));
86  ```
87
88### Registering Component Lifecycle Callback on the Native Side
89
90Register the component lifecycle callback using [ArkWeb_ComponentAPI](../reference/apis-arkweb/capi-web-arkweb-componentapi.md). Before calling the API, you are advised to use [ARKWEB_MEMBER_MISSING](../reference/apis-arkweb/capi-arkweb-type-h.md#macros) to check whether the function struct has the corresponding pointer to avoid crash caused by mismatch between the SDK and the device ROM.
91
92  ```c++
93  if (!ARKWEB_MEMBER_MISSING(component, onControllerAttached)) {
94      component->onControllerAttached(webTagValue, ValidCallback,
95                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
96  } else {
97      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onControllerAttached func not exist");
98  }
99
100  if (!ARKWEB_MEMBER_MISSING(component, onPageBegin)) {
101      component->onPageBegin(webTagValue, LoadStartCallback,
102                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
103  } else {
104      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageBegin func not exist");
105  }
106
107  if (!ARKWEB_MEMBER_MISSING(component, onPageEnd)) {
108      component->onPageEnd(webTagValue, LoadEndCallback,
109                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
110  } else {
111      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageEnd func not exist");
112  }
113
114  if (!ARKWEB_MEMBER_MISSING(component, onDestroy)) {
115      component->onDestroy(webTagValue, DestroyCallback,
116                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
117  } else {
118      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onDestroy func not exist");
119  }
120  ```
121
122### Invoking Application Functions on the Frontend Page
123
124Use [registerJavaScriptProxyEx](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#registerjavascriptproxyex) to register the application function with the frontend page. You are advised to register the application function in the [onControllerAttached](../reference/apis-arkweb/capi-web-arkweb-componentapi.md#oncontrollerattached) callback. To register the application function at other time, you need to call [refresh](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#refresh) for the registration to take effect.
125
126  ```c++
127  // Register an object.
128  OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk registerJavaScriptProxyEx begin");
129  ArkWeb_ProxyMethodWithResult method1 = {"method1", ProxyMethod1, static_cast<void *>(jsbridge_object_ptr->GetWeakPt  ())};
130  ArkWeb_ProxyMethodWithResult method2 = {"method2", ProxyMethod2, static_cast<void *>(jsbridge_object_ptr->GetWeakPt  ())};
131  ArkWeb_ProxyMethodWithResult methodList[2] = {method1, method2};
132  // Call the NDK API to register an object.
133  // In this case, you can use proxy.method1 and proxy.method2 to call ProxyMethod1 and ProxyMethod2 in this file on HTML5 pages.
134  ArkWeb_ProxyObjectWithResult proxyObject = {"ndkProxy", methodList, 2};
135  // If the permission parameter is empty, permission control is not performed.
136  controller->registerJavaScriptProxyEx(webTag, &proxyObject, /*permission*/"");
137  ```
138
139  - The **permission** parameter is a JSON string as follows:
140  ```json
141  {
142    "javascriptProxyPermission": {
143      "urlPermissionList": [       // Object-level permission. If it is granted, all methods are available.
144        {
145          "scheme": "resource",    // Exact match. The value cannot be empty.
146          "host": "rawfile",       // Exact match. The value cannot be empty.
147          "port": "",              // Exact match. If the value is empty, it is not checked.
148          "path": ""               // Prefix match. If the value is empty, it is not checked.
149        },
150        {
151          "scheme": "https",       // Exact match. The value cannot be empty.
152          "host": "xxx.com",       // Exact match. The value cannot be empty.
153          "port": "8080",          // Exact match. If the value is empty, it is not checked.
154          "path": "a/b/c"          // Prefix match. If the value is empty, it is not checked.
155        }
156      ],
157      "methodList": [
158        {
159          "methodName": "test",
160          "urlPermissionList": [   // Method-level permission.
161            {
162              "scheme": "https",   // Exact match. The value cannot be empty.
163              "host": "xxx.com",   // Exact match. The value cannot be empty.
164              "port": "",          // Exact match. If the value is empty, it is not checked.
165              "path": ""           // Prefix match. If the value is empty, it is not checked.
166            },
167            {
168              "scheme": "resource",// Exact match. The value cannot be empty.
169              "host": "rawfile",   // Exact match. The value cannot be empty.
170              "port": "",          // Exact match. If the value is empty, it is not checked.
171              "path": ""           // Prefix match. If the value is empty, it is not checked.
172            }
173          ]
174        },
175        {
176          "methodName": "test11",
177          "urlPermissionList": [   // Method-level permission.
178            {
179              "scheme": "q",       // Exact match. The value cannot be empty.
180              "host": "r",         // Exact match. The value cannot be empty.
181              "port": "",          // Exact match. If the value is empty, it is not checked.
182              "path": "t"          // Prefix match. If the value is empty, it is not checked.
183            },
184            {
185              "scheme": "u",       // Exact match. The value cannot be empty.
186              "host": "v",         // Exact match. The value cannot be empty.
187              "port": "",          // Exact match. If the value is empty, it is not checked.
188              "path": ""           // Prefix match. If the value is empty, it is not checked.
189            }
190          ]
191        }
192      ]
193    }
194  }
195  ```
196
197### Invoking Frontend Page Functions on the Application
198
199Use [runJavaScript](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#runjavascript) to call the frontend page function.
200
201  ```c++
202  // Construct a struct executed in runJS.
203  char* jsCode = "runJSRetStr()";
204  ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode, bufferSize, &JSBridgeObject::StaticRunJavaScriptCallback,
205                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
206  // Call runJSRetStr() of the frontend page.
207  controller->runJavaScript(webTagValue, &object);
208  ```
209
210### Sample Code
211
212* Frontend page code:
213
214  ```html
215  <!-- entry/src/main/resources/rawfile/runJS.html -->
216  <!-- runJS.html -->
217  <!DOCTYPE html>
218  <html lang="en-gb">
219  <head>
220      <meta name="viewport" content="width=device-width, initial-scale=1.0">
221      <title>run javascript demo</title>
222  </head>
223  <body>
224  <h1>run JavaScript Ext demo</h1>
225  <p id="webDemo"></p>
226  <br>
227  <button type="button" style="height:30px;width:200px" onclick="testNdkProxyObjMethod1()">test ndk method1 ! </button>
228  <br>
229  <br>
230  <button type="button" style="height:30px;width:200px" onclick="testNdkProxyObjMethod2()">test ndk method2 ! </button>
231  <br>
232
233  </body>
234  <script type="text/javascript">
235
236  function testNdkProxyObjMethod1() {
237        if (window.ndkProxy == undefined) {
238              document.getElementById("webDemo").innerHTML = "ndkProxy undefined"
239              return "objName undefined"
240        }
241
242        if (window.ndkProxy.method1 == undefined) {
243              document.getElementById("webDemo").innerHTML = "ndkProxy method1 undefined"
244              return "objName  test undefined"
245        }
246
247        if (window.ndkProxy.method2 == undefined) {
248              document.getElementById("webDemo").innerHTML = "ndkProxy method2 undefined"
249              return "objName  test undefined"
250        }
251        let retStr = window.ndkProxy.method1("hello", "world", [1.2, -3.4, 123.456], ["Saab", "Volvo", "BMW", undefined], 1.23456, 123789, true, false, 0,  undefined);
252        console.log("ndkProxy and method1 is ok, " + retStr + ", type:" + typeof(retStr));
253  }
254
255  function testNdkProxyObjMethod2() {
256        if (window.ndkProxy == undefined) {
257              document.getElementById("webDemo").innerHTML = "ndkProxy undefined"
258              return "objName undefined"
259        }
260
261        if (window.ndkProxy.method1 == undefined) {
262              document.getElementById("webDemo").innerHTML = "ndkProxy method1 undefined"
263              return "objName  test undefined"
264        }
265
266        if (window.ndkProxy.method2 == undefined) {
267              document.getElementById("webDemo").innerHTML = "ndkProxy method2 undefined"
268              return "objName  test undefined"
269        }
270
271      var student = {
272              name:"zhang",
273              sex:"man",
274              age:25
275      };
276      var cars = [student, 456, false, 4.567];
277      let params = "[\"{\\\"scope\\\"]";
278
279      let retStr = window.ndkProxy.method2("hello", "world", false, cars, params);
280      console.log("ndkProxy and method2 is ok, " + retStr + ", type:" + typeof(retStr));
281  }
282
283  function runJSRetStr(data) {
284      const d = new Date();
285      let time = d.getTime();
286      return JSON.stringify(time)
287  }
288  </script>
289  </html>
290  ```
291
292* Code in ArkTS:
293
294  ```javascript
295  // entry/src/main/ets/pages/Index.ets
296  import testNapi from 'libentry.so';
297  import { webview } from '@kit.ArkWeb';
298
299  class testObj {
300    constructor() {
301    }
302
303    test(): string {
304      console.log('ArkUI Web Component');
305      return "ArkUI Web Component";
306    }
307
308    toString(): void {
309      console.log('Web Component toString');
310    }
311  }
312
313  @Entry
314  @Component
315  struct Index {
316    webTag: string = 'ArkWeb1';
317    controller: webview.WebviewController = new webview.WebviewController(this.webTag);
318    @State testObjtest: testObj = new testObj();
319
320    aboutToAppear() {
321      console.info("aboutToAppear")
322      // Initialize the web NDK.
323      testNapi.nativeWebInit(this.webTag);
324    }
325
326    build() {
327      Column() {
328        Row() {
329          Button('runJS hello')
330            .fontSize(12)
331            .onClick(() => {
332              testNapi.runJavaScript(this.webTag, "runJSRetStr(\"" + "hello" + "\")");
333            })
334        }.height('20%')
335
336        Row() {
337          Web({ src: $rawfile('runJS.html'), controller: this.controller })
338            .javaScriptAccess(true)
339            .fileAccess(true)
340            .onControllerAttached(() => {
341              console.error("ndk onControllerAttached webId: " + this.controller.getWebId());
342            })
343        }.height('80%')
344      }
345    }
346  }
347  ```
348
349* ArkTS APIs exposed on the Node-API side:
350
351  ```javascript
352  // entry/src/main/cpp/types/libentry/index.d.ts
353  export const nativeWebInit: (webName: string) => void;
354  export const runJavaScript: (webName: string, jsCode: string) => void;
355  ```
356
357* Compilation configuration on the Node-API side in **entry/src/main/cpp/CMakeLists.txt**.
358
359  ```c++
360  # the minimum version of CMake.
361  cmake_minimum_required(VERSION 3.4.1)
362  project(NDKJSBridg)
363
364  set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
365
366  if(DEFINED PACKAGE_FIND_FILE)
367      include(${PACKAGE_FIND_FILE})
368  endif()
369
370  include_directories(${NATIVERENDER_ROOT_PATH}
371                      ${NATIVERENDER_ROOT_PATH}/include)
372
373  add_library(entry SHARED hello.cpp jsbridge_object.cpp)
374
375  find_library(
376      # Sets the name of the path variable.
377      hilog-lib
378      # Specifies the name of the NDK library that
379      # you want CMake to locate.
380      hilog_ndk.z
381  )
382
383  target_link_libraries(entry PUBLIC libace_napi.z.so ${hilog-lib} libohweb.so)
384  ```
385
386* Node-API layer code:
387
388  ```c++
389  // entry/src/main/cpp/hello.cpp
390  #include "napi/native_api.h"
391  #include <bits/alltypes.h>
392  #include <memory>
393  #include <string>
394  #include <sys/types.h>
395  #include <thread>
396
397  #include "hilog/log.h"
398  #include "web/arkweb_interface.h"
399  #include "jsbridge_object.h"
400
401  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
402  std::shared_ptr<JSBridgeObject> jsbridge_object_ptr = nullptr;
403  static ArkWeb_ControllerAPI *controller = nullptr;
404  static ArkWeb_ComponentAPI *component = nullptr;
405  ArkWeb_JavaScriptValueAPI *javaScriptValueApi = nullptr;
406
407  // Send the JS script to the HTML5 side for execution. This method is a callback of the execution result.
408  static void RunJavaScriptCallback(const char *webTag, const char *result, void *userData) {
409      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RunJavaScriptCallback webTag:%{public}s", webTag);
410      if (!userData) {
411          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RunJavaScriptCallback userData is nullptr");
412          return;
413      }
414      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
415      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
416          jsb_ptr->RunJavaScriptCallback(result);
417      } else {
418          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
419                       "ndk RunJavaScriptCallback jsb_weak_ptr lock failed");
420      }
421  }
422
423  // This example registers one object and two methods.
424  static ArkWeb_JavaScriptValuePtr ProxyMethod1(const char *webTag, const ArkWeb_JavaScriptBridgeData *dataArray, size_t arraySize, void *userData) {
425      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 webTag:%{public}s", webTag);
426      if (!userData) {
427          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 userData is nullptr");
428          return nullptr;
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->ProxyMethod1(dataArray, arraySize);
433      } else {
434          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 jsb_weak_ptr lock failed");
435      }
436
437      bool boolValue = true;
438      return javaScriptValueApi->createJavaScriptValue(ArkWeb_JavaScriptValueType::ARKWEB_JAVASCRIPT_BOOL, (void*)(&boolValue), 1);
439  }
440
441  static ArkWeb_JavaScriptValuePtr ProxyMethod2(const char *webTag, const ArkWeb_JavaScriptBridgeData *dataArray, size_t arraySize, void *userData) {
442      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 webTag:%{public}s", webTag);
443      if (!userData) {
444          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 userData is nullptr");
445          return nullptr;
446      }
447      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
448
449      std::string jsCode = "runJSRetStr()";
450      ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode.c_str(), jsCode.size(),
451                                       &JSBridgeObject::StaticRunJavaScriptCallback,
452                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
453      controller->runJavaScript(webTag, &object);
454
455      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
456          jsb_ptr->ProxyMethod2(dataArray, arraySize);
457      } else {
458          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 jsb_weak_ptr lock failed");
459      }
460
461      std::string str = "this is a string";
462      return javaScriptValueApi->createJavaScriptValue(ArkWeb_JavaScriptValueType::ARKWEB_JAVASCRIPT_STRING, (void*)str.c_str(), str.length() + 1);
463  }
464
465  void ValidCallback(const char *webTag, void *userData) {
466      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback webTag: %{public}s", webTag);
467      if (!userData) {
468          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback userData is nullptr");
469          return;
470      }
471      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
472      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
473          jsb_ptr->SaySomething("ValidCallback");
474      } else {
475          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback jsb_weak_ptr lock failed");
476      }
477
478      // Register an object.
479      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk registerJavaScriptProxyEx begin");
480      ArkWeb_ProxyMethodWithResult method1 = {"method1", ProxyMethod1, static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
481      ArkWeb_ProxyMethodWithResult method2 = {"method2", ProxyMethod2, static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
482      ArkWeb_ProxyMethodWithResult methodList[2] = {method1, method2};
483      // Call the NDK API to register an object.
484      // In this case, you can use proxy.method1 and proxy.method2 to call ProxyMethod1 and ProxyMethod2 in this file on HTML5 pages.
485      ArkWeb_ProxyObjectWithResult proxyObject = {"ndkProxy", methodList, 2};
486      controller->registerJavaScriptProxyEx(webTag, &proxyObject, "");
487
488      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk registerJavaScriptProxyEx end");
489  }
490
491  void LoadStartCallback(const char *webTag, void *userData) {
492      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback webTag: %{public}s", webTag);
493      if (!userData) {
494          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback userData is nullptr");
495          return;
496      }
497      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
498      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
499          jsb_ptr->SaySomething("LoadStartCallback");
500      } else {
501          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback jsb_weak_ptr lock failed");
502      }
503  }
504
505  void LoadEndCallback(const char *webTag, void *userData) {
506      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback webTag: %{public}s", webTag);
507      if (!userData) {
508          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback userData is nullptr");
509          return;
510      }
511      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
512      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
513          jsb_ptr->SaySomething("LoadEndCallback");
514      } else {
515          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback jsb_weak_ptr lock failed");
516      }
517  }
518
519  void DestroyCallback(const char *webTag, void *userData) {
520      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestoryCallback webTag: %{public}s", webTag);
521      if (!userData) {
522          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestroyCallback userData is nullptr");
523          return;
524      }
525      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
526      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
527          jsb_ptr->SaySomething("DestroyCallback");
528      } else {
529          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestroyCallback jsb_weak_ptr lock failed");
530      }
531  }
532
533  void SetComponentCallback(ArkWeb_ComponentAPI * component, const char* webTagValue) {
534      if (!ARKWEB_MEMBER_MISSING(component, onControllerAttached)) {
535          component->onControllerAttached(webTagValue, ValidCallback,
536                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
537      } else {
538          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onControllerAttached func not exist");
539      }
540
541      if (!ARKWEB_MEMBER_MISSING(component, onPageBegin)) {
542          component->onPageBegin(webTagValue, LoadStartCallback,
543                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
544      } else {
545          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageBegin func not exist");
546      }
547
548      if (!ARKWEB_MEMBER_MISSING(component, onPageEnd)) {
549          component->onPageEnd(webTagValue, LoadEndCallback,
550                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
551      } else {
552          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageEnd func not exist");
553      }
554
555      if (!ARKWEB_MEMBER_MISSING(component, onDestroy)) {
556          component->onDestroy(webTagValue, DestroyCallback,
557                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
558      } else {
559          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onDestroy func not exist");
560      }
561  }
562
563  // Parse and store the webTag.
564  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
565    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
566    size_t argc = 1;
567    napi_value args[1] = {nullptr};
568    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
569    // Obtain the first parameter webTag.
570    size_t webTagSize = 0;
571    napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
572    char *webTagValue = new (std::nothrow) char[webTagSize + 1];
573    size_t webTagLength = 0;
574    napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
575    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
576
577    jsbridge_object_ptr = std::make_shared<JSBridgeObject>(webTagValue);
578    if (jsbridge_object_ptr)
579        jsbridge_object_ptr->Init();
580
581    controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
582    if (controller)
583        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_ControllerAPI success");
584
585    component = reinterpret_cast<ArkWeb_ComponentAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_COMPONENT));
586    if (component)
587        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_ComponentAPI success");
588
589    javaScriptValueApi =
590        reinterpret_cast<ArkWeb_JavaScriptValueAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_JAVASCRIPT_VALUE));
591    if (javaScriptValueApi)
592        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_JavaScriptValueAPI success");
593    else
594        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "get ArkWeb_JavaScriptValueAPI failed");
595
596    SetComponentCallback(component, webTagValue);
597
598    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit end");
599
600    return nullptr;
601  }
602
603  // Send the JS script to the HTML5 side for execution.
604  static napi_value RunJavaScript(napi_env env, napi_callback_info info) {
605      size_t argc = 2;
606      napi_value args[2] = {nullptr};
607      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
608
609      // Obtain the first parameter webTag.
610      size_t webTagSize = 0;
611      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
612      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
613      size_t webTagLength = 0;
614      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
615      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk OH_NativeArkWeb_RunJavaScript webTag:%{public}s",
616                   webTagValue);
617
618      // Obtain the second parameter jsCode.
619      size_t bufferSize = 0;
620      napi_get_value_string_utf8(env, args[1], nullptr, 0, &bufferSize);
621      char *jsCode = new (std::nothrow) char[bufferSize + 1];
622      size_t byteLength = 0;
623      napi_get_value_string_utf8(env, args[1], jsCode, bufferSize + 1, &byteLength);
624
625      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
626                   "ndk OH_NativeArkWeb_RunJavaScript jsCode len:%{public}zu", strlen(jsCode));
627
628      // Construct a struct executed in runJS.
629      ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode, bufferSize, &JSBridgeObject::StaticRunJavaScriptCallback,
630                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
631      controller->runJavaScript(webTagValue, &object);
632      return nullptr;
633  }
634
635  EXTERN_C_START
636  static napi_value Init(napi_env env, napi_value exports) {
637      napi_property_descriptor desc[] = {
638          {"nativeWebInit", nullptr, NativeWebInit, nullptr, nullptr, nullptr, napi_default, nullptr},
639          {"runJavaScript", nullptr, RunJavaScript, nullptr, nullptr, nullptr, napi_default, nullptr},
640      };
641      napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
642      return exports;
643  }
644  EXTERN_C_END
645
646  static napi_module demoModule = {
647      .nm_version = 1,
648      .nm_flags = 0,
649      .nm_filename = nullptr,
650      .nm_register_func = Init,
651      .nm_modname = "entry",
652      .nm_priv = ((void *)0),
653      .reserved = {0},
654  };
655
656  extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
657  ```
658
659* Native service code:
660
661  ```c++
662  // entry/src/main/cpp/jsbridge_object.h
663  #include "web/arkweb_type.h"
664  #include <string>
665
666  class JSBridgeObject : public std::enable_shared_from_this<JSBridgeObject> {
667  public:
668      JSBridgeObject(const char* webTag);
669      ~JSBridgeObject() = default;
670      void Init();
671      std::weak_ptr<JSBridgeObject>* GetWeakPtr();
672      static void StaticRunJavaScriptCallback(const char *webTag, const ArkWeb_JavaScriptBridgeData *data, void *userData);
673      void RunJavaScriptCallback(const char *result);
674      void ProxyMethod1(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize);
675      void ProxyMethod2(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize);
676      void SaySomething(const char* say);
677
678  private:
679      std::string webTag_;
680      std::weak_ptr<JSBridgeObject> weak_ptr_;
681  };
682  ```
683
684  ```c++
685  // entry/src/main/cpp/jsbridge_object.cpp
686  #include "jsbridge_object.h"
687
688  #include "hilog/log.h"
689
690  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
691
692  JSBridgeObject::JSBridgeObject(const char *webTag) : webTag_(webTag) {}
693
694  void JSBridgeObject::Init() { weak_ptr_ = shared_from_this(); }
695
696  std::weak_ptr<JSBridgeObject> *JSBridgeObject::GetWeakPtr() { return &weak_ptr_; }
697
698  void JSBridgeObject::StaticRunJavaScriptCallback(const char *webTag, const ArkWeb_JavaScriptBridgeData *data,
699                                                   void *userData) {
700      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
701                   "JSBridgeObject StaticRunJavaScriptCallback webTag:%{public}s", webTag);
702      if (!userData) {
703          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
704                       "JSBridgeObject StaticRunJavaScriptCallback userData is nullptr");
705          return;
706      }
707      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
708      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
709          std::string result((char *)data->buffer, data->size);
710          jsb_ptr->RunJavaScriptCallback(result.c_str());
711      } else {
712          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
713                       "JSBridgeObject StaticRunJavaScriptCallback jsb_weak_ptr lock failed");
714      }
715  }
716
717  void JSBridgeObject::RunJavaScriptCallback(const char *result) {
718      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
719                   "JSBridgeObject OH_NativeArkWeb_RunJavaScript result:%{public}s", result);
720  }
721
722  void JSBridgeObject::ProxyMethod1(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize) {
723      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject ProxyMethod1 argc:%{public}d",
724                   arraySize);
725      for (int i = 0; i < arraySize; i++) {
726          std::string result((char *)dataArray[i].buffer, dataArray[i].size);
727          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
728                       "JSBridgeObject ProxyMethod1 argv[%{public}d]:%{public}s, size:%{public}d", i, result.c_str(),
729                       dataArray[i].size);
730      }
731  }
732
733  void JSBridgeObject::ProxyMethod2(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize) {
734      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject ProxyMethod2 argc:%{public}d",
735                   arraySize);
736      for (int i = 0; i < arraySize; i++) {
737          std::string result((char *)dataArray[i].buffer, dataArray[i].size);
738          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
739                       "JSBridgeObject ProxyMethod2 argv[%{public}d]:%{public}s, size:%{public}d", i, result.c_str(),
740                       dataArray[i].size);
741      }
742  }
743
744  void JSBridgeObject::SaySomething(const char *say) {
745      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject SaySomething argc:%{public}s", say);
746  }
747  ```
748
749## Using the Native API to Implement JSBridge
750
751### Binding the Native API to ArkWeb
752
753* 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.
754
755* ArkTS side:
756
757  ```js
758  // Define a webTag and transfer it as an input parameter when WebviewController is created to establish the mapping between controller and webTag.
759  webTag: string = 'ArkWeb1';
760  controller: web_webview.WebviewController = new web_webview.WebviewController(this.webTag);
761  // ...
762  // Use aboutToAppear() to pass webTag to C++ through Node-API. The webTag uniquely identifies the C++ ArkWeb component.
763  aboutToAppear() {
764    console.info("aboutToAppear")
765    // Initialize the web NDK.
766    testNapi.nativeWebInit(this.webTag);
767  }
768  // ...
769  ```
770
771* C++ Side:
772
773  ```c++
774  // Parse and store the webTag.
775  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
776      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
777      size_t argc = 1;
778      napi_value args[1] = {nullptr};
779      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
780      // Obtain the first parameter webTag.
781      size_t webTagSize = 0;
782      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
783      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
784      size_t webTagLength = 0;
785      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
786      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
787
788      // Save the webTag in the instance object.
789      jsbridge_object_ptr = std::make_shared<JSBridgeObject>(webTagValue);
790      // ...
791  ```
792
793### Obtaining API Struct Using the Native API
794
795To invoke the native APIs, obtain the API structs on the ArkWeb native side first. Through [OH_ArkWeb_GetNativeAPI](../reference/apis-arkweb/capi-arkweb-interface-h.md#oh_arkweb_getnativeapi), you can obtain the pointer structs of [ArkWeb_ControllerAPI](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md) and [ArkWeb_ComponentAPI](../reference/apis-arkweb/capi-web-arkweb-componentapi.md) based on the input parameter **type**. [ArkWeb_ControllerAPI](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md) corresponds to [web_webview.WebviewController API](../reference/apis-arkweb/arkts-apis-webview-WebviewController.md) on the ArkTS side, and [ArkWeb_ComponentAPI](../reference/apis-arkweb/capi-web-arkweb-componentapi.md) corresponds to [ArkWeb Component API](../reference/apis-arkweb/arkts-basic-components-web.md) on the ArkTS side.
796
797  ```c++
798  static ArkWeb_ControllerAPI *controller = nullptr;
799  static ArkWeb_ComponentAPI *component = nullptr;
800  // ...
801  controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
802  component = reinterpret_cast<ArkWeb_ComponentAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_COMPONENT));
803  ```
804
805### Registering Component Lifecycle Callback on the Native Side
806
807Register the component lifecycle callback using [ArkWeb_ComponentAPI](../reference/apis-arkweb/capi-web-arkweb-componentapi.md). Before calling the API, you are advised to use [ARKWEB_MEMBER_MISSING](../reference/apis-arkweb/capi-arkweb-type-h.md#macros) to check whether the function struct has the corresponding pointer to avoid crash caused by mismatch between the SDK and the device ROM.
808
809  ```c++
810  if (!ARKWEB_MEMBER_MISSING(component, onControllerAttached)) {
811      component->onControllerAttached(webTagValue, ValidCallback,
812                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
813  } else {
814      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onControllerAttached func not exist");
815  }
816
817  if (!ARKWEB_MEMBER_MISSING(component, onPageBegin)) {
818      component->onPageBegin(webTagValue, LoadStartCallback,
819                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
820  } else {
821      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageBegin func not exist");
822  }
823
824  if (!ARKWEB_MEMBER_MISSING(component, onPageEnd)) {
825      component->onPageEnd(webTagValue, LoadEndCallback,
826                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
827  } else {
828      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageEnd func not exist");
829  }
830
831  if (!ARKWEB_MEMBER_MISSING(component, onDestroy)) {
832      component->onDestroy(webTagValue, DestroyCallback,
833                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
834  } else {
835      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onDestroy func not exist");
836  }
837  ```
838
839### Invoking Application Functions on the Frontend Page
840
841Use [registerJavaScriptProxy](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#registerjavascriptproxy) to register the application function with the frontend page. You are advised to register the application function in the [onControllerAttached](../reference/apis-arkweb/capi-web-arkweb-componentapi.md#oncontrollerattached) callback. To register the application function at other time, you need to call [refresh](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#refresh) for the registration to take effect.
842
843  ```c++
844  // Register an object.
845  OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy begin");
846  ArkWeb_ProxyMethod method1 = {"method1", ProxyMethod1, static_cast<void *>(jsbridge_object_ptr->GetWeakPt  ())};
847  ArkWeb_ProxyMethod method2 = {"method2", ProxyMethod2, static_cast<void *>(jsbridge_object_ptr->GetWeakPt  ())};
848  ArkWeb_ProxyMethod methodList[2] = {method1, method2};
849  // Call the NDK API to register an object.
850  // In this case, you can use proxy.method1 and proxy.method2 to call ProxyMethod1 and ProxyMethod2 in this file on HTML5 pages.
851  ArkWeb_ProxyObject proxyObject = {"ndkProxy", methodList, 2};
852  controller->registerJavaScriptProxy(webTag, &proxyObject);
853  ```
854
855### Invoking Frontend Page Functions on the Application
856
857Use [runJavaScript](../reference/apis-arkweb/capi-web-arkweb-controllerapi.md#runjavascript) to call the frontend page function.
858
859  ```c++
860  // Construct a struct executed in runJS.
861  char* jsCode = "runJSRetStr()";
862  ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode, bufferSize, &JSBridgeObject::StaticRunJavaScriptCallback,
863                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
864  // Call runJSRetStr() of the frontend page.
865  controller->runJavaScript(webTagValue, &object);
866  ```
867
868### Sample Code
869
870* Frontend page code:
871
872  ```html
873  <!-- entry/src/main/resources/rawfile/runJS.html -->
874  <!-- runJS.html -->
875  <!DOCTYPE html>
876  <html lang="en-gb">
877  <head>
878      <meta name="viewport" content="width=device-width, initial-scale=1.0">
879      <title>run javascript demo</title>
880  </head>
881  <body>
882  <h1>run JavaScript Ext demo</h1>
883  <p id="webDemo"></p>
884  <br>
885  <button type="button" style="height:30px;width:200px" onclick="testNdkProxyObjMethod1()">test ndk method1 ! </button>
886  <br>
887  <br>
888  <button type="button" style="height:30px;width:200px" onclick="testNdkProxyObjMethod2()">test ndk method2 ! </button>
889  <br>
890
891  </body>
892  <script type="text/javascript">
893
894  function testNdkProxyObjMethod1() {
895        if (window.ndkProxy == undefined) {
896              document.getElementById("webDemo").innerHTML = "ndkProxy undefined"
897              return "objName undefined"
898        }
899
900        if (window.ndkProxy.method1 == undefined) {
901              document.getElementById("webDemo").innerHTML = "ndkProxy method1 undefined"
902              return "objName  test undefined"
903        }
904
905        if (window.ndkProxy.method2 == undefined) {
906              document.getElementById("webDemo").innerHTML = "ndkProxy method2 undefined"
907              return "objName  test undefined"
908        }
909        window.ndkProxy.method1("hello", "world", [1.2, -3.4, 123.456], ["Saab", "Volvo", "BMW", undefined], 1.23456, 123789, true, false, 0,  undefined);
910  }
911
912  function testNdkProxyObjMethod2() {
913        if (window.ndkProxy == undefined) {
914              document.getElementById("webDemo").innerHTML = "ndkProxy undefined"
915              return "objName undefined"
916        }
917
918        if (window.ndkProxy.method1 == undefined) {
919              document.getElementById("webDemo").innerHTML = "ndkProxy method1 undefined"
920              return "objName  test undefined"
921        }
922
923        if (window.ndkProxy.method2 == undefined) {
924              document.getElementById("webDemo").innerHTML = "ndkProxy method2 undefined"
925              return "objName  test undefined"
926        }
927
928      var student = {
929              name:"zhang",
930              sex:"man",
931              age:25
932      };
933      var cars = [student, 456, false, 4.567];
934      let params = "[\"{\\\"scope\\\"]";
935
936      window.ndkProxy.method2("hello", "world", false, cars, params);
937  }
938
939  function runJSRetStr(data) {
940      const d = new Date();
941      let time = d.getTime();
942      return JSON.stringify(time)
943  }
944  </script>
945  </html>
946  ```
947
948* Code in ArkTS:
949
950  ```javascript
951  // entry/src/main/ets/pages/Index.ets
952  import testNapi from 'libentry.so';
953  import { webview } from '@kit.ArkWeb';
954
955  class testObj {
956    constructor() {
957    }
958
959    test(): string {
960      console.log('ArkUI Web Component');
961      return "ArkUI Web Component";
962    }
963
964    toString(): void {
965      console.log('Web Component toString');
966    }
967  }
968
969  @Entry
970  @Component
971  struct Index {
972    webTag: string = 'ArkWeb1';
973    controller: webview.WebviewController = new webview.WebviewController(this.webTag);
974    @State testObjtest: testObj = new testObj();
975
976    aboutToAppear() {
977      console.info("aboutToAppear")
978      // Initialize the web NDK.
979      testNapi.nativeWebInit(this.webTag);
980    }
981
982    build() {
983      Column() {
984        Row() {
985          Button('runJS hello')
986            .fontSize(12)
987            .onClick(() => {
988              testNapi.runJavaScript(this.webTag, "runJSRetStr(\"" + "hello" + "\")");
989            })
990        }.height('20%')
991
992        Row() {
993          Web({ src: $rawfile('runJS.html'), controller: this.controller })
994            .javaScriptAccess(true)
995            .fileAccess(true)
996            .onControllerAttached(() => {
997              console.error("ndk onControllerAttached webId: " + this.controller.getWebId());
998            })
999        }.height('80%')
1000      }
1001    }
1002  }
1003  ```
1004
1005* ArkTS APIs exposed on the Node-API side:
1006
1007  ```javascript
1008  // entry/src/main/cpp/types/libentry/index.d.ts
1009  export const nativeWebInit: (webName: string) => void;
1010  export const runJavaScript: (webName: string, jsCode: string) => void;
1011  ```
1012
1013* Compilation configuration on the Node-API side in **entry/src/main/cpp/CMakeLists.txt**.
1014
1015  ```c++
1016  # the minimum version of CMake.
1017  cmake_minimum_required(VERSION 3.4.1)
1018  project(NDKJSBridg)
1019
1020  set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
1021
1022  if(DEFINED PACKAGE_FIND_FILE)
1023      include(${PACKAGE_FIND_FILE})
1024  endif()
1025
1026  include_directories(${NATIVERENDER_ROOT_PATH}
1027                      ${NATIVERENDER_ROOT_PATH}/include)
1028
1029  add_library(entry SHARED hello.cpp jsbridge_object.cpp)
1030
1031  find_library(
1032      # Sets the name of the path variable.
1033      hilog-lib
1034      # Specifies the name of the NDK library that
1035      # you want CMake to locate.
1036      hilog_ndk.z
1037  )
1038
1039  target_link_libraries(entry PUBLIC libace_napi.z.so ${hilog-lib} libohweb.so)
1040  ```
1041
1042* Node-API layer code:
1043
1044  ```c++
1045  // entry/src/main/cpp/hello.cpp
1046  #include "napi/native_api.h"
1047  #include <bits/alltypes.h>
1048  #include <memory>
1049  #include <string>
1050  #include <sys/types.h>
1051  #include <thread>
1052
1053  #include "hilog/log.h"
1054  #include "web/arkweb_interface.h"
1055  #include "jsbridge_object.h"
1056
1057  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
1058  std::shared_ptr<JSBridgeObject> jsbridge_object_ptr = nullptr;
1059  static ArkWeb_ControllerAPI *controller = nullptr;
1060  static ArkWeb_ComponentAPI *component = nullptr;
1061
1062  // Send the JS script to the HTML5 side for execution. This method is a callback of the execution result.
1063  static void RunJavaScriptCallback(const char *webTag, const char *result, void *userData) {
1064      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RunJavaScriptCallback webTag:%{public}s", webTag);
1065      if (!userData) {
1066          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RunJavaScriptCallback userData is nullptr");
1067          return;
1068      }
1069      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
1070      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
1071          jsb_ptr->RunJavaScriptCallback(result);
1072      } else {
1073          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
1074                       "ndk RunJavaScriptCallback jsb_weak_ptr lock failed");
1075      }
1076  }
1077
1078  // This example registers one object and two methods.
1079  static void ProxyMethod1(const char *webTag, const ArkWeb_JavaScriptBridgeData *dataArray, size_t arraySize, void *userData) {
1080      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 webTag:%{public}s", webTag);
1081      if (!userData) {
1082          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 userData is nullptr");
1083          return;
1084      }
1085      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
1086      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
1087          jsb_ptr->ProxyMethod1(dataArray, arraySize);
1088      } else {
1089          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 jsb_weak_ptr lock failed");
1090      }
1091  }
1092
1093  static void ProxyMethod2(const char *webTag, const ArkWeb_JavaScriptBridgeData *dataArray, size_t arraySize, void *userData) {
1094      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 webTag:%{public}s", webTag);
1095      if (!userData) {
1096          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 userData is nullptr");
1097          return;
1098      }
1099      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
1100
1101      std::string jsCode = "runJSRetStr()";
1102      ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode.c_str(), jsCode.size(),
1103                                       &JSBridgeObject::StaticRunJavaScriptCallback,
1104                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
1105      controller->runJavaScript(webTag, &object);
1106
1107      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
1108          jsb_ptr->ProxyMethod2(dataArray, arraySize);
1109      } else {
1110          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 jsb_weak_ptr lock failed");
1111      }
1112  }
1113
1114  void ValidCallback(const char *webTag, void *userData) {
1115      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback webTag: %{public}s", webTag);
1116      if (!userData) {
1117          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback userData is nullptr");
1118          return;
1119      }
1120      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
1121      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
1122          jsb_ptr->SaySomething("ValidCallback");
1123      } else {
1124          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback jsb_weak_ptr lock failed");
1125      }
1126
1127      // Register an object.
1128      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy begin");
1129      ArkWeb_ProxyMethod method1 = {"method1", ProxyMethod1, static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
1130      ArkWeb_ProxyMethod method2 = {"method2", ProxyMethod2, static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
1131      ArkWeb_ProxyMethod methodList[2] = {method1, method2};
1132      // Call the NDK API to register an object.
1133      // In this case, you can use proxy.method1 and proxy.method2 to call ProxyMethod1 and ProxyMethod2 in this file on HTML5 pages.
1134      ArkWeb_ProxyObject proxyObject = {"ndkProxy", methodList, 2};
1135      controller->registerJavaScriptProxy(webTag, &proxyObject);
1136
1137      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy end");
1138  }
1139
1140  void LoadStartCallback(const char *webTag, void *userData) {
1141      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback webTag: %{public}s", webTag);
1142      if (!userData) {
1143          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback userData is nullptr");
1144          return;
1145      }
1146      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
1147      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
1148          jsb_ptr->SaySomething("LoadStartCallback");
1149      } else {
1150          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback jsb_weak_ptr lock failed");
1151      }
1152  }
1153
1154  void LoadEndCallback(const char *webTag, void *userData) {
1155      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback webTag: %{public}s", webTag);
1156      if (!userData) {
1157          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback userData is nullptr");
1158          return;
1159      }
1160      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
1161      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
1162          jsb_ptr->SaySomething("LoadEndCallback");
1163      } else {
1164          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback jsb_weak_ptr lock failed");
1165      }
1166  }
1167
1168  void DestroyCallback(const char *webTag, void *userData) {
1169      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestoryCallback webTag: %{public}s", webTag);
1170      if (!userData) {
1171          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestroyCallback userData is nullptr");
1172          return;
1173      }
1174      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
1175      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
1176          jsb_ptr->SaySomething("DestroyCallback");
1177      } else {
1178          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestroyCallback jsb_weak_ptr lock failed");
1179      }
1180  }
1181
1182  void SetComponentCallback(ArkWeb_ComponentAPI * component, const char* webTagValue) {
1183      if (!ARKWEB_MEMBER_MISSING(component, onControllerAttached)) {
1184          component->onControllerAttached(webTagValue, ValidCallback,
1185                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
1186      } else {
1187          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onControllerAttached func not exist");
1188      }
1189
1190      if (!ARKWEB_MEMBER_MISSING(component, onPageBegin)) {
1191          component->onPageBegin(webTagValue, LoadStartCallback,
1192                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
1193      } else {
1194          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageBegin func not exist");
1195      }
1196
1197      if (!ARKWEB_MEMBER_MISSING(component, onPageEnd)) {
1198          component->onPageEnd(webTagValue, LoadEndCallback,
1199                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
1200      } else {
1201          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageEnd func not exist");
1202      }
1203
1204      if (!ARKWEB_MEMBER_MISSING(component, onDestroy)) {
1205          component->onDestroy(webTagValue, DestroyCallback,
1206                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
1207      } else {
1208          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onDestroy func not exist");
1209      }
1210  }
1211
1212  // Parse and store the webTag.
1213  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
1214      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
1215      size_t argc = 1;
1216      napi_value args[1] = {nullptr};
1217      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
1218      // Obtain the first parameter webTag.
1219      size_t webTagSize = 0;
1220      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
1221      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
1222      size_t webTagLength = 0;
1223      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
1224      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
1225
1226      // Save the webTag in the instance object.
1227      jsbridge_object_ptr = std::make_shared<JSBridgeObject>(webTagValue);
1228      if (jsbridge_object_ptr)
1229          jsbridge_object_ptr->Init();
1230
1231      controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
1232      component = reinterpret_cast<ArkWeb_ComponentAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_COMPONENT));
1233      SetComponentCallback(component, webTagValue);
1234
1235      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit end");
1236      return nullptr;
1237  }
1238
1239  // Send the JS script to the HTML5 side for execution.
1240  static napi_value RunJavaScript(napi_env env, napi_callback_info info) {
1241      size_t argc = 2;
1242      napi_value args[2] = {nullptr};
1243      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
1244
1245      // Obtain the first parameter webTag.
1246      size_t webTagSize = 0;
1247      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
1248      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
1249      size_t webTagLength = 0;
1250      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
1251      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk OH_NativeArkWeb_RunJavaScript webTag:%{public}s",
1252                   webTagValue);
1253
1254      // Obtain the second parameter jsCode.
1255      size_t bufferSize = 0;
1256      napi_get_value_string_utf8(env, args[1], nullptr, 0, &bufferSize);
1257      char *jsCode = new (std::nothrow) char[bufferSize + 1];
1258      size_t byteLength = 0;
1259      napi_get_value_string_utf8(env, args[1], jsCode, bufferSize + 1, &byteLength);
1260
1261      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
1262                   "ndk OH_NativeArkWeb_RunJavaScript jsCode len:%{public}zu", strlen(jsCode));
1263
1264      // Construct a struct executed in runJS.
1265      ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode, bufferSize, &JSBridgeObject::StaticRunJavaScriptCallback,
1266                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
1267      controller->runJavaScript(webTagValue, &object);
1268      return nullptr;
1269  }
1270
1271  EXTERN_C_START
1272  static napi_value Init(napi_env env, napi_value exports) {
1273      napi_property_descriptor desc[] = {
1274          {"nativeWebInit", nullptr, NativeWebInit, nullptr, nullptr, nullptr, napi_default, nullptr},
1275          {"runJavaScript", nullptr, RunJavaScript, nullptr, nullptr, nullptr, napi_default, nullptr},
1276      };
1277      napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
1278      return exports;
1279  }
1280  EXTERN_C_END
1281
1282  static napi_module demoModule = {
1283      .nm_version = 1,
1284      .nm_flags = 0,
1285      .nm_filename = nullptr,
1286      .nm_register_func = Init,
1287      .nm_modname = "entry",
1288      .nm_priv = ((void *)0),
1289      .reserved = {0},
1290  };
1291
1292  extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
1293  ```
1294
1295* Native service code:
1296
1297  ```c++
1298  // entry/src/main/cpp/jsbridge_object.h
1299  #include "web/arkweb_type.h"
1300  #include <string>
1301
1302  class JSBridgeObject : public std::enable_shared_from_this<JSBridgeObject> {
1303  public:
1304      JSBridgeObject(const char* webTag);
1305      ~JSBridgeObject() = default;
1306      void Init();
1307      std::weak_ptr<JSBridgeObject>* GetWeakPtr();
1308      static void StaticRunJavaScriptCallback(const char *webTag, const ArkWeb_JavaScriptBridgeData *data, void *userData);
1309      void RunJavaScriptCallback(const char *result);
1310      void ProxyMethod1(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize);
1311      void ProxyMethod2(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize);
1312      void SaySomething(const char* say);
1313
1314  private:
1315      std::string webTag_;
1316      std::weak_ptr<JSBridgeObject> weak_ptr_;
1317  };
1318  ```
1319
1320  ```c++
1321  // entry/src/main/cpp/jsbridge_object.cpp
1322  #include "jsbridge_object.h"
1323
1324  #include "hilog/log.h"
1325
1326  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
1327
1328  JSBridgeObject::JSBridgeObject(const char *webTag) : webTag_(webTag) {}
1329
1330  void JSBridgeObject::Init() { weak_ptr_ = shared_from_this(); }
1331
1332  std::weak_ptr<JSBridgeObject> *JSBridgeObject::GetWeakPtr() { return &weak_ptr_; }
1333
1334  void JSBridgeObject::StaticRunJavaScriptCallback(const char *webTag, const ArkWeb_JavaScriptBridgeData *data,
1335                                                   void *userData) {
1336      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
1337                   "JSBridgeObject StaticRunJavaScriptCallback webTag:%{public}s", webTag);
1338      if (!userData) {
1339          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
1340                       "JSBridgeObject StaticRunJavaScriptCallback userData is nullptr");
1341          return;
1342      }
1343      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
1344      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
1345          std::string result((char *)data->buffer, data->size);
1346          jsb_ptr->RunJavaScriptCallback(result.c_str());
1347      } else {
1348          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
1349                       "JSBridgeObject StaticRunJavaScriptCallback jsb_weak_ptr lock failed");
1350      }
1351  }
1352
1353  void JSBridgeObject::RunJavaScriptCallback(const char *result) {
1354      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
1355                   "JSBridgeObject OH_NativeArkWeb_RunJavaScript result:%{public}s", result);
1356  }
1357
1358  void JSBridgeObject::ProxyMethod1(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize) {
1359      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject ProxyMethod1 argc:%{public}d",
1360                   arraySize);
1361      for (int i = 0; i < arraySize; i++) {
1362          std::string result((char *)dataArray[i].buffer, dataArray[i].size);
1363          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
1364                       "JSBridgeObject ProxyMethod1 argv[%{public}d]:%{public}s, size:%{public}d", i, result.c_str(),
1365                       dataArray[i].size);
1366      }
1367  }
1368
1369  void JSBridgeObject::ProxyMethod2(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize) {
1370      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject ProxyMethod2 argc:%{public}d",
1371                   arraySize);
1372      for (int i = 0; i < arraySize; i++) {
1373          std::string result((char *)dataArray[i].buffer, dataArray[i].size);
1374          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
1375                       "JSBridgeObject ProxyMethod2 argv[%{public}d]:%{public}s, size:%{public}d", i, result.c_str(),
1376                       dataArray[i].size);
1377      }
1378  }
1379
1380  void JSBridgeObject::SaySomething(const char *say) {
1381      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject SaySomething argc:%{public}s", say);
1382  }
1383  ```
1384