概述
在鸿蒙开发过程中,经常会遇到鸿蒙h5混合开发的场景,涉及到混合开发,避不开的就是两个端的通信,本文理清了鸿蒙端使用webView的runJavaScript调用h5的方法,以及h5侧调用鸿蒙侧能力的方法,附上源码以及效果。
实战前准备
准备web页面模拟h5
在鸿蒙项目的src/main/resources/rawfile 目录下新建myWeb.html,以便于Web组件引用,Web组件显示网页的方法详情可阅读之前的博客:鸿蒙实战之登录 ,Span高亮隐私协议字体,Web组件展示隐私协议,并设置输入时键盘避让,没有废话,全是干货-CSDN博客
这里是一个web页面,页面中有一个按钮,点击这个按钮,可调用鸿蒙侧的函数,
window.hm.postToH5Message() // 这个window对象下的函数是鸿蒙侧给h5端注册的函数
myWeb.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta content="width=device-width, initial-scale=1.0" name="viewport"><title>鸿蒙h5通信示例</title><style>body {font-family: Arial, sans-serif;text-align: center;margin-top: 50px;}button {padding: 10px 20px;margin: 10px;font-size: 16px;cursor: pointer;background-color: #4CAF50;color: white;border: none;border-radius: 5px;}button:hover {background-color: #45a049;}#msg {margin-top: 20px;font-size: 24px;font-weight: bold;}#result {margin-top: 20px;font-size: 18px;}</style>
</head>
<body>
<h1>我是H5</h1>
<button onclick="getHmMessage()">点我调用鸿蒙侧函数</button>
<div id="msg">还未调用</div>
<div id="result"></div><script>let msg = '';// H5侧调用鸿蒙侧函数function getHmMessage() {window.hm.postToH5Message()}// 鸿蒙侧调用的函数function changeMessage(hmMsg) {msg = hmMsgdocument.getElementById("msg").textContent = msg;}
</script>
</body>
</html>
开始实战
鸿蒙调用h5的函数
下面是官方api文档:
@ohos.web.webview (Webview)-ArkTS API-ArkWeb(方舟Web)-应用框架 - 华为HarmonyOS开发者https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V14/js-apis-webview-V14#runjavascript
鸿蒙调用h5侧的函数,官方提供了一个方法,就是webView控制器上的runJavaScript方法,这个方法接收一个字符串,这个字符串就是h5侧被调用的方法,注意:传参时要注意一个问题,就是咱这里的调用这个方法,是直接写字符串去调用,但是如果要在调用方法里边传参,且正好是个字符串,就需要区分双引号和单引号,保证对runJavaScript穿的方法收尾对应的是一组符号,而方法内部传参对应的是一组符号,示例如下:
this.controller.runJavaScript('changeMessage("调用h5方法成功")')
在鸿蒙侧准备一个按钮,去点击触发h5的方法
Button('runJavaScript方法调用js方法').onClick(() => {if (this.controller) {this.controller.runJavaScript('changeMessage("调用h5方法成功")')}})
在h5侧声明这个方法
// 鸿蒙侧调用的函数function changeMessage(hmMsg) {msg += hmMsgdocument.getElementById("msg").textContent = msg;}
很明显,鸿蒙侧调用这个changeMessage之后h5侧的msg就会一直拼上鸿蒙这边传过去的参数,效果如下:
h5调用鸿蒙:
鸿蒙给h5注册方法
h5调用鸿蒙侧的能力,官方也提供了一个api就是Web组件的javaScriptProxy方法,
Web-ArkTS 组件-ArkWeb(方舟Web)-应用框架 - 华为HarmonyOS开发者,
还有webView控制器的registerJavaScriptProxy方法,Web-ArkTS 组件-ArkWeb(方舟Web)-应用框架 - 华为HarmonyOS开发者
二者的用法一样,接收的参数也差不多,但是也有点区别:
javaScriptProxy和registerJavaScriptProxy有什么区别,能注册多少个对象-Web开发(ArkWeb)-Web框架-应用框架开发-开发 - 华为HarmonyOS开发者
从功能上讲,二者都可以注入JavaScript对象到window对象中,并在window对象中调用该对象的方法。
从注册对象上讲,前者只能注册一个对象,后者可以注册多个对象。
从生命周期上讲,javaScriptProxy在Web组件初始化调用,registerJavaScriptProxy在Web组件初始化完成后调用。
从接口上讲,javaScriptProxy是Web组件的方法,而registerJavaScriptProxy是WebviewController的方法。
javaScriptProxy可以参考javaScriptProxy,registerJavaScriptProxy可以参考registerJavaScriptProxy
这里就介绍JavaScriptProxy的用法,先分析这个属性接收的参数
名称 | 类型 | 必填 | 说明 |
---|---|---|---|
object | object | 是 | 参与注册的对象。只能声明方法,不能声明属性。 |
name | string | 是 | 注册对象的名称,与window中调用的对象名一致。 |
methodList | Array<string> | 是 | 参与注册的应用侧JavaScript对象的同步方法。 |
controller | WebController | WebviewController9+ | 是 | - |
asyncMethodList12+ | Array<string> | 否 | 参与注册的应用侧JavaScript对象的异步方法。异步方法无法获取返回值。 |
permission12+ | string | 否 | json字符串,默认为空,通过该字符串配置JSBridge的权限管控,可以定义object、method一级的url白名单。 示例请参考前端页面调用应用侧函数。 |
这里只需关注必传参数,其他参数按需传入即可,案例中传入了四个参数,具体如下:
鸿蒙侧被调用的方法
// h5侧调用时鸿蒙侧弹一个窗postToH5Message() {AlertDialog.show({ message: '鸿蒙侧被h5调用了', })}
给javaScriptProxy方法传参
Web({src: $rawfile('myWeb.html'),controller: this.controller}).layoutWeight(1).javaScriptProxy({// 参与h5端注册的对象object: {postToH5Message: () => {this.postToH5Message();},},// 注册的js对象名name: "hm",// 注册的js方法methodList: ["postToH5Message"],// web的控制器controller: this.controller})
h5调用鸿蒙侧方法
到此咱们已经将鸿蒙侧的方法注册到了h5的window对象下的hm对象下,h5侧调用就只需要在需要的时机调用window.hm.postToH5Message()方法即可调用鸿蒙端的能力,示例中点击按钮之后,调用鸿蒙侧的方法,鸿蒙侧就会弹窗提示被调用:
<body>
<h1>我是H5</h1>
<button onclick="getHmMessage()">点我调用鸿蒙侧函数</button>
<div id="msg">还未调用</div>
<div id="result"></div><script>let msg = '';// H5侧调用鸿蒙侧函数function getHmMessage() {window.hm.postToH5Message()}// 鸿蒙侧调用的函数function changeMessage(hmMsg) {msg += hmMsgdocument.getElementById("msg").textContent = msg;}
</script>
</body>
总结:
至此,鸿蒙侧调用h5侧方法,以及h5侧调用鸿蒙侧能力的一个小案例就完成了,在实际开发中可根据使用场景去灵活搭配使用, 通信的核心就是鸿蒙侧两个api :鸿蒙调用h5就使用web控制器的runJavaScript方法,h5调用鸿蒙侧就使用javaScriptProxy方法给h5侧的window对象注册函数,去调用鸿蒙侧能力
完整代码:
h5侧:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta content="width=device-width, initial-scale=1.0" name="viewport"><title>鸿蒙h5通信示例</title><style>body {font-family: Arial, sans-serif;text-align: center;margin-top: 50px;}button {padding: 10px 20px;margin: 10px;font-size: 16px;cursor: pointer;background-color: #4CAF50;color: white;border: none;border-radius: 5px;}button:hover {background-color: #45a049;}#msg {margin-top: 20px;font-size: 24px;font-weight: bold;}#result {margin-top: 20px;font-size: 18px;}</style>
</head>
<body>
<h1>我是H5</h1>
<button onclick="getHmMessage()">点我调用鸿蒙侧函数</button>
<div id="msg">还未调用</div>
<div id="result"></div><script>let msg = '';// H5侧调用鸿蒙侧函数function getHmMessage() {window.hm.postToH5Message()}// 鸿蒙侧调用的函数function changeMessage(hmMsg) {msg += hmMsgdocument.getElementById("msg").textContent = msg;}
</script>
</body>
</html>
鸿蒙侧:
import webview from '@ohos.web.webview'@Entry
@Component
struct WebPage {controller: webview.WebviewController = new webview.WebviewController()@State msg: string = '我是鸿蒙侧'postToH5Message() {AlertDialog.show({ message: '鸿蒙侧被h5调用了', })}build() {Column({ space: 20 }) {Text('鸿蒙h5通信').margin({ top: 20 }).fontSize(26).fontWeight(FontWeight.Bold).width('100%').height(60).textAlign(TextAlign.Center).backgroundColor('#F6662F')Column({ space: 20 }) {Text(this.msg).fontSize(24).fontWeight(FontWeight.Bold)Button('runJavaScript方法调用js方法').onClick(() => {if (this.controller) {this.controller.runJavaScript('changeMessage("调用h5方法成功")')}})}.layoutWeight(1).justifyContent(FlexAlign.Center)Web({src: $rawfile('myWeb.html'),controller: this.controller}).layoutWeight(1).javaScriptProxy({// 参与h5端注册的对象object: {postToH5Message: () => {this.postToH5Message();},},// 注册的js对象名name: "hm",// 注册的js方法methodList: ["postToH5Message"],// web的控制器controller: this.controller})}.backgroundColor(Color.Gray).height('100%').width('100%')}
}