HarmonyOS 鸿蒙Next上实现ArkTS与H5的交互
HarmonyOS 鸿蒙Next上实现ArkTS与H5的交互
介绍
本篇Codelab主要介绍H5如何调用原生侧相关功能,并在回调中获取执行结果。以“获取通讯录”为示例分步讲解JSBridge桥接的实现。
相关概念
-
Web组件:提供具有网页显示能力的Web组件。
-
@ohos.web.webview:提供web控制能力。
完整示例
源码下载
环境搭建
我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
软件要求
-
DevEco Studio版本:DevEco Studio 3.1 Release。
-
HarmonyOS SDK版本:API version 9。
硬件要求
-
设备类型:华为手机或运行在DevEco Studio上的华为手机设备模拟器。
-
HarmonyOS系统:3.1.0 Developer Release。
环境搭建
-
安装DevEco Studio,详情请参考下载和安装软件。
-
设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
-
如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
-
如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
-
-
开发者可以参考以下链接,完成设备调试的相关配置:
代码结构解读
本篇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方法。
-
准备异步执行脚本,在脚本中声明一个JSBridgeMap、JSBridgeCallback方法与ohosCallNative对象。并通过runJavaScript在H5端注册ohosCallNative。
-
通过Web组件的javaScriptProxy属性将ArkTS侧的call方法以及JSBridgeHandle注册到H5。
-
H5侧调用ohosCallNative对象中的callNative方法,传递func、params以及callback回调。在callNative中保存callback回调。并调用JSBridgeHandle的call方法。
-
ArkTS侧执行完毕。最后调用runJavaScript方法执行callback,H5侧接收异步回调数据。
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的学习,并了解到以下知识点:
-
ArkTS侧如何使用桥接通道提供给H5调用方法。
-
H5如何接收ArkTS侧的异步数据。
关于HarmonyOS 鸿蒙Next上实现ArkTS与H5的交互的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。
打开Codelabs/SelectContact项目,运行在模拟器上,点击联系人,无响应。
DevEco Studio版本:DevEco Studio 3.1.1 Release
我换了一个测试机,在华为 Pocket S 上面是正常的。有网友说,H5的测试,模拟器不支持,只能在真机上面
点击联系人无反应,我看了下相关文档,说是demo中的方式,只支持FA模型,你看看你开发模型是否一致
webview.addJavascriptInterface(xxxtInterface, "Android"),这种文档,比较 写鸿蒙 应该大部分是android的吧。这种对接h5的东西,应该在不修改h5的前提下吧。不把这些东西搞清楚,开发者怎么开发。体验真心有点差啊
期待HarmonyOS能继续优化多屏协同功能,让跨设备体验更加完美。
确实啊,我也想找这种文档。我们项目之前的H5页面都是基于Cordova.js来调用原生能力的。调用方式不一致。我现在测试时,只要 H5页面引入了 Android 的 Cordova.js,在Web上面加载时,就展示不出来。但是如果将Web当作浏览器,不引入 Cordova.js,就能够正常显示。好几天了,也没找到问题所在。主要是没有报错信息。
附议。期待更优雅的解决方案。
我蹲一个?
查个眼
我年初就写好了Web JsBridge的代码,可以打开网页,弹出原生的对话框、上传文件、音频录音等。现在Next版本API大变样,不支持自定义装饰器了,然后进行了装饰器部分的代码改造,
因为没加入NEXT开发活动,也没有设备运行,
部分代码:
楼主你好,我想咨询一下你这传参中data 类型的定义,是给changeTel 用了这个下面接口去定义,那我如果其他的函数也要出传参,那这个打他的类型该怎么定义啊,感觉,所有的函数都用这个data 类型不好定义
您好,请问您有这份源码吗,能不能分享一下
就是上面楼主的发的gitee 里面的啊
你好,请问一下我参考demo写的但是发现原生调h5的时候调不通:this.controller.runJavaScript(`JSBridgeCallback("${id}", ${JSON.stringify(data)})`);
感觉自己写的没有问题,有没有大佬指导一下!