HarmonyOS Web组件(二)

news2024/9/22 11:27:50

1. HarmonyOS Web组件

官方文档
在这里插入图片描述

1.1. 混合开发的背景和好处

  混合开发(Hybrid Development)是一种结合原生应用和Web应用的开发模式,旨在同时利用两者的优势。随着移动应用需求的多样化和复杂化,单一的开发方式往往难以满足所有需求。混合开发提供了一种灵活、高效的解决方案,特别是在以下方面具有显著的优势:
  (1)跨平台兼容:混合开发允许开发者编写一次代码,并在多个平台(如Android、iOS、HarmonyOS等)上运行。这大大减少了开发和维护成本。
  (2)快速迭代:Web技术(如HTML、CSS、JavaScript)的快速开发和部署能力,使得混合应用可以更快地进行迭代和更新。
  (3)丰富的Web生态:借助丰富的Web生态系统,开发者可以利用大量现有的Web库和框架,快速实现复杂功能。
  (4)原生性能:通过将关键功能部分使用原生代码实现,混合应用可以在保证性能的同时,享受Web开发的灵活性。

1.2.混合开发应用的结构

  为了更好地理解混合开发的概念,以下是一张示意图,展示了混合开发架构中原生代码与Web代码的结合。
在这里插入图片描述
  (图中展示了混合开发应用的结构,其中包括:
  (1)原生层 Native Layer:包括操作系统(如HarmonyOS)、设备硬件和原生API,提供高性能和底层功能支持。
  (2)Web层 Web Layer:包括HTML、CSS、JavaScript等Web技术,负责应用的界面和逻辑部分。
  (3)桥接层 Bridge Layer:连接原生层和Web层,允许两者之间的数据和功能交互。
  通过这种架构,开发者可以在Web层快速构建界面和业务逻辑,同时利用原生层提供的高性能和丰富功能,实现混合开发的最佳效果。
  在HarmonyOS NEXT Developer Beta1版本中,ArkTS 提供了强大的混合开发能力,允许开发者在应用中嵌入 Web 组件,利用 Web 技术构建应用的一部分。接下来,我将介绍如何在 ArkTS 中使用 Web 组件。

1.3. ArkTS Web 组件教程

1.3.1. 语法说明

  在 ArkTS 中,混合开发主要通过 Web 组件和 WebView API 来实现。通过这些工具,可以加载和显示网页内容,进行页面控制和数据交互。
  官方文档

1.3.1.1. 基本语法

  Web 组件用于在界面中嵌入一个网页浏览器。它的常用属性包括:
  src:指定要加载的网页资源地址。
  controller:webview控制器。

src: ResourceStr = 'https://m.jd.com'
Web({ src: this.src, controller: this.controller })

  注意:访问在线网页时需添加网络权限:ohos.permission.INTERNET

1.3.1.2 . 事件处理

  Web 组件支持多种事件,如:
(1)onPageBegin:页面开始加载时触发。
(2)onPageEnd:页面加载完成时触发。
(3)onErrorReceive:页面加载出错时触发。
(4)onTitleReceive:网页document标题更改时触发该回调。
(5)onProgressChange:网页加载进度变化时触发该回调。
(6)onRefreshAccessedHistory:加载网页页面完成时触发该回调,用于应用更新其访问的历史链接。
(7)onAppear:组件挂载显示后触发此回调(通用事件)。

      Web({ src: this.src, controller: this.controller })
          .onProgressChange((data) => {
          })
          .onPageBegin(() => {
          })
          .onPageEnd(() => {
          })
          .onErrorReceive((e) => {
          })
          .onTitleReceive((data) => {
          })
          .onRefreshAccessedHistory(() => {
          })
          .onAppear(() => {
          })

1.3.1.3 . WebView API

  WebView API 提供了一组方法和属性,用于更细粒度地控制 Web 组件,如加载URL、执行JavaScript代码等。

import { webview } from '@kit.ArkWeb'

// 1. 创建 WebView 实例
controller = new webview.WebviewController()
// 2. 调用WebView 实例 api 进行控制
run() {
  // 动态加载页面
  this.controller.loadUrl('url')
  // 注入 js 对象
  this.controller.registerJavaScriptProxy
  // ...
}
Web({ src: this.src, controller: this.controller })

1.3. 实战案例

1.3.1. 新建工程

主要目录结构:

|-- entry
|   |-- src
|   |   |-- main
|   |   |   |-- ets
|   |   |   |   |-- pages
|   |   |   |   |   |-- Index.ets(案例代码)
|-- module.json5

1.3.2. 配置权限

在 module.json5 中配置网络权限:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
     // ...
    "requestPermissions": [
      { "name": "ohos.permission.INTERNET" }
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
        // ...
    ],
    "extensionAbilities": [
       // ...
    ]
  }
}

1.3.3. 加载页面

在 Index.ets 文件中,使用 Web 组件和 WebView API,加载web页面:

@Entry
@Component
struct WebPage {
  // 1. web 组件基本使用
  src: ResourceStr = 'https://m.jd.com'
  
  // webview控制器
  controller = new webview.WebviewController()
  
  build() {
      Navigation() {
        Web({ src: this.src, controller: this.controller })
      }
    .title('混合开发')
    .titleMode(NavigationTitleMode.Mini)

 }
}

1.3.4. 页面标题

获取当前加载网页标题,进行动态展示

  // ...
  @State
  // 当前网页的标题
  title: string = ''
  
  build() {
      Navigation() {
        Web({ src: this.src, controller: this.controller })
       .onTitleReceive((data) => {
            this.title = data?.title || '--'
        })
      }
    .title(this.title)
    .titleMode(NavigationTitleMode.Mini)

 }

1.3.5. 页面进度

获取页面进度数据,添加进度条效果:
(1)第一步:定义状态,存储加载中和进度数据

  // 当前访问页面历史记录索引
  historyCurrIndex: number = 0

(2)第二步:添加事件获取历史记录

// ...
.onRefreshAccessedHistory(() => {
// == 网页加载完成可访问页面历史记录 ==
// 获取当前Webview的页面历史记录列表
const history = this.controller.getBackForwardEntries()
// 当前页面历史记录索引
this.historyCurrIndex = history.currentIndex
// 历史记录索引的数量,最多保存50条,超过时起始记录会被覆盖
console.log('mgx', history.size)
})

(3)第三步:在原生返回钩子函数中控制逻辑

  onBackPress() {
    // 在web容器中, 当前页面之前还有页面, 则容器内返回上一页
    if (this.historyCurrIndex > 0) {
      this.controller.backward()
    } else {
    // 返回原生页面
      router.back()
    }
    // 自定义返回逻辑
    return true
  }

1.3.6. 在页面标题中添加菜单图标,点击刷新页面。

(1)第一步:给Navigation组件右侧添加菜单(图标随便)

build() {
  Navigation() {
    // ...
  }
.title(this.title)
.titleMode(NavigationTitleMode.Mini)
.menus(this.titleMenus)
}

(2)第二步:定义菜单 Builder 绑定事件控制刷新

  @Builder
  titleMenus() {
    Row() {
      Image($r('app.media.startIcon'))
        .width(18)
        .aspectRatio(1)
        .margin({ right: 10 })
        .onClick(() => {
          // 刷新网页
          this.controller.refresh()
        })
    }
    .width(50)
    .height('100%')
    .justifyContent(FlexAlign.End)
    .alignItems(VerticalAlign.Center)
  }

1.3.7. JSBridge代理

  接下来,进入重点环节,我们来学习实操下如何向 Web 容器的网页中注入 JS 对象,给网页提供原生的能力支持,例如: 选择相册、拍照、传感器等底层能力。
  核心依赖webview 提供的registerJavaScriptProxy api,提供了应用与Web组件加载的网页之间强大的交互能力。注入JavaScript对象到window对象中,并在window对象中调用该对象的方法。

官方参考文档
(1)第一步:定义注入 JS 的类型
  示例注入了两个函数:
  test 方法,获取网页调用后传参
  select 方法,选择原生相册,获取选择图片结果显示到网页中

interface InjectJs {
  // 测试方法
  test: (a: string) => void
  // 选择相册
  select: () => Promise<string>
}

type InjectKeys = keyof InjectJs

(2)第二步:定义注入的方法和逻辑

  // 2. JSBridge代理
  webInject() {
    this.controller.registerJavaScriptProxy({
      // 参数 1:注入应用侧JavaScript对象
      // 参数 2:注入对象的名称,与window中调用的对象名一致
      // 参数 3:注入后window对象可以通过此名字访问应用侧JavaScript对象
      test: (a) => {
        AlertDialog.show({
          message: `网页传参:${a}`
        })
      },
      select: async () => {
        // 1. 打开相册选择图片
        const photoSelectOptions = new picker.PhotoSelectOptions()
        photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
        photoSelectOptions.maxSelectNumber = 1;
        const photoPicker = new picker.PhotoViewPicker();
        const res = await photoPicker.select(photoSelectOptions)
        // 2. 文件操作
        // 2.1 获取照片的uri地址
        const uri = res.photoUris[0]
        // 2.2 根据uri同步打开文件
        const file = fs.openSync(uri)
        // 2.3 同步获取文件的详细信息
        const stat = fs.statSync(file.fd)
        // 2.4 创建缓冲区存储读取的文件流
        const buffer = new ArrayBuffer(stat.size)
        // 2.5 开始同步读取文件流到缓冲区
        fs.readSync(file.fd, buffer)
        // 2.6 关闭文件流
        fs.closeSync(file)

        // 3. 转成base64编码的字符串
        const helper = new util.Base64Helper()
        const str = helper.encodeToStringSync(new Uint8Array(buffer))

        return 'data:image/png;base64,' + str
      }

    } as InjectJs,
      'mg',
      [
        'test',
        'select',
      ] as InjectKeys[])
  }

(3)第三步:在通用事件onAppear 执行注入

Web({ src: this.src, controller: this.controller })
// ...
.onAppear(() => {
// JSBridge代理注入
this.webInject()
})

(4)第四步:本地创建网页加载
  这里使用的是原生 js 开发网页端,实际开发中可选择 vue 、 react 、 uni-app 等框架开发,效率更高。
  目录:entry/src/main/resources/rawfile/index.html

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>混合开发</title>
    <style>
    * {
      margin: 0;
      padding: 0;
    }

    ul li {
      padding: 10px;
    }
</style>
</head>

<body>
<div>
    <h1>H5页面</h1>
    <div>
        <p>
            <!--     显示选择相册的图片       -->
            <img id="img"
                 src="">
        </p>
    </div>
    <ul>
        <li>
            <button id="test">调用原生test</button>
        </li>
        <li>
            <button id="sel">调用原生select选择相册</button>
        </li>
    </ul>
</div>
<script>
    window.onload = () => {
      document.querySelector('#test').addEventListener('click', () => {
        mg.test('我是来自web数据啦')
      })

      document.querySelector('#sel').addEventListener('click', async () => {
        const b64 = await mg.select()
        document.querySelector('#img').setAttribute('src', b64)
      })
    }
</script>
</body>

</html>

1.3.8. 执行网页JS

  有时候,我们需要在原生端调用网页中 JS,完成一些业务需求。
(1)第一步:网页中挂载 JS到 window
重新运行项目,点击按钮调用注入的函数测试

<script>
    window.go = () => {
      return '我是网页JS函数'
    }
    window.onload = () => {
      // ...
    }
</script>

(2)原生端调用挂载的 JS
借助 webview 提供runJavaScript api 异步执行JavaScript脚本,并通过回调方式返回脚本执行的结果。

官方参考文档

  // 3. 执行网页 js
  runJs() {
    // this.controller.loadUrl($rawfile('index.html'))
    this.controller.runJavaScript('go()', (error, res) => {
      if (error) {
        return AlertDialog.show({
          message: error.message
        })
      }
      // 获取执行返回值
      AlertDialog.show({
        message: res
      })
    })
  }
  
build() {
  Navigation() {
      Button('执行网页 js')
        .onClick(() => {
          this.runJs()
        })
   // ...
 }
}

1.4. 总结

  本文介绍了在 HarmonyOS NEXT Developer Beta1 版本中,使用 ArkTS 进行混合开发时 Web 组件的基本用法。通过 Web 组件和 WebView API,可以轻松地在应用中嵌入和控制网页内容。以下是几个关键点的总结:
(1)基本语法:通过 Web 组件可以加载和显示网页,处理页面事件,并与网页进行交互。
(2)事件处理:支持多种事件处理,如页面开始加载、加载完成和加载出错、访问历史记录等。
(3)API 使用:WebView API 提供了丰富的方法,用于充当 Bridge 代理,更好和网页端进行通信。
  通过本文的介绍,你应该能够初步掌握在 ArkTS 中使用 Web 组件的基本方法,并应用于实际开发中。混合开发可以让你充分利用 Web 技术的优势,同时享受 ArkTS 的高效开发体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1938752.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

qt 在线安装包下载

1.获取在线安装包直接运行安装即可&#xff0c;需要注册或登录会员 如下是官网地址&#xff0c;可以直接注册下线最新版。 官网&#xff1a;https://www.qt.io/ 官网中文&#xff1a;https://www.qt.io/zh-cn/product/qt-for-application-development 下载界面如下&#xff…

netcat 使用

GPT-4o (OpenAI) Netcat (通常缩写为nc) 是一个功能强大的网络工具&#xff0c;可以方便地读写网络连接。它被广泛用于漏洞测试、网络调试和数据传输。Netcat 可以作为客户端&#xff0c;也可以作为服务器使用。 以下是一些常见的 Netcat 用法&#xff1a;基础用法 连接到服务…

Linux系统之部署扫雷小游戏(三)

Linux系统之部署扫雷小游戏(三) 一、小游戏介绍1.1 小游戏简介1.2 项目预览二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍三、检查本地环境3.1 检查系统版本3.2 检查系统内核版本3.3 检查软件源四、安装Apache24.1 安装Apache2软件4.2 启动apache2服务4.3 查看apache2服…

卷积神经网络学习问题总结

问题一&#xff1a; 深度学习中的损失函数和应用场景 回归任务&#xff1a; 均方误差函数&#xff08;MSE&#xff09;适用于回归任务&#xff0c;如预测房价、预测股票价格等。 import torch.nn as nn loss_fn nn.MSELoss() 分类任务&#xff1a; 交叉熵损失函数&…

【C语言已解决】“Segmentation Fault“

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 在编程过程中&#xff0c;遇到 “Segmentation Fault” 报错可能会让你感到沮丧。这个错误提示通常意味着你的程序尝试访问…

【IEEE出版】第四届能源工程与电力系统国际学术会议(EEPS 2024)

第四届能源工程与电力系统国际学术会议&#xff08;EEPS 2024&#xff09; 2024 4th International Conference on Energy Engineering and Power Systems 重要信息 大会官网&#xff1a;www.iceeps.com 大会时间&#xff1a;2024年8月9-11日 大会…

物联网在养殖业领域的应用——案例分析

作者主页: 知孤云出岫 目录 作者主页:物联网在养殖业领域的应用——案例分析背景技术架构硬件设置连接多种传感器到微控制器 代码实现1. Arduino代码&#xff1a;采集多种传感器数据并上传到Thingspeak2. Python代码&#xff1a;从Thingspeak获取数据并进行综合分析和可视化 …

提升教育质量:智慧校园教师进修助力

在智慧校园整体解决方案中&#xff0c;教职工管理系统的教师进修功能具有重要作用。它不仅是教师专业成长的催化剂&#xff0c;更是学校教育质量飞跃的加速器。通过智慧化、人性化的管理流程&#xff0c;这一功能赋能教师&#xff0c;让他们能够轻松获取多元化的进修机会&#…

搭建环境监测

原文&#xff1a;https://blog.c12th.cn/archives/30.html 环境监测 测试&#xff1a;笔记本原装操作系统&#xff1a;Windows 10 家庭中文版 资源分享链接&#xff1a;提取码&#xff1a;zjv2 卸载SQL步骤&#xff1a; https://blog.csdn.net/qq1623803207/article/details/7…

【Vue3】计算属性

【Vue3】计算属性 背景简介开发环境开发步骤及源码 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日子。本文内…

小白快速入门量化交易的自学路径

今年已然过去一半了&#xff0c;年初立的flag都实现了吗&#xff1f; 据我多年来的观察&#xff0c;很多小白萌新开始学习量化&#xff0c;特别是年初的时候立下“宏图大志”&#xff0c;但有相当一部分最终没能"上岸"&#xff0c;从入门到放弃&#xff0c;从然后到没…

Amesim中界面显示字体设置

对于大屏使用Amesim软件&#xff0c;系统默认的字体可能会很小不方便进行查看使用。在Amesim中我们可以通过设置显示字体的大小来解决此问题。 For large screens, the default font of the system may be small and inconvenient to view. In Amesim we can solve this probl…

24暑假算法刷题 | Day18 | LeetCode 530. 二叉搜索树的最小绝对差,501. 二叉搜索树中的众数,236. 二叉树的最近公共祖先

目录 530. 二叉搜索树的最小绝对差题目描述题解 501. 二叉搜索树中的众数题目描述题解 236. 二叉树的最近公共祖先题目描述题解 530. 二叉搜索树的最小绝对差 点此跳转题目链接 题目描述 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差…

Flink调优详解:案例解析(第42天)

系列文章目录 一、Flink-任务参数配置 二、Flink-SQL调优 三、阿里云Flink调优 文章目录 系列文章目录前言一、Flink-任务参数配置1.1 运行时参数1.2 优化器参数1.3 表参数 二、Flink-SQL调优2.1 mini-batch聚合2.2 两阶段聚合2.3 分桶2.4 filter去重&#xff08;了解&#xf…

Nvidia Isaac Sim代码编程 入门教程 2024(7)

Nvidia Isaac Sim 入门教程 2024 版权信息 Copyright 2023-2024 Herman YeAuromix. All rights reserved.This course and all of its associated content, including but not limited to text, images, videos, and any other materials, are protected by copyright law. …

mac二进制安装operator-sdk

0. 前置条件 1. 安装go 安装步骤略。 1. 下载operator-sdk源码包 https://github.com/operator-framework/operator-sdk 1.1 选择适合当前go版本的operator版本&#xff0c;在operator-sdk/go.mod文件中可以查看Operator-sdk使用的go版本。 2. 编译 源码包下载后&#x…

冒泡,选择,插入,希尔排序

目录 一. 冒泡排序 1. 算法思想 2. 时间复杂度与空间复杂度 3. 代码实现 二. 选择排序 1. 算法思想 2. 时间复杂度与空间复杂度 3. 代码实现 三.插入排序 1. 直接插入排序 (1). 算法思想 (2). 时间复杂度与空间复杂度 (3). 代码实现 2. 希尔排序 (1). 算法思想 …

MongoDB教程(十五):MongoDB原子操作

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、MongoD…

2、如何发行自己的数字代币(truffle智能合约项目实战)

2、如何发行自己的数字代币&#xff08;truffle智能合约项目实战&#xff09; 1-Atom IDE插件安装2-truffle tutorialtoken3-tutorialtoken源码框架分析4-安装openzeppelin代币框架&#xff08;代币发布成功&#xff09; 1-Atom IDE插件安装 正式介绍基于web的智能合约开发 推…

netty 自定义客户端连接池和channelpool

目录标题 客户端池化运行分析问题修复 客户端池化 通信完成之后&#xff0c;一般要关闭channel&#xff0c;释放内存。但是与一个服务器频繁的打开关闭浪费资源。 通过连接池&#xff0c;客户端和服务端之间可以创建多个 TCP 连接&#xff0c;提升消息的收发能力&#xff0c;同…