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 传递过来的数据。
相关推荐
Georgewu4 小时前
【 HarmonyOS 5 入门系列 】鸿蒙HarmonyOS示例项目讲解
harmonyos
libo_20256 小时前
HarmonyOS5 元宇宙3D原子化服务开发实践
harmonyos
半路下车6 小时前
【Harmony OS 5】DevEco Testing重塑教育质量
harmonyos·arkts
90后的晨仔6 小时前
解析鸿蒙 ArkTS 中的 Union 类型与 TypeAliases类型
前端·harmonyos
风浅月明6 小时前
[Harmony]颜色初始化
harmonyos·color
风浅月明6 小时前
[Harmony]网络状态监听
harmonyos·网络状态
半路下车7 小时前
【Harmony OS 5】DevEco Testing在教育领域的应用与实践
harmonyos·产品
simple丶7 小时前
【HarmonyOS Relational Database】鸿蒙关系型数据库
harmonyos·arkts·arkui
哼唧唧_7 小时前
使用 React Native 开发鸿蒙(HarmonyOS)运动健康类应用的系统化准备工作
react native·react.js·harmonyos·harmony os5·运动健康
三掌柜6668 小时前
HarmonyOS开发:显示图片功能详解
华为·harmonyos