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 传递过来的数据。
相关推荐
Lionel68926 分钟前
鸿蒙Flutter跨平台开发:首页特惠推荐模块的实现
华为·harmonyos
盐焗西兰花29 分钟前
鸿蒙学习实战之路-Reader Kit自定义页面背景最佳实践
学习·华为·harmonyos
果粒蹬i32 分钟前
【HarmonyOS】DAY10:React Native开发应用品质升级:响应式布局与用户体验优化实践
华为·harmonyos·ux
早點睡3901 小时前
基础入门 React Native 鸿蒙跨平台开发:react-native-flash-message 消息提示三方库适配
react native·react.js·harmonyos
早點睡3902 小时前
高级进阶 ReactNative for Harmony项目鸿蒙化三方库集成实战:react-native-image-picker(打开手机相册)
react native·react.js·harmonyos
早點睡3902 小时前
基础入门 React Native 鸿蒙跨平台开发:react-native-easy-toast三方库适配
react native·react.js·harmonyos
前端不太难2 小时前
在 HarmonyOS 上,游戏状态该怎么“死而复生”
游戏·状态模式·harmonyos
lbb 小魔仙12 小时前
【HarmonyOS实战】OpenHarmony + RN:自定义 useValidator 表单验证
华为·harmonyos
一起养小猫14 小时前
Flutter for OpenHarmony 实战:扫雷游戏完整开发指南
flutter·harmonyos
小哥Mark16 小时前
Flutter开发鸿蒙年味 + 实用实战应用|绿色烟花:电子烟花 + 手持烟花
flutter·华为·harmonyos