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