一、简介

Dsbridge跨语言交互组件
HarmonyOS版的DSBridge,通过本库可以在HarmonyOS与JavaScript完成交互,可以相互调用彼此的功能。

目前兼容Android、iOS第三方DSBridge库的核心功能,基本保持原来的使用方式,后续会持续迭代保持与DSBridge库相同的功能,减少前端和客户端的适配工作,另外也会根据鸿蒙的特性做一些定制需求。

二、安装

安装库:

ohpm install @hzw/ohos-dsbridge

三、基本用法

3.1 ArkTS原生侧

在原生新建一个类JsBridge,实现业务API , 通过类来集中统一管理API,方法用@JavaScriptInterface()标注,是不是很眼熟呢,加一个@JavaScriptInterface()标注主要为了使用规范,是自定义的装饰器,与Android保持一致性。

原生调用前端方法效果图

在这里插入图片描述


在这里插入图片描述

前端调用原生方法效果图

在这里插入图片描述

JavaScript侧

  1. 在JavaScript中初始化dsBridge,通过cdn或者npm安装都可以。
    如果项目没有历史包袱,建议直接用m-dsbridge包。
npm i m-dsbridge
// 或者cdn引入
<script src="https://cdn.jsdelivr.net/npm/m-dsbridge/dsBridge.js"></script>

也支持直接用原Android或iOS的DSBridge库的JS脚本。

https://cdn.jsdelivr.net/npm/dsbridge/dist/dsbridge.js

如果m-dsbridge 发生异常,建议切换到 https://cdn.jsdelivr.net/npm/dsbridge/dist/dsbridge.js

  1. 通过dsBridge对象注册Js函数,供原生调用。
// 注册同步函数
dsBridge.register('showAlert', function (a, b, c) {
       // return "原生调用JS showAlert函数"
        alert("原生调用JS showAlert函数" + a + " " + b + " " + c)
       return true
   })

// 注册异步函数
dsBridge.registerAsyn('showAlertAsync', function (a, b, c, callback) {
 let counter = 0
 let id = setInterval(() => {
   if (counter < 5) {
     callback(counter, false)
     alert("原生调用JS showAlertAsync函数" + a + " " + b + " " + c + " " + counter)
     counter++
   } else {
     callback(counter, true)
     alert("原生调用JS showAlertAsync函数" + a + " " + b + " " + c + " " + counter)
     clearInterval(id)
   }
 }, 1000)

})

其中异步的callback函数,如果最后一个参数返回true则完成整个链接的调用,false则可以一直回调给原生,这个就是JavaScript端的一次调用,多次返回。比如需要将JavaScript端进度数据不间断同步到原生,这时就可以派上用场了。

  1. 通过dsBridge对象调用原生API,第一个参数是原生方法名称,第二参数是原生方法接收的参数,异步方法有第三个参数是回调函数,会接收CompleteHandler异步回调结果。
// 同步
let msg = dsBridge.call('testSync', JSON.stringify({data: 100}))

// 异步, 参数可以是对象或者基本类型
dsBridge.call('testAsync', JSON.stringify({data: 200}), (msg) => {
 updateMsg(msg)
})

// 如果你使用的是DSBridge 2.0脚本,异步调用的参数必须是一个对象
dsBridge.call('testAsync', {data: 200}, (msg) => {
 updateMsg(msg)
})

前端页面testDsbridge.html 的代码

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<style>
    .btn {
        width: 600px;
        height: 100px;
        font-size: 40px;
        margin-top: 60px;
    }
</style>
<body>
<strong style="font-size:40px;">调用原生方法</strong>
</br>
<button class="btn" id="callArkTSTestStr" type="button" onclick="callArkTSTestStr()">callArkTSTestStr方法</button>

</br>
<button class="btn" id="callArkTSTestArry" type="button" onclick="callArkTSTestArry()">callArkTSTestArray方法</button>

</br>
<button class="btn" id="callArkTStoString2" type="button" onclick="callArkTStoString2()">callArkTStoString2方法</button>

</br>
<button class="btn" id="callTestAsync" type="button" onclick="callTestAsync()">callTestAsync方法</button>
<p style="font-size:40px;" id="resultData"></p>
<script src="https://cdn.jsdelivr.net/npm/m-dsbridge/dsBridge.js"></script>
<script>
    function callArkTSTestStr() {
       let str = testObjName.testStr();
       document.getElementById("resultData").innerHTML = str;
       console.info('H5 callArkTSTestStr 调用原生 testStr 方法返回的数据:' + str);
    }

    function callArkTSTestArry() {
        let arrayNum = testObjName.testArray();
        console.info('H5 callArkTSTestArry 调用原生 testArray 方法返回的数据:' + arrayNum);
    }

    function callArkTStoString2() {
        testObjName.toString2("这是来自H5数据");
        console.info('H5 callArkTStoString2 调用原生 toString2 方法 传递的数据');
    }

    function callTestAsync() {
        // 异步, 参数可以是对象或者基本类型
        dsBridge.call('testAsync', JSON.stringify({data: 200}), (msg) => {
            console.info('H5 使用 dsBridge 调用原生 testAsync 方法');
        })
    }
    // 注册同步函数
    dsBridge.register('showAlert', function (a, b, c) {
           // return "原生调用JS showAlert函数"
            alert("原生调用JS showAlert函数" + a + " " + b + " " + c)
           return true
       })

    // 注册异步函数
    dsBridge.registerAsyn('showAlertAsync', function (a, b, c, callback) {
     let counter = 0
     let id = setInterval(() => {
       if (counter < 2) {
         callback(counter, false)
         alert("原生调用JS showAlertAsync函数" + a + " " + b + " " + c + " " + counter)
         counter++
       } else {
         callback(counter, true)
         alert("原生调用JS showAlertAsync函数" + a + " " + b + " " + c + " " + counter)
         clearInterval(id)
       }
     }, 1000)

})
</script>
</body>
</html>

鸿蒙原生H5DSApi代码

export class H5DSApi{
 private cHandler: CompleteHandler = null

 /**
  * 同步
  * @param p
  * @returns
  */
 @JavaScriptInterface(false)
 testSync(p: string): string {
   LogUtils.d("testSync: " + JSON.stringify(p))
   return "hello native"
 }

 /**
  * 异步
  * @param p
  * @param handler
  */
 @JavaScriptInterface()
 testAsync(p: string, handler: CompleteHandler) {
   LogUtils.d("testAsync: " + JSON.stringify(p))
   this.cHandler = handler
 }
}

鸿蒙原生页面代码

import { JavaScriptInterface, OnReturnValue, WebViewControllerProxy } from '@hzw/ohos-dsbridge';
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit'
import { H5DSApi } from './dsbridge/H5DSApi'
import json from '@ohos.util.json';
import { JSON } from '@kit.ArkTS';


const H5_BASE_URL = "https://developer.huawei.com/consumer/cn/"
// const javaScriptMe
const JSmethodList = ["testStr", "testArray", "toString", "toString2", "navToBack", "requestEventData"];

class TestObj {
  testStr(): string {
    console.log("前端调用了 原生 testStr方法")
    return "原生 testStr方法返回的数据"
  }

  testArray(): Array<Number> {
    return [1, 2, 3, 4, 5, 6];
  }

  toString(): void {
    console.log('toString 方法 Web Component toString');
  }

  toString2(param: String): void {
    console.log('toString2 方法  Web Component toString param:' + param);
  }

  asyncTest(data: string): void {
    console.log("async data:" + data);
  }
}

@Entry
@Component
struct TestDsBridge {
  @State message: string = 'Hello World';
  webviewController: webview.WebviewController = new webview.WebviewController()
  // 创建Web控制器代理实例
  private controller: WebViewControllerProxy = WebViewControllerProxy.createController()
  private testObj = new TestObj()

  aboutToAppear(): void {
  	this.controller.setClosePageListener(() => {
     return true; // false 会拦截关闭页面
   })
    try {
      // this.controller.addJavascriptObject(new H5DSApi(), "H5DSObj")
      // this.controller.supportDS2(true);
      this.controller.addJavascriptObject(new H5DSApi())
      webview.WebviewController.setWebDebuggingAccess(true);
    } catch (error) {
      console.error(`aboutToAppear webview 配置Web开启调试模式出错了:ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
    }
  }

  // JS的注入
  registerJavaScriptProxy() {
    // javaScriptProxy接口只支持注册一个对象,使用registerJavaScriptProxy注册多个对象请
    this.controller.registerJavaScriptProxy(this.testObj, 'testObjName', JSmethodList);
  }

  build() {
    Column({space: 20}) {
      Button("使用Dsbridge调用前端 showAlert 方法").onClick(() => {
        this.controller.callJs("showAlert", [1, 2, '666'], (data: OnReturnValue) => {
          console.log("前端  showAlert 方法回调:" + data)
        })
      })
      Button("使用Dsbridge调用前端  showAlertAsync 方法").onClick(() => {
        this.controller.callJs("showAlertAsync", [1, 2, '666'], (data: OnReturnValue) => {
          console.log("前端  showAlertAsync 方法回调:" + data)
        })
      })

      // Button('deleteJavaScriptRegister').fontColor(Color.Black).fontSize(20).onClick((_event) => {
      //   try {
      //     console.log("getJavaScriptProxy name: ", this.controller.getJavaScriptProxy().name)
      //     console.log("getJavaScriptProxy name: ", JSON.stringify(this.controller.getJavaScriptProxy().methodList))
      //     console.log("getJavaScriptProxy name: ", this.controller.getJavaScriptProxy().object)
      //     //getJavaScriptProxy name:  _dsbridge
      //     // this.webviewController.deleteJavaScriptRegister(JavaScriptProxy_NAME);
      //   } catch (error) {
      //     console.error(`移除 testObjName 发生异常 ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
      //   }
      // })
      // Web({ src: H5_BASE_URL, controller: this.webviewController })// 将对象注入到web端
      Web({ src: $rawfile('testDsbridge.html'), controller: this.controller.webviewController })// 将对象注入到web端
        .overviewModeAccess(true)
        .databaseAccess(true)
        .geolocationAccess(false)
        .mediaPlayGestureAccess(true)
        .multiWindowAccess(true)
        .horizontalScrollBarAccess(false)
        .verticalScrollBarAccess(false)
        .cacheMode(CacheMode.Default)
        .forceDarkAccess(true)
        .javaScriptAccess(true) // 允许JS执行
        .fileAccess(true)        // 允许文件访问
        .imageAccess(true)       // 允许加载图片资源
        .onlineImageAccess(true) // 允许从网络加载图片
        .domStorageAccess(true)  // 允许使用DOM存储
        // .mixedMode(MixedMode.Compatible)
        .javaScriptProxy(this.controller.javaScriptProxy) // 设置JS代理
        // .javaScriptProxy({
        //   object: this.testObj,
        //   name: "android",
        //   methodList: JSmethodList,
        //   controller: this.webviewController,
        //   // 可选参数
        //   asyncMethodList: ["responseRequest"],
        // }
        .onControllerAttached(() => {
          this.registerJavaScriptProxy()
        })
        .onLoadIntercept((event) => {
          //返回true表示阻止此次加载,否则允许此次加载
          return false
        })
        .onAlert((event) =>{
          AlertDialog.show({ message: event.message })
          return false
        })
        .width("100%")
        .height("100%")
    }
    .height('100%')
    .width('100%')
  }
}

四、HarmonyOS使用Dsbridge了如何注册多个javaScriptProxy代理对象

javaScriptProxy接口只支持注册一个对象,若需要注册多个对象请使用registerJavaScriptProxy。

效果图

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

原生TestObj代码

class TestObj {
  testStr(): string {
    console.log("前端调用了 原生 testStr方法")
    return "原生 testStr方法返回的数据"
  }

  testArray(): Array<Number> {
    return [1, 2, 3, 4, 5, 6];
  }

  toString(): void {
    console.log('toString 方法 Web Component toString');
  }

  toString2(param: String): void {
    console.log('toString2 方法  Web Component toString param:' + param);
  }

  asyncTest(data: string): void {
    console.log("async data:" + data);
  }
}
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐