鸿蒙-JsBridge

974 阅读1分钟

现在市面开源的有两个JsBridge库,下面简单的适配一下鸿蒙中的Bridge,兼顾下面的两种场景

适配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)
  }
}

源码位置github