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