HarmonyOS鸿蒙应用开发——探索原生与H5通信框架DSBridge

简介: HarmonyOS版DSBridge是一个桥梁库,允许鸿蒙原生环境与JavaScript交互。它兼容Android和iOS的第三方DSBridge核心功能,支持同步和异步调用、命名空间API管理、进度回调及页面关闭监听等功能。主要特性包括适配鸿蒙NEXT版本、支持串行异步并发任务、兼容DSBridge 2.0与3.0版本JS脚本,并提供类形式集中管理API及自定义页面组件注册。源码仓库:HarmonyOS版 - DSBridge-HarmonyOS。安装命令为`ohpm install @hzw/ohos-dsbridge`。通过该库,开发者可以方便地在鸿蒙系统中实现原生与JS的高效交互。

HarmonyOS版的DSBridge是一个桥梁库,它允许鸿蒙原生环境与JavaScript之间进行交互,彼此能够调用对方的功能。该库目前兼容Android和iOS上第三方DSBridge库的核心功能,基本保持了原有的使用方式。


主要特性包括:

  • 已适配鸿蒙NEXT版本;
  • 支持在原生同步方法中执行串行异步并发任务,并同步等待异步结果,这是根据鸿蒙系统特点而设计的功能;
  • 同时兼容DSBridge 2.0与3.0版本的JS脚本;
  • 支持以类的形式集中统一管理API,同时也支持原生自定义页面组件的直接注册和使用;
  • 支持同步和异步调用方式;
  • 支持进度回调/回传功能,即一次调用可以多次返回结果;
  • 提供API存在性检测功能;
  • 支持监听和拦截JavaScript关闭页面的操作;
  • 支持命名空间API。


源码仓库

HarmonyOS版:DSBridge-HarmonyOSAndroid版:DSBridge-Android(建议使用维护中的版本:github.com/751496032/D…)iOS版:DSBridge-IOS


由于原DSBridge库的作者已停止维护,对于Android端,我们推荐使用由社区维护的活跃版本,以确保获得最新的功能和修复。


安装指南

安装库

使用以下命令安装@hzw/ohos-dsbridge库:

ohpm install @hzw/ohos-dsbridge


或者安装本地HAR包

如果你有一个本地的HAR包,可以使用以下命令进行安装:

ohpm install ../libs/library.har


基本用法

在ArkTS原生侧,你可以通过以下两种方式之一来实现和管理API接口:


1.新建一个类来集中统一管理API:

你可以创建一个名为JsBridge的类,并使用@JavaScriptInterface()装饰器来标注其方法,以便在JavaScript中调用。这个装饰器是为了保持与Android的一致性而自定义的。

export class JsBridge {
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;
}
}


2.在自定义页面组件中直接注册使用

如果你不希望使用类来管理API接口,你可以在自定义页面组件中直接注册并使用API接口。

@Component
@Entry
struct UseInComponentsPage {
aboutToAppear() {
// 在一个组件内只能存在一个无命名空间的对象
this.controller.addJavascriptObject(this);
}
/**
* 组件中的同步方法
* @param args 输入参数
* @returns 返回字符串
*/
@JavaScriptInterface(false)
testComponentSync(args: string): string {
return `组件中的同步方法: ${args}`;
}
/**
* 组件中的异步方法
* @param args 输入参数
* @param handler 回调处理函数
*/
@JavaScriptInterface()
testComponentAsync(args: string, handler: CompleteHandler) {
handler.complete(`组件中的异步方法: ${args}`);
}
}

注意:

  • API的同步方法不支持使用async/await声明。如果需要在同步方法内执行异步任务,可以使用taskWait()函数来完成。
  • 异步方法的形参CompleteHandler可用于结果的异步回调。


Web组件中的JS注入与交互

在原生Web组件初始化时,你可以通过WebViewControllerProxy类来获取WebViewController实例,以实现JS注入,并将其关联到Web组件中。接着,将API管理类(如JsBridge)关联到WebViewControllerProxy中,以便在Web页面中调用原生方法。

private controller: WebViewControllerProxy = WebViewControllerProxy.createController();
aboutToAppear() {
// 将JsBridge实例添加到WebView中,以便在JavaScript中访问
this.controller.addJavascriptObject(new JsBridge());
}
// 配置Web组件,并关联controller
Web({
src: this.localPath,
controller: this.controller.getWebViewController()
})
.javaScriptAccess(true) // 允许JavaScript执行
.javaScriptProxy(this.controller.getJavaScriptProxy()) // 设置JavaScript代理
.onAlert((event) => {
// 处理JavaScript中的alert事件
// AlertDialog.show({ message: event.message });
return false;
});


调用JavaScript函数

通过WebViewControllerProxy,你可以方便地调用JavaScript函数。callJs()方法提供了三个参数:第一个是JavaScript中注册的函数名称,第二个是传递给JavaScript函数的参数数组,第三个是监听JavaScript函数返回结果的回调函数。

Button("调用js函数-同步")  
  .onClick(() => {  
    this.controller.callJs("showAlert", [1, 2, '666'], (v) => {  
      this.msg = v + "";  
    });  
  });  
  
Button("调用js函数-异步")  
  .onClick(() => {  
    this.controller.callJs("showAlertAsync", [1, 2, '666'], (v) => {  
      this.msg = v + "";  
    });  
  });


兼容DSBridge2.0

如果你的前端使用的是DSBridge2.0的JS脚本,你可以通过supportDS2()方法来兼容。

aboutToAppear() {  
  // 如果是使用DSBridge2.0,调用supportDS2方法  
  this.controller.supportDS2(true);  
  
  // 注册JavaScript对象,两种方式任选其一  
  this.controller.addJavascriptObject(this);  
  // 或者  
  // this.controller.addJavascriptObject(new JsBridge2());  
  
  // 开启调试模式  
  webview.WebviewController.setWebDebuggingAccess(true);  
}

这样,你就可以在原生Web组件中方便地实现与JavaScript的交互,并兼容不同的JS脚本版本。


JavaScript侧dsBridge初始化与交互

1.初始化dsBridge

你可以通过npm安装或CDN引入的方式来初始化dsBridge。如果项目没有历史包袱,建议直接使用m-dsbridge包。

npm i m-dsbridge

或者,通过CDN引入:

<script src="https://cdn.jsdelivr.net/npm/m-dsbridge/dsBridge.js"></script>

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

<script src="https://cdn.jsdelivr.net/npm/dsbridge/dist/dsbridge.js"></script>

2.注册JavaScript函数供原生调用

通过dsBridge对象,你可以注册JavaScript函数,以便原生代码能够调用它们。

// 注册同步函数  
dsBridge.register('showAlert', function (a, b, c) {  
  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端的一次调用、多次返回。


3.调用原生API

通过dsBridge对象,你也可以调用原生API。第一个参数是原生方法名称,第二个参数是原生方法接收的参数。对于异步方法,还有第三个参数是回调函数,用于接收异步回调结果。

// 同步调用  
let msg = dsBridge.call('testSync', JSON.stringify({data: 100}));  
// 异步调用  
dsBridge.call('testAsync', JSON.stringify({data: 200}), (msg) => {  
  updateMsg(msg);  
});

这样,你就可以在JavaScript侧方便地初始化dsBridge,注册函数供原生调用,以及调用原生API了。


进度回调与页面关闭监听

进度回调(一次调用,多次返回)

在原生端,也支持JavaScript端的一次调用、多次回调的模式,这在某些应用场景下非常有用,比如将原生的下载进度实时同步到JavaScript中。这可以通过CompleteHandler#setProgressData()方法来实现。

原生端示例(假设使用TypeScript和Android环境):

@JavaScriptInterface()  
testAsync(p: string, handler: CompleteHandler) {  
  LogUtils.d("testAsync: " + JSON.stringify(p));  
  this.cHandler = handler;  
  let counter = 0;  
  setInterval(() => {  
    if (counter < 5) {  
      counter++;  
      handler.setProgressData("异步返回的数据--" + counter);  
    } else {  
      this.cHandler.complete("异步返回的数据--结束");  
      // 注意:通常complete只调用一次,表示异步操作完成。如果需要发送多个结束信号,请确保逻辑的正确性。  
      // this.cHandler.complete("异步返回的数据--结束2"); // 这行代码可能需要根据实际情况调整或删除。  
    }  
  }, 1000);  
}

JavaScript端调用:

dsBridge.call('testAsync', JSON.stringify({data: 200}), (msg) => {  
  updateMsg(msg);  
});


监听或拦截JavaScript关闭页面

当JavaScript调用close()函数尝试关闭当前页面时,原生代码可以设置监听器来观察并决定是否拦截这一行为。

原生端示例(假设使用TypeScript和某原生框架):

aboutToAppear() {  
  this.controller.setClosePageListener(() => {  
    return false; // 返回false会拦截关闭页面的事件,返回true则允许页面关闭。  
  });  
}

在回调函数中,如果返回false,则会拦截掉关闭页面的事件;如果返回true,则允许页面正常关闭。这提供了一种机制,让原生代码能够控制页面的关闭行为。


销毁结束任务与命名空间管理


销毁结束任务

当异步任务(如setProgressData)仍在执行中,如果此时关闭页面,可能会导致应用闪退。为了避免这种情况,建议在组件的生命周期函数aboutToDisappear()中结束任务。

原生端示例(假设使用TypeScript和某原生框架):

aboutToDisappear() {  
  this.jsBridge.destroy(); // 销毁并结束所有正在执行的任务  
}


命名空间管理

命名空间可以帮助你更好地管理API,尤其在API数量较多时。它允许你将API分类管理,不同级之间只需用.分隔即可。命名空间支持同步与异步方式使用。

原生端设置命名空间

原生端使用WebViewControllerProxy#addJavascriptObject方法指定一个命名空间名称:

this.controller.addJavascriptObject(new JsBridgeNamespace(), "namespace");

JavaScript端使用命名空间

在JavaScript中,使用命名空间名称加上对应的原生函数名来调用原生功能。

const callNative6 = () => {  
  let msg = dsBridge.call('namespace.testSync', { msg: '来自js命名空间的数据' });  
  updateMsg(msg);  
};  
  
const callNative7 = () => {  
  dsBridge.call('namespace.testAsync', 'test', (msg) => {  
    updateMsg(msg);  
  });  
};

JavaScript端注册命名空间

你也可以在JavaScript端使用dsBridge对象注册js函数的命名空间。

// 注册同步命名空间  
dsBridge.register('sync', {  
  test: function (a, b) {  
    return "namespace:  " + (a + b);  
  }  
});  
  
// 注册异步命名空间  
dsBridge.registerAsync("async", {  
  test: function (a, b, callback) {  
    callback("namespace:  " + (a + b));  
  }  
});

第一个参数是命名空间的名称,比如sync或async,第二个参数是API业务对象实例,支持字面量对象和Class类实例。


原生端调用JavaScript命名空间中的函数

this.controller.callJs("sync.test", [1, 2], (value: string) => {  
  this.msg = value;  
});  
  
this.controller.callJs("async.test", [3, 2], (value: string) => {  
  this.msg = value;  
});

通过命名空间,你可以更加有序地管理你的API,使得代码更加清晰和易于维护。


在原生同步方法中执行串行异步并发任务

在鸿蒙系统中,原生同步方法通常不支持直接使用async/await来处理异步任务,这主要受到鸿蒙Web脚本注入机制的限制,同时也为了兼容Android/iOS项目。为了满足在同步方法中执行异步任务并立即返回结果给H5的需求,我们设计了一个taskWait()函数。

taskWait()函数允许在同步方法中执行串行异步并发任务,主线程会同步等待异步结果。如果任务在3秒内未完成,函数会自动结束等待并返回结果,但这种情况下可能会存在数据丢失的风险。

以下是一个使用taskWait()函数在同步方法中执行异步任务的示例:

/**  
 * 同步方法中执行异步并发任务  
 * @param args 传入参数  
 * @returns 返回计算结果  
 */  
@JavaScriptInterface(false)  
testTaskWait(args: string): number {  
  let p = new Param(100, 200);  
  let p1 = new Param(100, 300);  
  
  // 执行异步任务并等待结果  
  taskWait(p);  
  p1.tag = "Param";  
  taskWait(p1);  
  
  // 输出日志并返回结果  
  LogUtils.d(`testTaskWait sum: ${p.sum}  ${p1.sum}`);  
  return p.sum + p1.sum;  
}


其中,Param类需要继承BaseSendable,并使用@Sendable装饰器声明。异步任务放在run()方法中执行:

@Sendable  
export class Param extends BaseSendable {  
  private a: number = 0;  
  private b: number = 0;  
  public sum: number = 0;  
  public enableLog: boolean = true;  
  
  constructor(a: number, b: number) {  
    super();  
    this.a = a;  
    this.b = b;  
  }  
  
  // 异步任务执行  
  async run(): Promise<void> {  
    this.sum = await this.add();  
  }  
  
  async add(): Promise<number> {  
    return this.a + this.b;  
  }  
}


需要注意的是,taskWait()函数是一个轻量级的同步等待函数,不建议执行耗时过长的任务。对于特别耗时的任务,建议使用异步桥接函数来避免阻塞主线程和数据丢失的风险。


目录
相关文章
|
7月前
|
存储 IDE 开发工具
HarmonyOS应用开发尝鲜篇:HarmonyOS快速入门
HarmonyOS应用开发尝鲜篇:HarmonyOS快速入门
|
4天前
|
安全 架构师 数据管理
《鸿蒙HarmonyOS应用开发从入门到精通(第2版)》简介
《鸿蒙HarmonyOS应用开发从入门到精通(第2版)》由北京大学出版社出版,内容涵盖HarmonyOS架构、DevEco Studio、Ability、安全管理等,辅以68个实例和4个综合实战案例。全书589页,定价129元,适合学生、开发人员及架构师。封面延续黑色设计,配以蓝色“鸿蒙HarmonyOS”字样,富有科技感。本书紧跟最新技术,提供源代码下载和勘误交流平台,帮助读者掌握HarmonyOS开发技能,构建万物互联的新时代。
56 22
|
4天前
|
数据管理 API 调度
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
HarmonyOS Next 是华为新一代操作系统,专注于分布式技术的深度应用与生态融合。本文通过技术特点、应用场景及实战案例,全面解析其核心技术架构与开发流程。重点介绍分布式软总线2.0、数据管理、任务调度等升级特性,并提供基于 ArkTS 的原生开发支持。通过开发跨设备协同音乐播放应用,展示分布式能力的实际应用,涵盖项目配置、主界面设计、分布式服务实现及部署调试步骤。此外,深入分析分布式数据同步原理、任务调度优化及常见问题解决方案,帮助开发者掌握 HarmonyOS Next 的核心技术和实战技巧。
120 76
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
|
1天前
【HarmonyOS Next开发】:ListItemGroup使用
通过使用ListItemGroup和AlphabetIndexer两种类型组件,实现带标题分类和右侧导航栏的页面
81 61
|
4天前
|
物联网 调度 vr&ar
鸿蒙HarmonyOS应用开发 |鸿蒙技术分享HarmonyOS Next 深度解析:分布式能力与跨设备协作实战
鸿蒙技术分享:HarmonyOS Next 深度解析 随着万物互联时代的到来,华为发布的 HarmonyOS Next 在技术架构和生态体验上实现了重大升级。本文从技术架构、生态优势和开发实践三方面深入探讨其特点,并通过跨设备笔记应用实战案例,展示其强大的分布式能力和多设备协作功能。核心亮点包括新一代微内核架构、统一开发语言 ArkTS 和多模态交互支持。开发者可借助 DevEco Studio 4.0 快速上手,体验高效、灵活的开发过程。 239个字符
148 13
鸿蒙HarmonyOS应用开发 |鸿蒙技术分享HarmonyOS Next 深度解析:分布式能力与跨设备协作实战
|
2天前
|
人工智能 小程序 Android开发
鸿蒙应用开发从入门到入行 - 篇1:HarmonyOS介绍——带你深入理解鸿蒙特性
本文介绍了华为的HarmonyOS(鸿蒙系统),这是一个面向全场景的分布式操作系统,不仅适用于手机和平板,还支持电脑、车机、手表、电视等多种设备。文章详细解析了鸿蒙系统的三大特性:一次开发多端部署、可分可合自由流转、统一生态原生智能,并分析了鸿蒙系统为何能蚕食安卓市场份额的原因。猫林老师认为,鸿蒙凭借其先进的技术和国内政策支持,有望在未来的市场中占据重要地位。最后,文章提供了学习鸿蒙系统的建议和一些课后练习,帮助读者更好地理解和掌握这一系统。
28 7
鸿蒙应用开发从入门到入行 - 篇1:HarmonyOS介绍——带你深入理解鸿蒙特性
|
23小时前
|
物联网 开发工具 Android开发
《鸿蒙HarmonyOS应用开发从入门到精通(第2版)》学习笔记——HarmonyOS产生的背景
HarmonyOS是华为自主研发的分布式操作系统,旨在应对美国“实体清单”带来的技术封锁。2019年首次亮相,它不仅支持手机、平板等多终端设备,还通过统一的软件系统解决了不同设备间的体验割裂问题。HarmonyOS强调全场景智能互联,提升设备间的安全性和协同能力。其商用版本基于OpenHarmony开源项目开发,而HarmonyOS NEXT则是去除了AOSP代码的纯自研版本,代表了未来发展方向。
26 12
|
7月前
|
JavaScript 前端开发 IDE
HarmonyOS应用开发尝鲜篇:初识HarmonyOS
HarmonyOS应用开发尝鲜篇:初识HarmonyOS
|
前端开发 JavaScript Java
华为HarmonyOS鸿蒙应用开发初体验
HarmonyOS鸿蒙系统出来好几年了,开发鸿蒙应用和咱平时的前端开发到底有什么差别呢,下面就从一个前端开发的视角带领大家体验一下HarmonyOS开发。
208 0
|
存储 安全 数据安全/隐私保护
HarmonyOS 高级特性
本章将探讨 HarmonyOS 的高级特性,包括分布式能力、安全机制和性能优化。这些特性可以帮助你构建更强大、更安全、更高效的应用。
195 0

热门文章

最新文章