HarmonyOS - 实现 ArkTS 和 web 页面的数据交互

前言

在现在容器化技术盛行的大背景下,移动端的很多页面逻辑需要借助于 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 传递过来的数据。
相关推荐
北海zx2 分钟前
HarmonyNext:如何在鸿蒙上录屏后进行音视频编码
harmonyos
别说我什么都不会15 分钟前
【仓颉三方库】音视频开发—— ijkplayer-ffi
harmonyos
王二蛋与他的张大花3 小时前
HarmonyOS运动开发:如何监听用户运动步数数据
harmonyos
别说我什么都不会4 小时前
【仓颉三方库】音视频开发—— mp3tag4cj
harmonyos
半青年5 小时前
鸿蒙系统应用开发全栈指南
华为·华为云·harmonyos
中杯可乐多加冰5 小时前
CloudFront VPC Origins 实践流程深入解析 —— 安全高效架构的实战之道
人工智能·掘金·金石计划
HvrI16 小时前
【Harmony_Bug】forEach + asyncawait 的异步陷阱
开发语言·华为·bug·harmonyos·鸿蒙
鸿蒙开发工程师—阿辉15 小时前
一键多环境构建——用 Hvigor 玩转 HarmonyOS Next
ubuntu·华为·harmonyos
NapleC15 小时前
HarmonyOS NEXT:多设备的自由流转
华为·harmonyos