当前位置: 首页 > article >正文

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: string
  key: string
  success: (data?: string) => void
  fail: (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.kler.cn/a/504572.html

相关文章:

  • 【跟着官网学技术系列之MySQL】第6天之输入查询
  • 改进萤火虫算法之八:量子萤火虫算法(Quantum-behaved Firfly Algorithm,QFA)
  • 开疆智能Profient转DeviceNET主网关连接发那科机器人配置案例
  • excel 整理表格,分割一列变成多列数据
  • Mac远程控制电脑Windows怎么弄?
  • 走出实验室的人形机器人,将复刻ChatGPT之路?
  • centos 7 Samba服务器的配置
  • 【BLE】CC2541之使用自定义128bit的UUID
  • uniapp 绘制五星评分 精确到半星
  • Linux C 使用ZBar库解析二维码和条形码
  • 数据结构——线性表和顺序表
  • 在 Debian 上安装 Docker
  • UML系列之Rational Rose笔记九:组件图
  • intel x99主板设置上电服务器自动启动
  • 机器学习之DBSCAN算法自动分类
  • python识别图片中指定颜色的图案并保存为图片
  • JS-Web API-day02
  • sql报错非法的字符校对Illegal mix of collations
  • Vue2+OpenLayers点聚合功能实现(提供Gitee源码)
  • FPGA 21 ,深入理解 Verilog 中的基数,以及二进制数与十进制数之间的关系( Verilog中的基数 )