前端 Web 与原生应用端 WebView 通信交互 - HarmonyOS Next

基于鸿蒙 HarmonyOS Next 与前端 Vue 通信交互相关小结;
DevEco Studio NEXT Developer Preview2
Vue js

两端相互拟定好协议后,通过前端页面的点击事件,将所需的数据传输给原生移动端组件方法中,处理后将消息回传至前端.

根据官方文档的案例尝试,但没成功 ... 后经过几经尝试后两端握手成功 ... (官方文档略显粗糙,好一番折腾)

一.应用端

基于 import web_webview from '@ohos.web.webview' 并初始化 Web 组件;
调用 javaScriptProxy 方法,定义配置协议、参数和方法相关,具体可参考如下 code 片段;
name: 交互协议
object: 定义交互对象
methodList: 交互对象中所涵盖的方法,支持多个,也可以通过一个对象方法再细化多个子方法
controller: 组件

import web_webview from '@ohos.web.webview'@Entry
@Component
export struct HomePage {controller: web_webview.WebviewController = new web_webview.WebviewController()ports: web_webview.WebMessagePort[] = [];nativePort: web_webview.WebMessagePort | null = null;message: web_webview.WebMessageExt = new web_webview.WebMessageExt();// 声明注册对象@State WebCallAppMethod: WebCallAppClass = new WebCallAppClass()aboutToAppear(): void {try {// 启用网页调试功能web_webview.WebviewController.setWebDebuggingAccess(true);} catch (error) {let e: business_error.BusinessError = error as business_error.BusinessError;console.log(`Error Code: ${e.code}, Message: ${e.message}`);this.controller.refresh(); // 页面异常,刷新}}build() {Row() {Column({ space: 20 }) {Web({ src: 'http://192.168.12.108:8080', controller: this.controller }).width('100%').height('100%').backgroundColor(Color.White).multiWindowAccess(true).javaScriptAccess(true).geolocationAccess(true).imageAccess(true).onlineImageAccess(true).domStorageAccess(true).fileAccess(true).mediaPlayGestureAccess(true).mixedMode(MixedMode.All).layoutMode(WebLayoutMode.FIT_CONTENT) // 自适应布局.verticalScrollBarAccess(true).horizontalScrollBarAccess(false).cacheMode(CacheMode.Default).zoomAccess(false)// 禁止手势缩放.onConsole((event) => {console.log('[交互] - onConsole')LogUtils.info(event?.message.getMessage())return false}).onPageBegin(() => { // 页面加载中// this.registerWebJavaScript()}).onPageEnd(() => { // 页面加载完成console.log('[Web] - 页面加载完成')// this.registerWebJavaScript()}).onErrorReceive((event) => { // 异常: 无网络,页面加载错误时if (event) {console.info('getErrorInfo:' + event.error.getErrorInfo());console.info('getErrorCode:' + event.error.getErrorCode());console.info('url:' + event.request.getRequestUrl());console.info('isMainFrame:' + event.request.isMainFrame());console.info('isRedirect:' + event.request.isRedirect());console.info('isRequestGesture:' + event.request.isRequestGesture());console.info('getRequestHeader_headerKey:' + event.request.getRequestHeader().toString());let result = event.request.getRequestHeader();console.info('The request header result size is ' + result.length);for (let i of result) {console.info('The request header key is : ' + i.headerKey + ', value is : ' + i.headerValue);}}}).onHttpErrorReceive((event) => { // 异常: 网页加载资源 Http code >= 400 时if (event) {console.info('url:' + event.request.getRequestUrl());console.info('isMainFrame:' + event.request.isMainFrame());console.info('isRedirect:' + event.request.isRedirect());console.info('isRequestGesture:' + event.request.isRequestGesture());console.info('getResponseData:' + event.response.getResponseData());console.info('getResponseEncoding:' + event.response.getResponseEncoding());console.info('getResponseMimeType:' + event.response.getResponseMimeType());console.info('getResponseCode:' + event.response.getResponseCode());console.info('getReasonMessage:' + event.response.getReasonMessage());let result = event.request.getRequestHeader();console.info('The request header result size is ' + result.length);for (let i of result) {console.info('The request header key is : ' + i.headerKey + ' , value is : ' + i.headerValue);}let resph = event.response.getResponseHeader();console.info('The response header result size is ' + resph.length);for (let i of resph) {console.info('The response header key is : ' + i.headerKey + ' , value is : ' + i.headerValue);}}}).onConfirm((event) => { // 提示框处理相关AlertDialog.show({title: '温馨提示',message: event?.message,confirm: {value: 'onAlert',action: () => {event?.result.handleConfirm()}},cancel: () => {event?.result.handleCancel()}})return true;}).onShowFileSelector((event) => { // 文件上传处理相关console.log('MyFileUploader onShowFileSelector invoked');const documentSelectOptions = new picker.PhotoSelectOptions();let uri: string | null = null;const documentViewPicker = new picker.PhotoViewPicker();documentViewPicker.select(documentSelectOptions).then((documentSelectResult) => {uri = documentSelectResult[0];console.info('documentViewPicker.select to file succeed and uri is:' + uri);if (event) {event.result.handleFileList([uri]);}}).catch((err: BusinessError) => {console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`);})return true;}).javaScriptProxy({ // web call app// 对象注入 webobject: this.WebCallAppMethod,name: 'WebCallApp', // AppCallWeb WebCallAppSsss  WebCallAppmethodList: ['WebCallApp', 'CmdTest', 'CmdOpenUrl'],controller: this.controller})}.width('100%').height('100%')}}
}interface CommandModel { // 泛型: 交互sn: string,args: Object,command: string,
}class WebCallAppClass {constructor() {}WebCallApp(value: string): string { // 采用该 Json 对象模式,通过解析对象中的 type 后细化对应不同的子方法console.log('[交互] --- WebCallApp - 测试')console.log(value)let params:CommandModel = JSON.parse(value)console.info(params.sn)console.info(params.command)console.info(JSON.stringify(params.args))return '[交互] --- WebCallApp - 测试 - 回调123123123'}CmdOpenUrl(): Object {console.log('[交互] --- WebCallApp - CmdOpenUrl');new Object({'command': '111',})return Object;}CmdTest(value: string): string {console.log('[交互] --- WebCallApp - test');console.log(value);return '[交互] --- WebCallApp - test';}
}

二.前端

前端配置有两种方式,可以通过 index.html 配置 js 后调用,也可以单独另起一个 js 类方法去适配,具体可参考如下 code 按需尝试;

方式一.通过 index.html

在项目根目录的 index.html 文件中添加如下 script 段落后,在业务所需的地方调用即可

// index.html
<script>// eruda.init()(function () {if (!window.applicationCache && typeof(Worker)=='undefined') {alert("E001-检测到您的环境不支持HTML5,程序终止运行!");//不支持HTML5return;}var global = window; // create a pointer to the window rootif (typeof WebCallAppSsss === 'undefined') {global.WebCallApp = { // 此处的 WebCallApp 与原生端 javaScriptProxy 中的 name 相互匹配// 如下方法对应的是 javaScriptProxy 中 object 对象中的方法WebCallApp: (arg) => {},CmdOpenUrl: (arg) => {},CmdTest: (arg) => {},}; // create elf root if not existed}window.WebCallAppSsss.global = global; // add a pointer to window})();
</script>
// 业务所需的点击事件方法中调用
methods : {onClickGoBack() {let str = WebCallAppSsss.CmdTest('[交互] - 测试'); // 方式一// this.webApp.WebCallApp('CmdTest', '111111'); // 方式二Toast.success('abc');},
}

方式二.通过自定义 js

自定义 webCallApp 类,通过引入类方法调用

// WebCallApp.js
import {AppCallBacks,AppCommendBackHandlers,
} from './AppMsgHandlers'export default {WebCallApp(command,args,callback,context) {/*** 交互** 协议:command* 入参:args* 回调:callback* 参数:context* */if (typeof Elf.AppCallWeb != "undefined") {if (this.isInHarmonyOS()) { // 鸿蒙 HarmonyOS Nextconsole.log('[OpenHarmony] - ' + command);let sn = null;let params = {args: args || {}, // 入参command: command, // 交互协议sn: this.getSerialNumber()};console.log('[鸿蒙] - 入参');console.log(params);// if (typeof WebCallApp === 'undefined') { // 移至 AppMsgHandlers 中//   Elf.WebCallApp = {//     WebCallApp: (args) => {}//   };// }// window.WebCallApp.Elf = Elf;let Str = WebCallApp['WebCallApp'](JSON.stringify(params));console.log(Str);} else { // Android & iOScontext = context || window;//默认为window对象args = args || {};let  sn = null;//IOS调用相机--sn特殊处理if (command == "callCamera") {sn = "examCamera";} else {sn = this.getSerialNumber();//请求App统一加水单号}let params = {args: args,command: command};//绑定回调函数if (callback) {AppCallBacks[sn] = {callback: callback,context: context};}if (window.webkit && window.webkit.messageHandlers) {//IOSparams.sn = sn;window.webkit.messageHandlers["WebCallApp"].postMessage(JSON.stringify(params));} else if (Elf.WebCallApp) {//Androidparams.sn = sn;Elf.WebCallApp(JSON.stringify(params));} else {}}}},isInApp() {if (typeof Elf.AppCallWeb != "undefined") {return !!((window.webkit && window.webkit.messageHandlers) || typeof Elf.WebCallApp == "function" || typeof Elf.WebCallCef == "function");}},isInIOS() {return window.webkit && window.webkit.messageHandlers;},isInAndroid() {if (typeof Elf.AppCallWeb != "undefined") {return typeof Elf.WebCallApp == "function";}},isInHarmonyOS() {if (navigator.userAgent.toLowerCase().indexOf('openharmony') !== -1) {return true;} else {return false;}},getSerialNumber() {var uuid = this.UUID(3,8);return new Date().format("yyyyMMddhhmmssS") + uuid;},UUID(len,radix) {var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');var uuid = [],i;radix = radix || chars.length;if (len) {for (i = 0; i < len; i++) {uuid[i] = chars[0 | Math.random() * radix];}} else {var r;uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';uuid[14] = '4';for (i = 0; i < 36; i++) {if (!uuid[i]) {r = 0 | Math.random() * 16;uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];}}}return uuid.join('');},
}
/* eslint-disable */
// AppMsgHandlers
import webApp from './index';/*** app对接* 移动端种植Elf对象* window => Elf* */
(function () {if (!window.applicationCache&&typeof(Worker)=='undefined') {alert("E001-检测到您的环境不支持HTML5,程序终止运行!");//不支持HTML5return;}// iOS & Androidvar global = window;//create a pointer to the window rootif (typeof Elf === 'undefined') {global.Elf = {};//create elf root if not existed}Elf.global = global;//add a pointer to window// Harmonyif (typeof WebCallApp === 'undefined') { // var global = window; global.WebCallApp = {WebCallApp: (args) => {}};}//global.WebCallApp.Elf = Elf;WebCallApp.global = global;  
})();var AppCallBacks = {},//动态数据流水列表AppCommendBackHandlers = [],//APP后退监听事件列表APPCommendBookStateHandlers = [],//下载状态监听事件列表AppCommendRefreshHandlers = [],//刷新监听事件列表APPCommendAddToBookShelfHandlers = [],//添加到书架监听事件列表APPCommendAddToObtainedBookHandlers = [],//添加到已获得图书列表监听APPCommendReBackHandlers = [],//监听重新回到页面通知AppCommendNetworkHandlers = [],//监听网络链接状态AppCommendAppStartingHandlers = [],//监听APP进入后台运行AppCommendAppReactivateHandlers = [],//监听APP重新进入前台运行AppCommendScreenShotss = [],//监听手机截屏AppCommendKeyboardBounceUp = [];//监听移动端软键盘事件if (typeof Elf != "undefined") {Elf.AppCallWeb = (sn,result) => {if (result && typeof result == "string") {result = decodeURIComponent(result.replace(/\+/g,'%20'));try {result = JSON.parse(result);//解决空格变成+的问题} catch (error) {AppCallBacks[sn].callback.call(AppCallBacks[sn].context,result);return;}if (result.sn) {AppCallBacks[sn].callback.call(AppCallBacks[sn].context,result.QrCode);return;}}if (AppCallBacks[sn]) {if (JSON.parse(result.opFlag)) {//执行对应回调AppCallBacks[sn].callback.call(AppCallBacks[sn].context,(typeof result.serviceResult == "string") ? JSON.parse(result.serviceResult) : result.serviceResult);} else {//接口调用返回失败信息,统一处理错误消息Toast(result.errorMessage ? result.errorMessage : "服务器异常!");}//调用完成删除对象delete AppCallBacks[sn];} else if (AppMsgHandlers[sn] && typeof AppMsgHandlers[sn] == "function") {//处理消息通知AppMsgHandlers[sn].call(window,result);}};
}
// if (typeof WebCallApp === 'undefined') { // var global = window;
//   Elf.WebCallApp = {
//     WebCallApp: (args) => {}
//   };
// }
// window.WebCallApp.Elf = Elf;export {AppCallBacks,AppCommendBackHandlers
}

业务方法调用

// 业务所需的点击事件方法中调用
methods : {onClickGoBack() {// let str = WebCallAppSsss.CmdTest('[交互] - 测试'); // 方式一this.webApp.WebCallApp('CmdTest', '111111'); // 方式二Toast.success('abc');},
}

以上便是此次分享的全部内容,希望能对大家有所帮助!

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

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

相关文章

随笔——预处理详解

目录 前言预定义符号#define#define定义常量#define定义宏 带有副作用的宏参数宏替换的规则宏和函数的对比#和###运算符##运算符 命名约定#undef命令行定义条件编译头文件的包含包含方式嵌套包含 其他预处理指令完 前言 之前我们在《随笔——编译与链接》中对预处理作了大致的…

【ARM Cache 及 MMU 系列文章 6 -- Cache 寄存器 CTR_EL0 | CLIDR | CCSIDR | CSSELR 使用详解 1】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 Cache 常用寄存器Cache CSSELR 寄存器Cache CSSELR 使用场景Cache CSSELR 操作示例 Cache CLIDR 寄存器LoUU 介绍LoUU 使用 LoUIS 介绍CLIDR 使用 Cache CCSIDR 寄存器Cache CTR_EL0 C…

中科数安 |-公司办公透明加密系统,数据防泄漏软件

#数据防泄漏软件# 中科数安是一家专注于提供企业级数据防泄漏解决方案的公司&#xff0c;其办公透明加密系统是专为保护企业内部核心数据资料设计的。 PC地址&#xff1a;——www.weaem.com 该系统通过以下主要功能模块实现高效的安全防护&#xff1a; 文档透明加密&#xff1…

滴滴出行 大数据研发实习生【继任】

大数据研发实习生JD 职位描述 1、负责滴滴核心业务的数据建设&#xff0c;设计并打造适应滴滴一站式出行平台业务特点的数仓体系。 2、负责抽象核心业务流程&#xff0c;沉淀业务通用分析框架&#xff0c;开发数仓中间层和数据应用产品。 3、负责不断完善数据治理体系&#xff…

【数据结构】栈的应用

目录 0 引言 1 栈在括号匹配中的应用 2 栈在表达式求值中的应用 2.1 算数表达式 2.2 中缀表达式转后缀表达式 2.3 后缀表达式求值 3 栈在递归中的应用 3.1 栈在函数调用中的作用 3.2 栈在函数调用中的工作原理 4 总结 0 引言 栈&#xff08;Stack&#xff09;是一…

WPF视频学习-基础知识篇

1.简介WPF&#xff1a; C# 一套关于windows界面应用开发框架 2.WPF和winform的差别 &#xff0c;(WPF比较新) 创建新项目使用模板&#xff1a; WPF使用.xaml后缀&#xff0c;双击可查看操作界面和设置代码&#xff0c;其文件展开之后中有MainWindow.xaml.cs为程序交互逻辑。…

linux笔记8--安装软件

文章目录 1. PMS和软件安装的介绍2. 安装、更新、卸载安装更新ubuntu20.04更新镜像源&#xff1a; 卸载 3. 其他发行版4. 安装第三方软件5. 推荐 1. PMS和软件安装的介绍 PMS(package management system的简称)&#xff1a;包管理系统 作用&#xff1a;方便用户进行软件安装(也…

nginx mirror流量镜像详细介绍以及实战示例

nginx mirror流量镜像详细介绍以及实战示例 1.nginx mirror作用2.nginx安装3.修改配置3.1.nginx.conf3.2.conf.d目录下添加default.conf配置文件3.3.nginx配置注意事项3.3.nginx重启 4.测试 1.nginx mirror作用 为了便于排查问题&#xff0c;可能希望线上的请求能够同步到测试…

PyCharm QThread 设置断点不起作用

背景&#xff1a; 端午节回来上班第一天&#xff0c;不想干活&#xff0c;领导又再后面看着&#xff0c;突然想起一个有意思的问题&#xff0c;为啥我的程序在子进程QThread的子类里打的断点不好用呢&#xff1f;那就解决一下这个问题吧。 原因&#xff1a; 如果您的解释器上…

开发框架表单设计器办公效率高吗?

对于很多职场人来说&#xff0c;拥有一款可以提质、增效、降本的办公利器是大有裨益的。随着科技的进步和发展&#xff0c;低代码技术平台凭借可视化界面、易操作、好维护、高效率等多个优势特点&#xff0c;成为大众喜爱的办公利器。开发框架表单设计器是减少信息孤岛&#xf…

macbook本地部署 pyhive环境连接 hive用例

前言 公司的测试和生产环境中尚未提供基于Hive的客户端。若希望尝试操作Hive表&#xff0c;目前一个可行的方案是使用Python语言&#xff0c;通过借助pyhive库&#xff0c;您可以对Hive表进行各种操作。以下是一些示例记录供您参考。 一、pyhive是什么&#xff1f; PyHive是一…

从零到一建设数据中台(番外篇)- 数据中台UI欣赏

番外篇 - 数据中台 UI 欣赏 话不多说&#xff0c;直接上图。 数据目录的重要性&#xff1a; 数据目录是一种关键的信息管理工具&#xff0c;它为组织提供了一个全面的、集中化的数据资产视图。 它不仅记录了数据的存储位置&#xff0c;还详细描述了数据的结构、内容、来源、使…

细说ARM MCU的串口接收数据的实现过程

目录 一、硬件及工程 1、硬件 2、软件目的 3、创建.ioc工程 二、 代码修改 1、串口初始化函数MX_USART2_UART_Init() &#xff08;1&#xff09;MX_USART2_UART_Init()串口参数初始化函数 &#xff08;2&#xff09;HAL_UART_MspInit()串口功能模块初始化函数 2、串口…

批量申请SSL证书如何做到既方便成本又最低

假如您手头拥有1千个域名&#xff0c;并且打算为每一个域名搭建网站&#xff0c;那么在当前的网络环境下&#xff0c;您必须确保这些网站通过https的方式提供服务。这意味着&#xff0c;您将为每一个域名申请SSL证书&#xff0c;以确保网站数据传输的安全性和可信度。那么&…

面试-NLP八股文

机器学习 交叉熵损失&#xff1a; L − ( y l o g ( y ^ ) ( 1 − y ) l o g ( 1 − ( y ^ ) ) L-(ylog(\hat{y}) (1-y)log(1-(\hat{y})) L−(ylog(y^​)(1−y)log(1−(y^​))均方误差&#xff1a; L 1 n ∑ i 1 n ( y i − y ^ i ) 2 L \frac{1}{n}\sum\limits_{i1}^{n}…

【ai】openai-quickstart 配置pycharm工程

之前都是本地执行脚本【AI】指定python3.10安装Jupyter Lab环境为:C:\Users\zhangbin\AppData\Local\Programs\Python\Python310 参考之前创建的python工程 使用的是局部的私有的虚拟环境 pycharm给出的解释器 直接使用现有的,不new了 可以选择3.10 :可以选虚拟的:

Rust-02-变量与可变性

在Rust中&#xff0c;变量和可变性是两个重要的概念。 变量&#xff1a;变量是用于存储数据的标识符。在Rust中&#xff0c;变量需要声明其类型&#xff0c;例如&#xff1a; let x: i32 5; // 声明一个名为x的变量&#xff0c;类型为i32&#xff08;整数&#xff09;&#…

SpringCloud 前端-网关-微服务-微服务间实现信息共享传递

目录 1 网关获取用户校验信息并保存至请求头&#xff08;前端-网关&#xff09; 2 微服务获取网关中的用户校验信息&#xff08;网关-微服务&#xff09; 2.1 一般的做法是在公共的module中添加&#xff0c;此处示例为common 公共配置module中添加 2.2 定义拦截器 2.3 定义…

简单通用的系统安装、备份、还原方法,支持 ARM 系统【Ventory+FirePE+DiskGenius】

文章目录 0. 简介1. 制作 Ventory 启动盘1.1. 下载 Ventory1.2. 制作 Ventory 启动盘 2. 添加 FirePE 等系统镜像到启动盘2.1. 下载 FirePE2.2. 导出 .iso 系统镜像文件2.3. .iso 系统镜像文件添加至启动盘 3. 启动 FirePE 等系统镜像3.1. 在 bios 中选择启动盘启动3.2. 启动系…

# RocketMQ 实战:模拟电商网站场景综合案例(八)

RocketMQ 实战&#xff1a;模拟电商网站场景综合案例&#xff08;八&#xff09; 一、RocketMQ 实战&#xff1a;模拟电商网站场景综合案例–下单异常问题演示 1.png 1、如果订单在扣减库存、扣减优惠券、扣减余额后&#xff0c;在 未 确认订单 前&#xff0c;出现了异常&am…