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