• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 应用侧与前端页面的相互调用(C/C++)
2
3本指导适用于ArkWeb应用侧与前端网页通信场景,开发者可根据应用架构选择使用ArkWeb Native接口完成业务通信机制(以下简称Native JSBridge)。
4
5## 适用的应用架构
6
7应用使用ArkTS、C++语言混合开发,或本身应用架构较贴近于小程序架构,自带C++侧环境,推荐使用ArkWeb在Native侧提供的[ArkWeb_ControllerAPI](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#arkweb_controllerapi)、[ArkWeb_ComponentAPI](../reference/apis-arkweb/_ark_web___component_a_p_i.md#arkweb_componentapi)实现JSBridge功能。
8
9  ![arkweb_jsbridge_arch](figures/arkweb_jsbridge_arch.png)
10
11  上图展示了具有普遍适用性的小程序的通用架构。在这一架构中,逻辑层依赖于应用程序自带的JavaScript运行时,该运行时在一个已有的C++环境中运行。通过Native接口,逻辑层能够直接在C++环境中与视图层(其中ArkWeb充当渲染器)进行通信,无需回退至ArkTS环境使用ArkTS JSBridge接口。
12
13  左图是使用ArkTS JSBridge接口构建小程序的方案,如红框所示,应用需要先调用到ArkTS环境,再调用到C++环境。右图是使用Native JSBridge接口构建小程序的方案,不需要ArkTS环境和C++环境的切换,执行效率更高。
14
15  ![arkweb_jsbridge_diff](figures/arkweb_jsbridge_diff.png)
16
17  Native JSBridge方案可以解决ArkTS环境的冗余切换,同时允许回调在非UI线程上运行,避免造成UI阻塞。
18
19## 使用Native接口实现JSBridge通信
20
21### 使用Native接口绑定ArkWeb
22
23* ArkWeb组件声明在ArkTS侧,需要用户自定义一个标识webTag,并将webTag通过Node-API传至应用Native侧,后续ArkWeb Native接口使用,均需webTag作为对应组件的唯一标识。
24
25* ArkTS侧
26
27  ```js
28  // 自定义webTag,在WebviewController创建时作为入参传入,建立controller与webTag的映射关系
29  webTag: string = 'ArkWeb1';
30  controller: web_webview.WebviewController = new web_webview.WebviewController(this.webTag);
31
32  // aboutToAppear中将webTag通过Node-API接口传入C++侧,作为C++侧ArkWeb组件的唯一标识
33  aboutToAppear() {
34    console.info("aboutToAppear")
35    //初始化web ndk
36    testNapi.nativeWebInit(this.webTag);
37  }
38  ```
39
40* C++侧
41
42  ```c++
43  // 解析存储webTag
44  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
45      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
46      size_t argc = 1;
47      napi_value args[1] = {nullptr};
48      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
49      // 获取第一个参数webTag
50      size_t webTagSize = 0;
51      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
52      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
53      size_t webTagLength = 0;
54      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
55      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
56
57      // 将webTag保存在实例对象中
58      jsbridge_object_ptr = std::make_shared<JSBridgeObject>(webTagValue);
59      // ...
60  ```
61
62### 使用Native接口获取API结构体
63
64ArkWeb Native侧得先获取API结构体,才能调用结构体里的Native API。ArkWeb Native侧API通过函数[OH_ArkWeb_GetNativeAPI](../reference/apis-arkweb/_web.md#oh_arkweb_getnativeapi())获取,根据入参type不同,可分别获取[ArkWeb_ControllerAPI](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#arkweb_controllerapi)、[ArkWeb_ComponentAPI](../reference/apis-arkweb/_ark_web___component_a_p_i.md#arkweb_componentapi)函数指针结构体。其中[ArkWeb_ControllerAPI](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#arkweb_controllerapi)对应ArkTS侧[web_webview.WebviewController API](../reference/apis-arkweb/js-apis-webview.md),[ArkWeb_ComponentAPI](../reference/apis-arkweb/_ark_web___component_a_p_i.md#arkweb_componentapi)对应ArkTS侧[ArkWeb组件API](../reference/apis-arkweb/ts-basic-components-web.md)。
65
66  ```c++
67  static ArkWeb_ControllerAPI *controller = nullptr;
68  static ArkWeb_ComponentAPI *component = nullptr;
69  ...
70  controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
71  component = reinterpret_cast<ArkWeb_ComponentAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_COMPONENT));
72  ```
73
74### Native侧注册组件生命周期回调
75
76通过[ArkWeb_ComponentAPI](../reference/apis-arkweb/_ark_web___component_a_p_i.md#arkweb_componentapi)注册组件生命周期回调,在调用API前建议通过[ARKWEB_MEMBER_MISSING](../reference/apis-arkweb/_web.md#arkweb_member_missing)校验该函数结构体是否有对应函数指针,避免SDK与设备ROM不匹配导致crash问题。
77
78  ```c++
79  if (!ARKWEB_MEMBER_MISSING(component, onControllerAttached)) {
80      component->onControllerAttached(webTagValue, ValidCallback,
81                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
82  } else {
83      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onControllerAttached func not exist");
84  }
85
86  if (!ARKWEB_MEMBER_MISSING(component, onPageBegin)) {
87      component->onPageBegin(webTagValue, LoadStartCallback,
88                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
89  } else {
90      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageBegin func not exist");
91  }
92
93  if (!ARKWEB_MEMBER_MISSING(component, onPageEnd)) {
94      component->onPageEnd(webTagValue, LoadEndCallback,
95                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
96  } else {
97      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageEnd func not exist");
98  }
99
100  if (!ARKWEB_MEMBER_MISSING(component, onDestroy)) {
101      component->onDestroy(webTagValue, DestroyCallback,
102                                      static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
103  } else {
104      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onDestroy func not exist");
105  }
106  ```
107
108### 前端页面调用应用侧函数
109
110通过[registerJavaScriptProxy](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#registerjavascriptproxy)将应用侧函数注册至前端页面,推荐在[onControllerAttached](../reference/apis-arkweb/_ark_web___component_a_p_i.md#oncontrollerattached)回调中注册,其它时机注册需要手动调用[refresh](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#refresh)才能生效。
111
112  ```c++
113  // 注册对象
114  OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy begin");
115  ArkWeb_ProxyMethod method1 = {"method1", ProxyMethod1, static_cast<void *>(jsbridge_object_ptr->GetWeakPt  ())};
116  ArkWeb_ProxyMethod method2 = {"method2", ProxyMethod2, static_cast<void *>(jsbridge_object_ptr->GetWeakPt  ())};
117  ArkWeb_ProxyMethod methodList[2] = {method1, method2};
118  // 调用ndk接口注册对象
119  // 如此注册的情况下,在H5页面就可以使用proxy.method1proxy.method2调用此文件下的ProxyMethod1和ProxyMethod2方法了
120  ArkWeb_ProxyObject proxyObject = {"ndkProxy", methodList, 2};
121  controller->registerJavaScriptProxy(webTag, &proxyObject);
122  ```
123
124### 应用侧调用前端页面函数
125
126通过[runJavaScript](../reference/apis-arkweb/_ark_web___controller_a_p_i.md#runjavascript)调用前端页面函数。
127
128  ```c++
129  // 构造runJS执行的结构体
130  char* jsCode = "runJSRetStr()";
131  ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode, bufferSize, &JSBridgeObject::StaticRunJavaScriptCallback,
132                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
133  // 调用前端页面runJSRetStr()函数
134  controller->runJavaScript(webTagValue, &object);
135  ```
136
137### 完整示例
138
139* 前端页面代码
140
141  ```html
142  <!-- entry/src/main/resources/rawfile/runJS.html -->
143  <!-- runJS.html -->
144  <!DOCTYPE html>
145  <html lang="en-gb">
146  <head>
147      <meta name="viewport" content="width=device-width, initial-scale=1.0">
148      <title>run javascript demo</title>
149  </head>
150  <body>
151  <h1>run JavaScript Ext demo</h1>
152  <p id="webDemo"></p>
153  <br>
154  <button type="button" style="height:30px;width:200px" onclick="testNdkProxyObjMethod1()">test ndk method1 ! </button>
155  <br>
156  <br>
157  <button type="button" style="height:30px;width:200px" onclick="testNdkProxyObjMethod2()">test ndk method2 ! </button>
158  <br>
159
160  </body>
161  <script type="text/javascript">
162
163  function testNdkProxyObjMethod1() {
164        if (window.ndkProxy == undefined) {
165              document.getElementById("webDemo").innerHTML = "ndkProxy undefined"
166              return "objName undefined"
167        }
168
169        if (window.ndkProxy.method1 == undefined) {
170              document.getElementById("webDemo").innerHTML = "ndkProxy method1 undefined"
171              return "objName  test undefined"
172        }
173
174        if (window.ndkProxy.method2 == undefined) {
175              document.getElementById("webDemo").innerHTML = "ndkProxy method2 undefined"
176              return "objName  test undefined"
177        }
178        window.ndkProxy.method1("hello", "world", [1.2, -3.4, 123.456], ["Saab", "Volvo", "BMW", undefined], 1.23456, 123789, true, false, 0,  undefined);
179  }
180
181  function testNdkProxyObjMethod2() {
182        if (window.ndkProxy == undefined) {
183              document.getElementById("webDemo").innerHTML = "ndkProxy undefined"
184              return "objName undefined"
185        }
186
187        if (window.ndkProxy.method1 == undefined) {
188              document.getElementById("webDemo").innerHTML = "ndkProxy method1 undefined"
189              return "objName  test undefined"
190        }
191
192        if (window.ndkProxy.method2 == undefined) {
193              document.getElementById("webDemo").innerHTML = "ndkProxy method2 undefined"
194              return "objName  test undefined"
195        }
196
197      var student = {
198              name:"zhang",
199              sex:"man",
200              age:25
201      };
202      var cars = [student, 456, false, 4.567];
203      let params = "[\"{\\\"scope\\\"]";
204
205      window.ndkProxy.method2("hello", "world", false, cars, params);
206  }
207
208  function runJSRetStr(data) {
209      const d = new Date();
210      let time = d.getTime();
211      return JSON.stringify(time)
212  }
213  </script>
214  </html>
215  ```
216
217* ArkTS侧代码
218
219  ```javascript
220  // entry/src/main/ets/pages/Index.ets
221  import testNapi from 'libentry.so';
222  import { webview } from '@kit.ArkWeb';
223
224  class testObj {
225    constructor() {
226    }
227
228    test(): string {
229      console.log('ArkUI Web Component');
230      return "ArkUI Web Component";
231    }
232
233    toString(): void {
234      console.log('Web Component toString');
235    }
236  }
237
238  @Entry
239  @Component
240  struct Index {
241    webTag: string = 'ArkWeb1';
242    controller: webview.WebviewController = new webview.WebviewController(this.webTag);
243    @State testObjtest: testObj = new testObj();
244
245    aboutToAppear() {
246      console.info("aboutToAppear")
247      //初始化web ndk
248      testNapi.nativeWebInit(this.webTag);
249    }
250
251    build() {
252      Column() {
253        Row() {
254          Button('runJS hello')
255            .fontSize(12)
256            .onClick(() => {
257              testNapi.runJavaScript(this.webTag, "runJSRetStr(\"" + "hello" + "\")");
258            })
259        }.height('20%')
260
261        Row() {
262          Web({ src: $rawfile('runJS.html'), controller: this.controller })
263            .javaScriptAccess(true)
264            .fileAccess(true)
265            .onControllerAttached(() => {
266              console.error("ndk onControllerAttached webId: " + this.controller.getWebId());
267            })
268        }.height('80%')
269      }
270    }
271  }
272  ```
273
274* Node-API侧暴露ArkTS接口
275
276  ```javascript
277  // entry/src/main/cpp/types/libentry/index.d.ts
278  export const nativeWebInit: (webName: string) => void;
279  export const runJavaScript: (webName: string, jsCode: string) => void;
280  ```
281
282* Node-API侧编译配置`entry/src/main/cpp/CMakeLists.txt`
283
284  ```c++
285  # the minimum version of CMake.
286  cmake_minimum_required(VERSION 3.4.1)
287  project(NDKJSBridg)
288
289  set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
290
291  if(DEFINED PACKAGE_FIND_FILE)
292      include(${PACKAGE_FIND_FILE})
293  endif()
294
295  include_directories(${NATIVERENDER_ROOT_PATH}
296                      ${NATIVERENDER_ROOT_PATH}/include)
297
298  add_library(entry SHARED hello.cpp jsbridge_object.cpp)
299
300  find_library(
301      # Sets the name of the path variable.
302      hilog-lib
303      # Specifies the name of the NDK library that
304      # you want CMake to locate.
305      hilog_ndk.z
306  )
307
308  target_link_libraries(entry PUBLIC libace_napi.z.so ${hilog-lib} libohweb.so)
309  ```
310
311* Node-API层代码
312
313  ```c++
314  // entry/src/main/cpp/hello.cpp
315  #include "napi/native_api.h"
316  #include <bits/alltypes.h>
317  #include <memory>
318  #include <string>
319  #include <sys/types.h>
320  #include <thread>
321
322  #include "hilog/log.h"
323  #include "web/arkweb_interface.h"
324  #include "jsbridge_object.h"
325
326  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
327  std::shared_ptr<JSBridgeObject> jsbridge_object_ptr = nullptr;
328  static ArkWeb_ControllerAPI *controller = nullptr;
329  static ArkWeb_ComponentAPI *component = nullptr;
330
331  // 发送JS脚本到H5侧执行,该方法为执行结果的回调。
332  static void RunJavaScriptCallback(const char *webTag, const char *result, void *userData) {
333      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RunJavaScriptCallback webTag:%{public}s", webTag);
334      if (!userData) {
335          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RunJavaScriptCallback userData is nullptr");
336          return;
337      }
338      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
339      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
340          jsb_ptr->RunJavaScriptCallback(result);
341      } else {
342          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
343                       "ndk RunJavaScriptCallback jsb_weak_ptr lock failed");
344      }
345  }
346
347  // 示例代码 ,注册了1个对象,2个方法
348  static void ProxyMethod1(const char *webTag, const ArkWeb_JavaScriptBridgeData *dataArray, size_t arraySize, void *userData) {
349      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 webTag:%{public}s", webTag);
350      if (!userData) {
351          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 userData is nullptr");
352          return;
353      }
354      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
355      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
356          jsb_ptr->ProxyMethod1(dataArray, arraySize);
357      } else {
358          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod1 jsb_weak_ptr lock failed");
359      }
360  }
361
362  static void ProxyMethod2(const char *webTag, const ArkWeb_JavaScriptBridgeData *dataArray, size_t arraySize, void *userData) {
363      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 webTag:%{public}s", webTag);
364      if (!userData) {
365          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 userData is nullptr");
366          return;
367      }
368      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
369
370      std::string jsCode = "runJSRetStr()";
371      ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode.c_str(), jsCode.size(),
372                                       &JSBridgeObject::StaticRunJavaScriptCallback,
373                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
374      controller->runJavaScript(webTag, &object);
375
376      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
377          jsb_ptr->ProxyMethod2(dataArray, arraySize);
378      } else {
379          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ProxyMethod2 jsb_weak_ptr lock failed");
380      }
381  }
382
383  void ValidCallback(const char *webTag, void *userData) {
384      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback webTag: %{public}s", webTag);
385      if (!userData) {
386          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback userData is nullptr");
387          return;
388      }
389      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
390      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
391          jsb_ptr->SaySomething("ValidCallback");
392      } else {
393          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk ValidCallback jsb_weak_ptr lock failed");
394      }
395
396      // 注册对象
397      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy begin");
398      ArkWeb_ProxyMethod method1 = {"method1", ProxyMethod1, static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
399      ArkWeb_ProxyMethod method2 = {"method2", ProxyMethod2, static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
400      ArkWeb_ProxyMethod methodList[2] = {method1, method2};
401      // 调用ndk接口注册对象
402      // 如此注册的情况下,在H5页面就可以使用proxy.method1proxy.method2调用此文件下的ProxyMethod1和ProxyMethod2方法了
403      ArkWeb_ProxyObject proxyObject = {"ndkProxy", methodList, 2};
404      controller->registerJavaScriptProxy(webTag, &proxyObject);
405
406      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk RegisterJavaScriptProxy end");
407  }
408
409  void LoadStartCallback(const char *webTag, void *userData) {
410      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback webTag: %{public}s", webTag);
411      if (!userData) {
412          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback userData is nullptr");
413          return;
414      }
415      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
416      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
417          jsb_ptr->SaySomething("LoadStartCallback");
418      } else {
419          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadStartCallback jsb_weak_ptr lock failed");
420      }
421  }
422
423  void LoadEndCallback(const char *webTag, void *userData) {
424      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback webTag: %{public}s", webTag);
425      if (!userData) {
426          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback userData is nullptr");
427          return;
428      }
429      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
430      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
431          jsb_ptr->SaySomething("LoadEndCallback");
432      } else {
433          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk LoadEndCallback jsb_weak_ptr lock failed");
434      }
435  }
436
437  void DestroyCallback(const char *webTag, void *userData) {
438      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestoryCallback webTag: %{public}s", webTag);
439      if (!userData) {
440          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestroyCallback userData is nullptr");
441          return;
442      }
443      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
444      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
445          jsb_ptr->SaySomething("DestroyCallback");
446      } else {
447          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk DestroyCallback jsb_weak_ptr lock failed");
448      }
449  }
450
451  void SetComponentCallback(ArkWeb_ComponentAPI * component, const char* webTagValue) {
452      if (!ARKWEB_MEMBER_MISSING(component, onControllerAttached)) {
453          component->onControllerAttached(webTagValue, ValidCallback,
454                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
455      } else {
456          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onControllerAttached func not exist");
457      }
458
459      if (!ARKWEB_MEMBER_MISSING(component, onPageBegin)) {
460          component->onPageBegin(webTagValue, LoadStartCallback,
461                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
462      } else {
463          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageBegin func not exist");
464      }
465
466      if (!ARKWEB_MEMBER_MISSING(component, onPageEnd)) {
467          component->onPageEnd(webTagValue, LoadEndCallback,
468                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
469      } else {
470          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onPageEnd func not exist");
471      }
472
473      if (!ARKWEB_MEMBER_MISSING(component, onDestroy)) {
474          component->onDestroy(webTagValue, DestroyCallback,
475                                          static_cast<void *>(jsbridge_object_ptr->GetWeakPtr()));
476      } else {
477          OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "component onDestroy func not exist");
478      }
479  }
480
481  // 解析存储webTag
482  static napi_value NativeWebInit(napi_env env, napi_callback_info info) {
483      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit start");
484      size_t argc = 1;
485      napi_value args[1] = {nullptr};
486      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
487      // 获取第一个参数webTag
488      size_t webTagSize = 0;
489      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
490      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
491      size_t webTagLength = 0;
492      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
493      OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit webTag:%{public}s", webTagValue);
494
495      // 将webTag保存在实例对象中
496      jsbridge_object_ptr = std::make_shared<JSBridgeObject>(webTagValue);
497      if (jsbridge_object_ptr)
498          jsbridge_object_ptr->Init();
499
500      controller = reinterpret_cast<ArkWeb_ControllerAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_CONTROLLER));
501      component = reinterpret_cast<ArkWeb_ComponentAPI *>(OH_ArkWeb_GetNativeAPI(ARKWEB_NATIVE_COMPONENT));
502      SetComponentCallback(component, webTagValue);
503
504      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk NativeWebInit end");
505      return nullptr;
506  }
507
508  // 发送JS脚本到H5侧执行
509  static napi_value RunJavaScript(napi_env env, napi_callback_info info) {
510      size_t argc = 2;
511      napi_value args[2] = {nullptr};
512      napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
513
514      // 获取第一个参数webTag
515      size_t webTagSize = 0;
516      napi_get_value_string_utf8(env, args[0], nullptr, 0, &webTagSize);
517      char *webTagValue = new (std::nothrow) char[webTagSize + 1];
518      size_t webTagLength = 0;
519      napi_get_value_string_utf8(env, args[0], webTagValue, webTagSize + 1, &webTagLength);
520      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "ndk OH_NativeArkWeb_RunJavaScript webTag:%{public}s",
521                   webTagValue);
522
523      // 获取第二个参数 jsCode
524      size_t bufferSize = 0;
525      napi_get_value_string_utf8(env, args[1], nullptr, 0, &bufferSize);
526      char *jsCode = new (std::nothrow) char[bufferSize + 1];
527      size_t byteLength = 0;
528      napi_get_value_string_utf8(env, args[1], jsCode, bufferSize + 1, &byteLength);
529
530      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
531                   "ndk OH_NativeArkWeb_RunJavaScript jsCode len:%{public}zu", strlen(jsCode));
532
533      // 构造runJS执行的结构体
534      ArkWeb_JavaScriptObject object = {(uint8_t *)jsCode, bufferSize, &JSBridgeObject::StaticRunJavaScriptCallback,
535                                       static_cast<void *>(jsbridge_object_ptr->GetWeakPtr())};
536      controller->runJavaScript(webTagValue, &object);
537      return nullptr;
538  }
539
540  EXTERN_C_START
541  static napi_value Init(napi_env env, napi_value exports) {
542      napi_property_descriptor desc[] = {
543          {"nativeWebInit", nullptr, NativeWebInit, nullptr, nullptr, nullptr, napi_default, nullptr},
544          {"runJavaScript", nullptr, RunJavaScript, nullptr, nullptr, nullptr, napi_default, nullptr},
545      };
546      napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
547      return exports;
548  }
549  EXTERN_C_END
550
551  static napi_module demoModule = {
552      .nm_version = 1,
553      .nm_flags = 0,
554      .nm_filename = nullptr,
555      .nm_register_func = Init,
556      .nm_modname = "entry",
557      .nm_priv = ((void *)0),
558      .reserved = {0},
559  };
560
561  extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
562  ```
563
564* Native侧业务代码
565
566  ```c++
567  // entry/src/main/cpp/jsbridge_object.h
568  #include "web/arkweb_type.h"
569  #include <string>
570
571  class JSBridgeObject : public std::enable_shared_from_this<JSBridgeObject> {
572  public:
573      JSBridgeObject(const char* webTag);
574      ~JSBridgeObject() = default;
575      void Init();
576      std::weak_ptr<JSBridgeObject>* GetWeakPtr();
577      static void StaticRunJavaScriptCallback(const char *webTag, const ArkWeb_JavaScriptBridgeData *data, void *userData);
578      void RunJavaScriptCallback(const char *result);
579      void ProxyMethod1(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize);
580      void ProxyMethod2(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize);
581      void SaySomething(const char* say);
582
583  private:
584      std::string webTag_;
585      std::weak_ptr<JSBridgeObject> weak_ptr_;
586  };
587  ```
588
589  ```c++
590  // entry/src/main/cpp/jsbridge_object.cpp
591  #include "jsbridge_object.h"
592
593  #include "hilog/log.h"
594
595  constexpr unsigned int LOG_PRINT_DOMAIN = 0xFF00;
596
597  JSBridgeObject::JSBridgeObject(const char *webTag) : webTag_(webTag) {}
598
599  void JSBridgeObject::Init() { weak_ptr_ = shared_from_this(); }
600
601  std::weak_ptr<JSBridgeObject> *JSBridgeObject::GetWeakPtr() { return &weak_ptr_; }
602
603  void JSBridgeObject::StaticRunJavaScriptCallback(const char *webTag, const ArkWeb_JavaScriptBridgeData *data,
604                                                   void *userData) {
605      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
606                   "JSBridgeObject StaticRunJavaScriptCallback webTag:%{public}s", webTag);
607      if (!userData) {
608          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
609                       "JSBridgeObject StaticRunJavaScriptCallback userData is nullptr");
610          return;
611      }
612      std::weak_ptr<JSBridgeObject> jsb_weak_ptr = *static_cast<std::weak_ptr<JSBridgeObject> *>(userData);
613      if (auto jsb_ptr = jsb_weak_ptr.lock()) {
614          std::string result((char *)data->buffer, data->size);
615          jsb_ptr->RunJavaScriptCallback(result.c_str());
616      } else {
617          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
618                       "JSBridgeObject StaticRunJavaScriptCallback jsb_weak_ptr lock failed");
619      }
620  }
621
622  void JSBridgeObject::RunJavaScriptCallback(const char *result) {
623      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
624                   "JSBridgeObject OH_NativeArkWeb_RunJavaScript result:%{public}s", result);
625  }
626
627  void JSBridgeObject::ProxyMethod1(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize) {
628      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject ProxyMethod1 argc:%{public}d",
629                   arraySize);
630      for (int i = 0; i < arraySize; i++) {
631          std::string result((char *)dataArray[i].buffer, dataArray[i].size);
632          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
633                       "JSBridgeObject ProxyMethod1 argv[%{public}d]:%{public}s, size:%{public}d", i, result.c_str(),
634                       dataArray[i].size);
635      }
636  }
637
638  void JSBridgeObject::ProxyMethod2(const ArkWeb_JavaScriptBridgeData *dataArray, int32_t arraySize) {
639      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject ProxyMethod2 argc:%{public}d",
640                   arraySize);
641      for (int i = 0; i < arraySize; i++) {
642          std::string result((char *)dataArray[i].buffer, dataArray[i].size);
643          OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb",
644                       "JSBridgeObject ProxyMethod2 argv[%{public}d]:%{public}s, size:%{public}d", i, result.c_str(),
645                       dataArray[i].size);
646      }
647  }
648
649  void JSBridgeObject::SaySomething(const char *say) {
650      OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ArkWeb", "JSBridgeObject SaySomething argc:%{public}s", say);
651  }
652  ```
653