HarmonyOS 鸿蒙Next上实现ArkTS与H5的交互

发布于 1周前 作者 wuwangju 来自 鸿蒙OS

HarmonyOS 鸿蒙Next上实现ArkTS与H5的交互

介绍

本篇Codelab主要介绍H5如何调用原生侧相关功能,并在回调中获取执行结果。以“获取通讯录”为示例分步讲解JSBridge桥接的实现。

相关概念

完整示例

gitee源码地址

源码下载

ArkTS与H5的交互(ArkTS).zip

1694078706704.gif

环境搭建

我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。

软件要求

硬件要求

  • 设备类型:华为手机或运行在DevEco Studio上的华为手机设备模拟器。

  • HarmonyOS系统:3.1.0 Developer Release。

环境搭建

  1. 安装DevEco Studio,详情请参考下载和安装软件

  2. 设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:

    • 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。

    • 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境

  3. 开发者可以参考以下链接,完成设备调试的相关配置:

image.png

代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。

├──entry/src/main/ets              // 代码区	        
│  ├──common                       // 公共代码区
│  │  ├──constants                 // 公共常量
│  │  │  ├──CodeConstant.ets       // 异步脚本模板
│  │  │  └──CommonConstant.ets     // 公共常量和样式常量
│  │  └──utils                     // 工具类
│  │     ├──JsBridge.ets           // 桥接类
│  │     └──Logger.ets             // 日志类
│  ├──entryability
│ │ └──EntryAbility.ets // 程序入口 │ ├──pages │ │ └──SelectContact.ets // 主页面 │ └──viewmodel // 项目所需数据类型定义 │ ├──JavaScriptItem.ets // javaScriptProxy数据格式 │ └──ParamsItem.ets // 回调参数数据格式 └──entry/src/main/resources // 资源入口(rawfile文件夹中存放html) └──rawfile ├──js
│ └──mainPage.js // H5调用函数文件 ├──css │ └──main.css // H5样式文件 └──MainPage.html // H5页面
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

ArkTS侧与H5的交互

首先在开发H5页面(输入框和金额选择部分)前需要实现JSBridge桥接打通两侧的交互。开发者可以在ArkTS侧定义一个JSBridge类,在类中封装call方法以及initJsBridge方法。

  1. 准备异步执行脚本,在脚本中声明一个JSBridgeMap、JSBridgeCallback方法与ohosCallNative对象。并通过runJavaScript在H5端注册ohosCallNative。

  2. 通过Web组件的javaScriptProxy属性将ArkTS侧的call方法以及JSBridgeHandle注册到H5。

  3. H5侧调用ohosCallNative对象中的callNative方法,传递func、params以及callback回调。在callNative中保存callback回调。并调用JSBridgeHandle的call方法。

  4. ArkTS侧执行完毕。最后调用runJavaScript方法执行callback,H5侧接收异步回调数据。

image.png

4.1 初始化JSBridge

在initJSBridge方法中,通过webviewControll.runJavaScript()将JSBridge初始化脚本注入H5执行。其中callID用来标识H5回调;JSBridgeCallback方法用来执行H5侧回调;window.ohosCallNative对象给H5侧提供调用函数。

// CodeConstant.ets

/**

  • 异步执行脚本 */ export const code = ` const JSBridgeMap = {}; let callID = 0;

// 执行H5回调函数 function JSBridgeCallback (id, params) { JSBridgeMapid; JSBridgeMap[id] = null; delete JSBridgeMap[id]; }

// 在window中声明callNative方法供H5调用 window.ohosCallNative = { callNative(method, params, callback) { const id = callID++; const paramsObj = { callID: id, data: params || null } JSBridgeMap[id] = callback || (() => {}); JSBridgeHandle.call(method, JSON.stringify(paramsObj)); } } `;<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

4.2 javaScriptProxy注入

通过Web组件的javaScriptProxy属性,将JSBridgeHandle对象注册到H5侧的window上,作为H5调用原生的通道。

// JsBridge.ets
export default class JsBridge {
/**

  • 注入JavaScript对象到window对象中
  • @returns javaScriptProxy object */ get javaScriptProxy(): JavaScriptItem { return { object: { call: this.call }, name: “JSBridgeHandle”, methodList: [‘call’], controller: this.controller } as JavaScriptItem; } }

// SelectContact.ets @Entry @Component struct SelectContact { webController: WebView.WebviewController = new WebView.WebviewController(); private jsBridge: JSBridge = new JSBridge(this.webController);

build() { Column() { Web({ src: $rawfile(‘MainPage.html’), controller: this.webController }) .javaScriptAccess(true) .javaScriptProxy(this.jsBridge.javaScriptProxy) … } … } }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

4.3 call方法及callback回调

call方法作为H5调用原生侧接口的统一入口,在该方法中根据H5调用的方法名,匹配到对应的接口后调用,调用结束后通过this.callback()方法,将调用结果回传到H5。

// JsBridge.ets
/**

  • 定义桥接类 / export default class JsBridge { /*
    • 将ArkTS侧数据传递给call方法 */ call = (func: string, params: string): void => { const paramsObject: ParamsItem = JSON.parse(params); switch (func) { case ‘chooseContact’: result = this.chooseContact(); break; default: break; } result.then((data: string) => { this.callback(paramsObject?.callID, data); }) }

/**

  • 将ArkTS侧数据传递到H5 */ callback = (id: number, data: string): void => { this.controller.runJavaScript(JSBridgeCallback(<span class="hljs-string"><span class="hljs-string">"${id}"</span></span>, ${<span class="hljs-built_in"><span class="hljs-built_in">JSON</span></span>.stringify(data)})); } }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

4.4 H5调用ArkTS

实现了上述桥接逻辑后,在H5侧只需要调用ohosCallNative方法,将函数名以及回调函数传递到ArkTS。

// mainPage.js
function chooseContact() {
window.ohosCallNative.callNative(‘chooseContact’, {}, (data) => {
…
});
}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. ArkTS侧如何使用桥接通道提供给H5调用方法。

  2. H5如何接收ArkTS侧的异步数据。



关于HarmonyOS 鸿蒙Next上实现ArkTS与H5的交互的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。
17 回复

打开Codelabs/SelectContact项目,运行在模拟器上,点击联系人,无响应。

DevEco Studio版本:DevEco Studio 3.1.1 Release

我也是,找了个华为手机Mate 30 5G,测试也是无反应

我换了一个测试机,在华为 Pocket S 上面是正常的。有网友说,H5的测试,模拟器不支持,只能在真机上面

点击联系人无反应,我看了下相关文档,说是demo中的方式,只支持FA模型,你看看你开发模型是否一致

怎么在 jsbridge 里弹出自定义弹窗
我想问问 这鸿蒙的webview 的使用 有没有 更详细的文档,我就感觉到只使用一个api 没有什么一步一步 走过来,代表什么的详细教程,就让开发者一步一步摸索每一步代表什么意思,例如window.ohosCallNative 这个 ohosCallNative 是必须这个名字 还是随便写,它是否是相当于Android的

webview.addJavascriptInterface(xxxtInterface, "Android"),这种文档,比较 写鸿蒙 应该大部分是android的吧。这种对接h5的东西,应该在不修改h5的前提下吧。不把这些东西搞清楚,开发者怎么开发。体验真心有点差啊

期待HarmonyOS能继续优化多屏协同功能,让跨设备体验更加完美。

确实啊,我也想找这种文档。我们项目之前的H5页面都是基于Cordova.js来调用原生能力的。调用方式不一致。我现在测试时,只要 H5页面引入了 Android 的 Cordova.js,在Web上面加载时,就展示不出来。但是如果将Web当作浏览器,不引入 Cordova.js,就能够正常显示。好几天了,也没找到问题所在。主要是没有报错信息。

附议。期待更优雅的解决方案。

请问目前除了让H5修改支持JSBridge的调用形式,之前的window postMessage这种形式完成不了与鸿蒙原生的H5交互了么?

我年初就写好了Web JsBridge的代码,可以打开网页,弹出原生的对话框、上传文件、音频录音等。现在Next版本API大变样,不支持自定义装饰器了,然后进行了装饰器部分的代码改造,

因为没加入NEXT开发活动,也没有设备运行,

部分代码:

cke_4789.png

cke_4158.png

楼主你好,我想咨询一下你这传参中data 类型的定义,是给changeTel 用了这个下面接口去定义,那我如果其他的函数也要出传参,那这个打他的类型该怎么定义啊,感觉,所有的函数都用这个data 类型不好定义cke_164.png

cke_389.png

您好,请问您有这份源码吗,能不能分享一下

就是上面楼主的发的gitee 里面的啊

你好,请问一下我参考demo写的但是发现原生调h5的时候调不通:this.controller.runJavaScript(`JSBridgeCallback("${id}", ${JSON.stringify(data)})`);

感觉自己写的没有问题,有没有大佬指导一下!

回到顶部