HarmonyOS NEXT开发进阶(六):HarmonyOS NEXT实现嵌套 H5 及双向通信
文章目录
- 一、前言
- 二、鸿蒙应用加载Web页面
- 2.1 加载网络地址页面
- 2.2 加载本地H5页面
- 三、实现Web组件 H5 层与鸿蒙应用层进行相互通讯
- 3.1 鸿蒙应用向 H5 页面发送数据
- 3.2 H5页面向鸿蒙应用发送数据
- 四、拓展阅读
一、前言
随着HarmonyOS NEXT
的快速发展,越来越多的应用厂商选择加入鸿蒙生态阵营。然而,考虑到存量项目技术架构选型,如何设计一套兼容性更强的应用系统显得尤为重要,尤其针对面对多端应用市场,在前期iOS
、Android
两端应用市场支持基础上再次接入鸿蒙生态,应用开发及维护成本均明显提升。为此,可考虑将应用主体功能部分剥离为H5应用,原生端通过容器嵌套方式接入H5主体应用方式,当涉及主体公共功能发生变更时,仅需维护H5项目即可,无需频繁上架应用市场。鸿蒙生态系统提供了一种原生与H5交互的机制,使得开发者可以在鸿蒙原生应用中嵌入H5页面,实现一次开发,多端运行的目标。
二、鸿蒙应用加载Web页面
2.1 加载网络地址页面
-
在
module.json5
中添加网络权限。"requestPermissions": [ { "name": "ohos.permission.INTERNET" } ]
-
导入
webview
。import web_webview from '@ohos.web.webview'
-
创建
WebviewController
。controller: web_webview.WebviewController = new web_webview.WebviewController();
-
创建
Web
组件。Web({ src: "http://www.example.com/", controller: this.controller })
案例效果:
2.2 加载本地H5页面
- 在项目的
rowfile
中存放html
代码
-
在 Web组件中使用
$rawfile
加载本地html
。Web({ src: $rawfile('webTo.html'), controller: this.controller })
三、实现Web组件 H5 层与鸿蒙应用层进行相互通讯
3.1 鸿蒙应用向 H5 页面发送数据
在创建的WebviewController
中使用 runJavaScript()
方法可直接触发 H5
页面中的方法。
鸿蒙侧示例代码
controller: web_webview.WebviewController= new web_webview.WebviewController();
@State content: string = ""
@state input: string = ""
build(){
Column(){
Column(){
Text("H5层")
Web({ src: $rawfile('webTo.html'),controller: this.controller })
.onConfirm((e:any) => {
console.log("shq1874009 > " + JSON.stringify(e))
this.content = e['message']
return true;
})
}.height("50%").margin({top: 10}).padding(10).border({width:1}).width("100%")
Column(){
Text("应用层")
TextInput({placeholder:"请输入数据"})
.onChange((e) =>{ this.input = e})
Button("向H5层发送数据").onClick(()=>{
this.controller.runJavaScript('sendText("AAA")}).margin(10)
Row().width("100%").height(1).backgroundColor("#ddd").margin(10)
Text("接收H5传递的内容:"+ this.content)
}.height("50%").margin({top: 10}).padding(10).border({width:1}).width("100%")
.......
同样也可以使用模板字符串拼接参数进行传参。
controller: web_webview.WebviewController= new web_webview.WebviewController();
@State content: string = ""
@state input: string = ""
build(){
Column(){
Column(){
Text("H5层")
Web({ src: $rawfile('webTo.html'),controller: this.controller })
.onConfirm((e:any) => {
console.log("shq1874009 > " + JSON.stringify(e))
this.content = e['message']
return true;
})
}.height("50%").margin({top: 10}).padding(10).border({width:1}).width("100%")
Column(){
Text("应用层")
TextInput({placeholder:"请输入数据"})
.onChange((e) =>{ this.input = e})
Button("向H5层发送数据").onClick(()=>{
this.controller.runJavaScript('sendText("${this.input}")}).margin(10)
Row().width("100%").height(1).backgroundColor("#ddd").margin(10)
Text("接收H5传递的内容:"+ this.content)
}.height("50%").margin({top: 10}).padding(10).border({width:1}).width("100%")
.......
H5侧示例代码
<script>
function toOnos() {
let obj = {
name: "张三", age: "20"
}
confirm(JSON.stringify(obj))
}
function sendText(){
document.getElementById("divCon").innerText = "你好"
}
</script>
<div>
<button onclick="to0nos()">给原生应用传递数据</button>
<div id="divCon" style="width: 100px;height: 100px;background: #ddd;margin-top: 20px;"></div>
</div>
案例效果
3.2 H5页面向鸿蒙应用发送数据
在鸿蒙原生代码侧使用 javaScriptProxy
方法向 h5 的 window
对象中注册方法,此处注册的对象名叫 JSBridge
,在该对象中写入了一个 nativeMethod
方法,h5 中直接调用 nativeMethod()
方法即可向原生发送消息。
H5侧
h5侧直接调用 window
对象下的 JSBridge.nativeMethod
方法,第一个参数对应原生侧对应的 channelName
方法名,第二个参数为 h5 自定义参数,可带入回调方法,供原生侧完成调用的回调结果。
示例代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./icsshosdk.js"></script>
<style>
body {
padding-top: 80px;
}
.title {
background: #eee;
line-height: 60px;
text-align: center;
margin-bottom: 50px;
}
.button {
cursor: pointer;
line-height: 45px;
color: #fff;
border-radius: 10px;
left: 20%;
width: calc(100% - 30px);
text-align: center;
background: #616bff;
margin: 15px;
}
.button:active {
background: #525dff;
}
</style>
<script>
document.addEventListener('webActiveReceive', (e) => {
console.log("luvi > " + JSON.stringify(e.detail));
let { key, data } = JSON.parse(e.detail)
switch (key) {
case "changeBgColor":
document.getElementById("idt").style = "background: #ffecea;color: #ff7361"
break;
case "changeBtColor":
document.querySelectorAll(".button").forEach(el => {
el.style = `background: ${data}`
})
break;
default:
break;
}
})
</script>
<script>
function openNativePage() {
let params = {
name: "LoginPage",
success: function (res) {
console.log("luviWeb > openNativePage success. " + res)
},
fail: function () {
console.log("luviWeb > openNativePage fail.")
}
}
window.JSBridge.nativeMethod("openNativePage", params)
}
function getCity() {
let params = {
success: function (res) {
document.getElementById("cityName").innerText = `当前城市:${res}`
},
fail: function () {
console.log("luviWeb > getCity fail.")
}
}
window.JSBridge.nativeMethod("getCity", params)
}
</script>
</head>
<body>
<div style="width: 100%;">
<p class="title" id="idt">JSBridge演示</p>
<div>
<p class="button" onclick="openNativePage()">跳转原生页面</p>
</div>
<div style="margin-top: 30px;">
<p style="margin-left: 15px;" id="cityName">当前城市:</p>
<p class="button" onclick="getCity()">获取当前定位</p>
</div>
</div>
</body>
</html>
鸿蒙侧示例代码如下
import { webview } from '@kit.ArkWeb';
export interface IParamsCallback {
name: string
key: string
success: (data?: string) => void
fail: (data?: string) => void
}
@Entry
@Component
export struct MyWeb {
webController: WebviewController = new webview.WebviewController()
webUrl: string | Resource = "";
build() {
Column() {
Web({ src: this.webUrl, controller: this.webController })
.javaScriptProxy({
object: {
nativeMethod: (channelName: string, paramsCallback: IParamsCallback) => {
if (!channelName || !paramsCallback) {
return
}
switch (channelName) {
case "openNativePage":
paramsCallback.success()
console.log("luvi > h5调用 openNativePage 方法,携带参数" + paramsCallback.name)
break;
case "getCity":
paramsCallback.success()
console.log("luvi > h5调用 getCity 方法,携带参数" + paramsCallback.name)
break;
default:
break;
}
},
},
name: 'JSBridge',
methodList: ['nativeMethod'],
controller: this.webController,
})
.fileAccess(true)
.domStorageAccess(true)
.zoomAccess(false)
.width("100%")
.height("100%")
}
}
}
示例结果如下:
四、拓展阅读
- HarmonyOS webview
- 前端页面调用应用侧函数
- 应用侧调用前端页面函数
- 建立应用侧与前端页面数据通道