现在市面开源的有两个JsBridge库,下面简单的适配一下鸿蒙中的Bridge,兼顾下面的两种场景
- Android JsBridge 和 IOS WebViewJavascriptBridge
- apache的 Cordova
适配JsBridge
首先了解JsBridge的原理。 主要在BridgeWebView中,桥接了两个方法,
- send
主要是h5调用NA的方法
,回调给h5的时候 是使用了 webview.evaluateJavascript - response NA使用webview.evaluateJavascript通信的时候,
返回给NA的回调就是用的这个
,
@JavascriptInterface
public String send(String data, String callbackId) {
Log.d("BaseJavascriptInterface", data + ", callbackId: " + callbackId + " " + Thread.currentThread().getName());
return send(data);
}
@JavascriptInterface
public void response(String data, String responseId) {
}
开始适配
把index.html 和 WebViewJavascriptBridge.js 复制过来,放到rawFile文件夹,需要把WebViewJavascriptBridge.js 压缩一下,否则读取不全(先不研究为啥读不全了)
JsBridgeHelper
主要是用来 使用WebviewController,调用web的方法
class JsBridgeHelper {
controller: webview.WebviewController;
map: HashMap<string, (data: string) => void> = new HashMap()
constructor(controller: webview.WebviewController) {
this.controller = controller
}
sendResponse(data: string, callbackId: string) {
let response: JSResponse = new JSResponse()
response.responseId = callbackId
response.responseData = data
let content = `javascript:WebViewJavascriptBridge._handleMessageFromNative('${JSON.stringify(response)}');`
console.log(`json=> ${content}`)
this.controller.runJavaScript(content)
}
callHandler(handlerName: string, data: string, callBack?: (event: string) => void) {
let callbackId = `ArkTs${new Date().getTime()}`
let jsRequest = new JSRequest()
jsRequest.data = data
if (callBack) {
this.map.set(callbackId, callBack)
jsRequest.callbackId = callbackId
}
jsRequest.handlerName = handlerName
let content = `javascript:WebViewJavascriptBridge._handleMessageFromNative('${JSON.stringify(jsRequest)}');`
this.controller.runJavaScript(content)
}
sendToWeb(data: string) {
this.callHandler('', data)
}
}
初始化Web
在onControllerAttached注册bridge,在onPageEnd里面加载本地的WebViewJavascriptBridge.js
// 加载本地的html
@State url: string | Resource = $rawfile('JsBridgeDemo.html')
@State controller: webview.WebviewController = new webview.WebviewController();
// 把controller交给JsBridgeHelper,主要是可以用来调用web方法
jsBridgeHelper: JsBridgeHelper = new JsBridgeHelper(this.controller)
// 这个就是咱们定义的桥接
@State jsBridge: MainJavascriptInterface = new MainJavascriptInterface(this.jsBridgeHelper);
Web({ src: this.url, controller: this.controller })
.onControllerAttached(() => {
// // 注册 jsbridge,类,h5中的名字,注册的方法
this.controller.registerJavaScriptProxy(this.jsBridge, "WebViewJavascriptBridge",
["send", "response", "submitFromWeb"]);
// 这种注册必须调用refresh
this.controller.refresh()
})
.zoomAccess(false)// 设置是否支持手势进行缩放 默认允许,咱们app一般不允许
.onPageEnd(() => {
// 加载 WebViewJavascriptBridge.js
let jsBridge = getContext(this).resourceManager.getRawFileContentSync('WebViewJavascriptBridge.js')
let decoder = new util.TextDecoder('utf-8')
let content = decoder.decode(jsBridge)
console.log('读取到 ' + content)
this.controller.loadUrl('javascript:' + content)
})
.textZoomRatio(250)
.onConsole((event) => {
// h5的打印,可以在这里看到
console.log(`H5的打印-> ${event?.message.getMessage()}`)
return true
})
MainJavascriptInterface
这个就是jsbridge
class MainJavascriptInterface {
jsBridgeHelper: JsBridgeHelper
constructor(jsBridgeHelper: JsBridgeHelper) {
this.jsBridgeHelper = jsBridgeHelper;
}
// h5 调用 NA , NA回调给h5的。是通过 runJavaScript
send(data: string, callbackId: string): string {
console.log(TAG, `MainJavascriptInterface: method=send ,data=>${data} , callbackId=>${callbackId}`)
// 这里的返回值其实是没有意义的
return '--'
}
// 当 NA 发送消息,h5 回调给 NA是用这种方法
response(data: string, responseId: string): void {
console.log(TAG, `MainJavascriptInterface: method=response data=>${data} , responseId=>${responseId}`)
if (this.jsBridgeHelper.map.hasKey(responseId)) {
this.jsBridgeHelper.map.remove(responseId)(data)
}
}
submitFromWeb(data: string, callbackId: string) {
console.log(TAG, `MainJavascriptInterface: method=submitFromWeb data=>${data} , responseId=>${callbackId}`)
this.jsBridgeHelper.sendResponse('submitFromWeb response', callbackId)
}
}