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