前言
在现在容器化技术盛行的大背景下,移动端的很多页面逻辑需要借助于 web 页面来进行实现。那么必不可免的就需要进行原生端和 web 端的数据交互。交互类型有以下两种:
- 原生端发送数据到 web 端;
- web 端发送数据到原生端;
那么,在鸿蒙的平台,我们如何来实现这两种类型的数据交互呢?让我们一起来看下吧!
原生端发送数据到 web 端
假设我们需要一个 web 页面来展示一个类似于美团外卖点餐页面,那么该页面需要原生端将其设备的经纬度传给 web 页面来进行客户的地址定位。示例代码一共包含两部分:原生端的代码和 web 页面的代码。
原生端示例代码如下:
kotlin
import { webview } from '@kit.ArkWeb';
@Entry
@Component
struct Index {
private controller: webview.WebviewController = new webview.WebviewController();
private ports: webview.WebMessagePort[] = [];
private latitude: number = 39.90
private longitude: number = 114.10
build() {
Column() {
Button("发送经纬度到 Web 页面").onClick(() => {
if (this.ports && this.ports[0]) {
this.ports[1].postMessageEvent("经度:" + this.longitude + ";" + "纬度:" + this.latitude);
}
})
Web({ src: $rawfile('index.html'), controller: this.controller })
.onPageEnd(() => {
// 1、创建两个消息端口。
this.ports = this.controller.createWebMessagePorts();
// // 2、在应用侧的消息端口上注册回调事件。
this.ports[1].onMessageEvent((result: webview.WebMessage) => { })
// 3、将另一个消息端口发送到HTML侧,由HTML侧保存并使用。
this.controller.postMessage('__init_port__', [this.ports[0]], '*');
})
}
.height('100%')
.width('100%')
}
}
首先,导入 ArkUI 的 webview
组件用来加载 web 视图。接着创建四个私有变量来存储相应类型的变量。
页面中包含一个 Button
组件用来模拟原生端向 web 发送数据的过程;和 Web
组件用来加载 HTML。
原生端如果发送数据需要以下四步:
- 调用
createWebMessagePorts()
获取两个端口号(一个用来原生给 web 发数据;一个用来 web 给 原生发数据)。 - 调用
onMessageEvent()
进行 web 的数据监听。 - 调用
postMessage()
将函数名和端口数据传递给 web。 - 调用
postMessageEvent()
将数据发送给 web。
HTML 示例代码如下:
xml
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView Message Port Demo</title>
</head>
<body>
<h1>外卖列表</h1>
<p class="output">默认经纬度</p>
</body>
<script>
var h5Port;
var output = document.querySelector('.output');
window.addEventListener('message', function (event) {
if (event.data === '__init_port__') {
if (event.ports[0] !== null) {
// 1. 保存从应用侧发送过来的端口。
h5Port = event.ports[0];
h5Port.onmessage = function (event) {
// 2. 接收ets侧发送过来的消息。
var msg = '客户的经纬度:';
var result = event.data;
if (typeof(result) === 'string') {
msg = msg + result;
}
output.innerHTML = msg;
}
}
}
})
</script>
</html>
web 要想接收到原生端的数据需要以下两步:
- 保存原生端发送过来的端口。
- 通过端口的
onmessage
回调获取到数据并进行展示。
介绍完原生端向 web 端发送数据的流程之后,接下来介绍下如何从 web 端向原生端发送流程。
web 端发送数据到原生端
首先来看下 HTML 中的示例代码:
xml
<!--index.html-->
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView Message Port Demo</title>
</head>
<body>
<h1>外卖列表</h1>
<p class="output">默认经纬度</p>
// 用于模拟发送逻辑
<input type="button" value="SendToEts" onclick="PostMsgToEts('web 消息');"/><br/>
</body>
<script>
var h5Port;
var output = document.querySelector('.output');
window.addEventListener('message', function (event) {
if (event.data === '__init_port__') {
if (event.ports[0] !== null) {
h5Port = event.ports[0];
h5Port.onmessage = function (event) {
var msg = '客户的经纬度:';
var result = event.data;
if (typeof(result) === 'string') {
msg = msg + result;
}
output.innerHTML = msg;
}
}
}
})
// 添加函数通过 h5Port 发送数据
function PostMsgToEts(data) {
if (h5Port) {
h5Port.postMessage(data);
} else {
console.error('h5Port is null, Please initialize first');
}
}
</script>
</html>
web 端的代码需要添加以下两个步骤:
- 添加一个标签用来模拟触发发送数据的逻辑。
- 在 script 标签中添加
PostMsgToEts()
函数用来给原生端发送数据。
原生端的示例代码:
kotlin
import { webview } from '@kit.ArkWeb';
@Entry
@Component
struct Index {
private controller: webview.WebviewController = new webview.WebviewController();
private ports: webview.WebMessagePort[] = [];
private latitude: number = 39.90
private longitude: number = 114.10
@State messageFromWeb: string = "Hello"
build() {
Column() {
// 添加 Text 组件用来显示 web 端发送来的数据
Text(this.messageFromWeb)
Button("发送经纬度到 Web 页面").onClick(() => {
if (this.ports && this.ports[0]) {
this.ports[1].postMessageEvent("经度:" + this.longitude + ";" + "纬度:" + this.latitude);
}
})
Web({ src: $rawfile('index.html'), controller: this.controller })
.onPageEnd(() => {
this.ports = this.controller.createWebMessagePorts();
// 实现回调接口接受数据
this.ports[1].onMessageEvent((result: webview.WebMessage) => {
if (typeof (result) === 'string') {
this.messageFromWeb = result;
}
})
this.controller.postMessage('__init_port__', [this.ports[0]], '*');
})
}
.height('100%')
.width('100%')
}
}
原生端也需要下面的两步:
- 声明组件用来展示 web 传送过来的数据。
- 实现
onMessageEvent
的回调函数接受 web 传递过来的数据。