HarmonyOS NEXT开发进阶(六):HarmonyOS NEXT实现嵌套 H5 及双向通信

文章目录

    • 一、前言
    • 二、鸿蒙应用加载Web页面
      • 2.1 加载网络地址页面
      • 2.2 加载本地H5页面
    • 三、实现Web组件 H5 层与鸿蒙应用层进行相互通讯
      • 3.1 鸿蒙应用向 H5 页面发送数据
      • 3.2 H5页面向鸿蒙应用发送数据
    • 四、拓展阅读

一、前言

随着HarmonyOS NEXT的快速发展,越来越多的应用厂商选择加入鸿蒙生态阵营。然而,考虑到存量项目技术架构选型,如何设计一套兼容性更强的应用系统显得尤为重要,尤其针对面对多端应用市场,在前期iOSAndroid两端应用市场支持基础上再次接入鸿蒙生态,应用开发及维护成本均明显提升。为此,可考虑将应用主体功能部分剥离为H5应用,原生端通过容器嵌套方式接入H5主体应用方式,当涉及主体公共功能发生变更时,仅需维护H5项目即可,无需频繁上架应用市场。鸿蒙生态系统提供了一种原生与H5交互的机制,使得开发者可以在鸿蒙原生应用中嵌入H5页面,实现一次开发,多端运行的目标。

二、鸿蒙应用加载Web页面

2.1 加载网络地址页面

  1. module.json5中添加网络权限。

    "requestPermissions": [{"name": "ohos.permission.INTERNET"}
    ]
    
  2. 导入webview

    import web_webview from '@ohos.web.webview'
    
  3. 创建WebviewController

    controller: web_webview.WebviewController = new web_webview.WebviewController();
    
  4. 创建Web组件。

    Web({ src: "http://www.example.com/", controller: this.controller })
    

案例效果:

在这里插入图片描述

2.2 加载本地H5页面

  1. 在项目的 rowfile 中存放 html 代码

在这里插入图片描述

  1. 在 Web组件中使用 $rawfile 加载本地html

    Web({ src: $rawfile('webTo.html'), controller: this.controller })
    

三、实现Web组件 H5 层与鸿蒙应用层进行相互通讯

3.1 鸿蒙应用向 H5 页面发送数据

在创建的WebviewController中使用 runJavaScript() 方法可直接触发 H5 页面中的方法。

鸿蒙侧示例代码

controller: web_webview.WebviewController= new web_webview.WebviewController(); 
@State content: string = ""
@state input: string = ""
build(){ Column(){Column(){Text("H5层")Web({ src: $rawfile('webTo.html'),controller: this.controller }).onConfirm((e:any) => { console.log("shq1874009 > " + JSON.stringify(e))this.content = e['message']return true;})}.height("50%").margin({top: 10}).padding(10).border({width:1}).width("100%") Column(){Text("应用层")TextInput({placeholder:"请输入数据"}).onChange((e) =>{ this.input = e})Button("向H5层发送数据").onClick(()=>{this.controller.runJavaScript('sendText("AAA")}).margin(10)Row().width("100%").height(1).backgroundColor("#ddd").margin(10)Text("接收H5传递的内容:"+ this.content)}.height("50%").margin({top: 10}).padding(10).border({width:1}).width("100%") .......

同样也可以使用模板字符串拼接参数进行传参。

controller: web_webview.WebviewController= new web_webview.WebviewController(); 
@State content: string = ""
@state input: string = ""
build(){ Column(){Column(){Text("H5层")Web({ src: $rawfile('webTo.html'),controller: this.controller }).onConfirm((e:any) => { console.log("shq1874009 > " + JSON.stringify(e))this.content = e['message']return true;})}.height("50%").margin({top: 10}).padding(10).border({width:1}).width("100%") Column(){Text("应用层")TextInput({placeholder:"请输入数据"}).onChange((e) =>{ this.input = e})Button("向H5层发送数据").onClick(()=>{this.controller.runJavaScript('sendText("${this.input}")}).margin(10)Row().width("100%").height(1).backgroundColor("#ddd").margin(10)Text("接收H5传递的内容:"+ this.content)}.height("50%").margin({top: 10}).padding(10).border({width:1}).width("100%") .......

H5侧示例代码

<script>function toOnos() {let obj = {name: "张三", age: "20"}confirm(JSON.stringify(obj))}function sendText(){document.getElementById("divCon").innerText = "你好"}
</script>
<div><button onclick="to0nos()">给原生应用传递数据</button><div id="divCon" style="width: 100px;height: 100px;background: #ddd;margin-top: 20px;"></div>
</div>

案例效果

在这里插入图片描述

3.2 H5页面向鸿蒙应用发送数据

在鸿蒙原生代码侧使用 javaScriptProxy 方法向 h5 的 window 对象中注册方法,此处注册的对象名叫 JSBridge ,在该对象中写入了一个 nativeMethod 方法,h5 中直接调用 nativeMethod() 方法即可向原生发送消息。

H5侧
h5侧直接调用 window 对象下的 JSBridge.nativeMethod 方法,第一个参数对应原生侧对应的 channelName 方法名,第二个参数为 h5 自定义参数,可带入回调方法,供原生侧完成调用的回调结果。

示例代码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="./icsshosdk.js"></script><style>body {padding-top: 80px;}.title {background: #eee;line-height: 60px;text-align: center;margin-bottom: 50px;}.button {cursor: pointer;line-height: 45px;color: #fff;border-radius: 10px;left: 20%;width: calc(100% - 30px);text-align: center;background: #616bff;margin: 15px;}.button:active {background: #525dff;}</style><script>document.addEventListener('webActiveReceive', (e) => {console.log("luvi > " + JSON.stringify(e.detail));let { key, data } = JSON.parse(e.detail)switch (key) {case "changeBgColor":document.getElementById("idt").style = "background: #ffecea;color: #ff7361"break;case "changeBtColor":document.querySelectorAll(".button").forEach(el => {el.style = `background: ${data}`})break;default:break;}})</script><script>function openNativePage() {let params = {name: "LoginPage",success: function (res) {console.log("luviWeb > openNativePage success. " + res)},fail: function () {console.log("luviWeb > openNativePage fail.")}}window.JSBridge.nativeMethod("openNativePage", params)}function getCity() {let params = {success: function (res) {document.getElementById("cityName").innerText = `当前城市:${res}`},fail: function () {console.log("luviWeb > getCity fail.")}}window.JSBridge.nativeMethod("getCity", params)}</script>
</head><body><div style="width: 100%;"><p class="title" id="idt">JSBridge演示</p><div><p class="button" onclick="openNativePage()">跳转原生页面</p></div><div style="margin-top: 30px;"><p style="margin-left: 15px;" id="cityName">当前城市:</p><p class="button" onclick="getCity()">获取当前定位</p></div></div>
</body></html>

鸿蒙侧示例代码如下

import { webview } from '@kit.ArkWeb';export interface IParamsCallback {name: stringkey: stringsuccess: (data?: string) => voidfail: (data?: string) => void
}@Entry
@Component
export struct MyWeb {webController: WebviewController = new webview.WebviewController()webUrl: string | Resource = "";build() {Column() {Web({ src: this.webUrl, controller: this.webController }).javaScriptProxy({object: {nativeMethod: (channelName: string, paramsCallback: IParamsCallback) => {if (!channelName || !paramsCallback) {return}switch (channelName) {case "openNativePage":paramsCallback.success()console.log("luvi > h5调用 openNativePage 方法,携带参数" + paramsCallback.name)break;case "getCity":paramsCallback.success()console.log("luvi > h5调用 getCity 方法,携带参数" + paramsCallback.name)break;default:break;}},},name: 'JSBridge',methodList: ['nativeMethod'],controller: this.webController,}).fileAccess(true).domStorageAccess(true).zoomAccess(false).width("100%").height("100%")}}
}

示例结果如下:

在这里插入图片描述

四、拓展阅读

  • HarmonyOS webview
  • 前端页面调用应用侧函数
  • 应用侧调用前端页面函数
  • 建立应用侧与前端页面数据通道

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OPT: Open Pre-trained Transformer语言模型

摘要 大规模语言模型通常需要数十万计算日的训练时间&#xff0c;展现了在零样本和小样本学习中的显著能力。鉴于其计算成本之高&#xff0c;这些模型在没有大量资本投入的情况下难以复现。对于那些通过API提供的少数模型&#xff0c;研究者无法获取完整的模型权重&#xff0c…

探索图像编辑的无限可能——Adobe Photoshop全解析

文章目录 前言一、PS的历史二、PS的应用场景三、PS的功能及工具用法四、图层的概念五、调整与滤镜六、创建蒙版七、绘制形状与路径八、实战练习结语 前言 在当今数字化的世界里&#xff0c;视觉内容无处不在&#xff0c;而创建和编辑这些内容的能力已经成为许多行业的核心技能…

ffmpeg 编译遇到的坑

makeinfo: error parsing ./doc/t2h.pm: Undefined subroutine &Texinfo::Config::set_from_init_file called at ./doc/t2h.pm line 24. 编译选项添加&#xff1a; --disable-htmlpages

CSS | 实现三列布局(两边边定宽 中间自适应,自适应成比)

目录 示例1 &#xff08;中间自适应 示例2&#xff08;中间自适应 示例3&#xff08;中间自适应 示例4 &#xff08;自适应成比 示例5&#xff08;左中定宽&#xff0c;右边自适应 示例6&#xff08;中间自适应 示例7&#xff08;中间自适应 示例8&#xff08;中间定宽…

《自动驾驶与机器人中的SLAM技术》ch9:自动驾驶车辆的离线地图构建

目录 1 点云建图的流程 2 前端实现 2.1 前端流程 2.2 前端结果 3 后端位姿图优化与异常值剔除 3.1 两阶段优化流程 3.2 优化结果 ① 第一阶段优化结果 ② 第二阶段优化结果 4 回环检测 4.1 回环检测流程 ① 遍历第一阶段优化轨迹中的关键帧。 ② 并发计算候选回环对…

20250112面试鸭特训营第20天

更多特训营笔记详见个人主页【面试鸭特训营】专栏 250112 1. TCP 和 UDP 有什么区别&#xff1f; 特性TCPUDP连接方式面向连接&#xff08;需要建立连接&#xff09;无连接&#xff08;无需建立连接&#xff09;可靠性可靠的&#xff0c;提供确认、重传机制不可靠&#xff0c…

【Rust】错误处理机制

目录 思维导图 引言 一、错误处理的重要性 1.1 软件中的错误普遍存在 1.2 编译时错误处理要求 二、错误的分类 2.1 可恢复错误&#xff08;Recoverable Errors&#xff09; 2.2 不可恢复错误&#xff08;Unrecoverable Errors&#xff09; 三、Rust 的错误处理机制 3…

v-bind操作class

v-bind操作class 参考文献&#xff1a; Vue的快速上手 Vue指令上 Vue指令下 Vue指令的综合案例 指令的修饰符 文章目录 v-bind操作classv-bind对于样式控制的增强操作class案例(tab导航高亮)操作style操作style案例 结语 博客主页: He guolin-CSDN博客 关注我一起学习&#…

算法妙妙屋-------2..回溯的奇妙律动

回溯算法是一种用于系统性地搜索和解决问题的算法&#xff0c;它以深度优先搜索&#xff08;DFS&#xff09;为基础&#xff0c;用来探索所有可能的解决方案。通过递归地尝试候选解并在必要时回退&#xff08;即“回溯”&#xff09;&#xff0c;它能够高效地解决许多涉及组合、…

【微信小程序】5|我的页面 | 我的咖啡店-综合实训

我的页面 引言 本文将详细解析如何实现一个包含登录注册、多个功能模块跳转以及特定功能展示的“我的”页面。我们将使用 Vant Weapp 组件库来简化开发过程&#xff0c;并确保代码的高级性和条理性。 1. 项目结构 首先&#xff0c;确保你的项目结构如下所示&#xff1a; - …

ssh2详细使用步骤,以及常用方法介绍

开源地址&#xff1a;https://github.com/mscdex/ssh2 ssh2 是一个功能强大的 Node.js 库&#xff0c;用于通过 SSH 协议与远程服务器交互。它支持命令执行、文件上传下载、端口转发等操作&#xff0c;常用于自动化脚本和远程服务器管理。 下面是 ssh2 的详细使用步骤和常用方…

计算机网络速成

前言&#xff1a;最近在做一些动态的crypto&#xff0c;但是配置总搞不好&#xff0c;正好也有学web的想法&#xff0c;就先学学web再回去做密码&#xff0c;速成视频推荐b站建模老哥 目录 计算机网络概述网络的范围分级电路交换网络&#xff08;电路交换&#xff09;报文交换网…

基于springboot+vue的 嗨玩-旅游网站

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

八股学习 Redis

八股学习 Redis 使用场景常见问题问题1、2示例场景缓存穿透解决方案一解决方案二 问题3示例场景缓存击穿解决方案 问题4示例场景缓存雪崩解决方案 问题5示例场景双写一致性强一致方案允许延时一致方案 问题6RDB方式AOF方式两种方式对比 问题7示例场景惰性删除定期删除 使用场景…

行业案例:高德服务单元化方案和架构实践

目录 为什么要做单元化 高德单元化的特点 高德单元化实践 服务单元化架构 就近接入实现方案 路由表设计 路由计算 服务端数据驱动的单元化场景 总结 系列阅读 为什么要做单元化 单机房资源瓶颈 随着业务体量和服务用户群体的增长,单机房或同城双机房无法支持服…

GO语言实现KMP算法

前言 本文结合朱战立教授编著的《数据结构—使用c语言&#xff08;第五版&#xff09;》&#xff08;以下简称为《数据结构&#xff08;第五版&#xff09;朱站立》&#xff09;中4.4.2章节内容编写&#xff0c;KMP的相关概念可参考此书4.4.2章节内容。原文中代码是C语言&…

Windows核心编程—匿名管道双向通信

注&#xff1a;父进程要创建两个匿名管道&#xff0c;并且STARTUPINFO 里面的两个字段很重要 A进程 void CMFCApplication1Dlg::OnBnClickedButton1() {SECURITY_ATTRIBUTES sa {};sa.nLength sizeof(SECURITY_ATTRIBUTES);sa.bInheritHandle TRUE;CreatePipe(&m_hRead…

基于springboot+vue的洪涝灾害应急信息管理系统设计与实现

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

centos修改/etc/resolv.conf 重启network后又恢复到原来的状态

博主使用的是centos7 问题描述&#xff1a;centos修改/etc/resolv.conf 执行 service network restart 后&#xff0c;/etc/resolv.conf 又恢复到原来的状态 解决方法&#xff1a;/etc/resolv.conf 保存 DNS 是暂时的&#xff0c;当重新启动 network 时&#xff0c;/etc/resol…

MySQL:索引

目录 1.MySQL索引是干什么的 2.铺垫知识 3.单个page的理解 4.页目录 单页情况 多页情况 1.MySQL索引是干什么的 MySQL的索引是提高查询效率&#xff0c;主要提高海量数据的检索速度。 2.铺垫知识 操作系统与磁盘之间IO的基本单位是4kb。 数据库是一个应用层软件&#…