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  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  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