前端 JavaScript 与鸿蒙 Web 组件间相互通信的方式;
注:此案例采用两端间双向模式机制进行通信;
单向模式可参考 前端 Web 与原生应用端 WebView 通信交互
官方文档传送门如下:
WebCallApp
AppCallWeb
一.鸿蒙端
1.设置 WebCallApp 方法
import WebView from '@ohos.web.webview';
import business_error from '@ohos.base'
import { BusinessError } from '@kit.BasicServicesKit';
// 声明注册对象
@State WebCallAppMethod: WebCallAppClass = new WebCallAppClass(this.controller)
// WebCallApp 类方法
class WebCallAppClass {
private webView: WebView.WebviewController;
constructor(webView: WebviewController) {
this.webView = webView
}
// 方式一: 方法无回调,通过交互协议 WebCallApp => AppCallWeb
WebCallApp(value: string) {
console.log('********* [交互] --- 协议 - HWebView')
// 接收 Web 端数据源
console.log(value)
// 交互数据处理
do something ...
// 如果需要数据回调,则通过如下 callback 方法将处理后的数据回调至 Web
// 如果不需要数据回调,则执行其它业务逻辑即可,无需调用如下 callback 方法
this.webView.runJavaScript(value)
}
// 方式二: 方法回调,WebCallApp 直接 return
// WebCallApp(value: string): string { // 直接 return 方式
// console.log('[交互] --- WebCallApp - 测试 - HWebView')
// // 接收 Web 端数据源
// console.log(value)
//
// // 交互数据处理
// do something ...
//
// // callback
// return value
// }
WebTestAsync = async (value: string): Promise<string> => { // 测试 - 异步
let userInfo: UserInfoModal = JSON.parse(userInfoData)
userInfo.instituteId = instituteId
userInfo.genderCode = genderCode
let commandManager = CommandManager.shareInstance()
let res = await commandManager.webCallAppCommandWithScriptMessage(value, userInfo, this.webView)
let argsJson = JSON.stringify(res.args)
console.log('[WebTestAsync]')
console.log(argsJson)
return argsJson
}
WebTest(value: string): Promise<string> { // 测试 - promise
let p: Promise<string> = new Promise((resolve, reject) => {
let userInfo: UserInfoModal = JSON.parse(userInfoData)
userInfo.instituteId = instituteId
userInfo.genderCode = genderCode
let commandManager = CommandManager.shareInstance()
let res = commandManager.webCallAppCommandWithScriptMessage(value, userInfo, this.webView)
let argsJson = JSON.stringify(res.args)
resolve('[Callback]:' + argsJson)
})
return p
}
}
2.基于 @ohos.web.webview 初始化并配置
官方文档传送门
通过 javaScriptProxy 的代理方法与前端通信接发消息;
1).name 两端交互的协议 key
2).object 对应的是 WebCallApp 的交互接收方法
3).methodList 基于 object 的 WebCallApp 中交互具体实现的若干函数方法
4).controller 组件
Web({ src: this.url, controller: this.controller })
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.multiWindowAccess(true)
.javaScriptAccess(true)// 访问本地资源文件
.imageAccess(true)// 权限状态开启
.onlineImageAccess(true)// 权限状态开启
.fileAccess(true)// 权限状态开启
.domStorageAccess(true)// 数据存储权限
.mediaPlayGestureAccess(true)// 媒体权限
.mixedMode(MixedMode.All)// https 加载
.layoutMode(WebLayoutMode.FIT_CONTENT)// 自适应布局
.verticalScrollBarAccess(true)// 滚动条
.horizontalScrollBarAccess(false)// 滚动条
.cacheMode(CacheMode.Default)// 缓存
.zoomAccess(false)// 禁止手势缩放
.geolocationAccess(true)// 定位权限
.onConsole((event) => {
console.log('[交互] - onConsole')
LogUtils.info(event?.message.getMessage())
return false
})
.onPageBegin(() => { // 页面加载中
console.log('[Web] - 页面加载中:', this.url)
})
.onPageEnd(() => {
console.log('[Web] - 页面加载完成:', this.url)
this.isLoading = false
})
.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);
}
}
})
.onAlert((event) => { // 提示框处理相关
AlertDialog.show({
title: '温馨提示',
message: event?.message,
confirm: {
value: '确认',
action: () => {
event?.result.handleConfirm()
}
},
cancel: () => {
event?.result.handleCancel()
}
})
return true;
})
.onConfirm((event) => { // 提示框处理相关
AlertDialog.show({
title: '温馨提示',
message: event?.message,
confirm: {
value: '确认',
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
})
.onLoadIntercept((event) => {
if (event.data.isRedirect()) {
console.log('[重定向]');
}
return false
})
.javaScriptProxy({
// web call app, web 组件初始化调用
// 对象注入 web
object: this.WebCallAppMethod,
name: 'WebCallAppHarmony', // AppCallWeb
methodList: ['WebCallApp', 'WebTest', 'WebTestSync', 'WebTestAsync'],
controller: this.controller
})
3.完整案例
import HeaderComponent from "../../components/NavigationBar"
import WebView from '@ohos.web.webview';
import business_error from '@ohos.base'
import { BusinessError } from '@kit.BasicServicesKit';
import CommandManager from '../../expand/utility/CommandManager'
import AppCallWeb, { DataType } from '../../expand/utility/AppCallWeb'
// 路由取值
const routerParams = router.getParams() as RouterModel
// 用户信息相关
let userID: string = ''
let token: string = ''
let instituteId: string = ''
let cellphone: string = ''
let userInfoData: string = ''
@Entry
@Component
struct HWebView {
controller: WebView.WebviewController = new WebView.WebviewController();
// setCookies
headers: Array<WebView.WebHeader> = [{ headerKey: 'author', headerValue: 'survivors' }];
// 页面 loading
isLoading: boolean = true
// 声明注册对象
@State WebCallAppMethod: WebCallAppClass = new WebCallAppClass(this.controller)
// 标题
@State title: string = ''
// 导航栏是否显示(默认显示 true)
@State navHidden: boolean = true
// 链接
@State url: string = 'https://blog.csdn.net/survivorsfyh'
aboutToAppear(): void { // 页面即将渲染
console.log('[WebView] - 页面即将渲染');
// 路由取值
console.log(JSON.stringify(routerParams))
const title = routerParams.title
const navHidden = routerParams.navHidden
const link = routerParams.link
this.title = title ? title : ''
this.navHidden = navHidden ? navHidden : false
this.url = link ? link : ''
this.webDebugMethod()
}
aboutToDisappear(): void { // 页面即将销毁
console.log('[WebView] - 页面即将销毁');
}
onBackPress(): boolean | void { // Web 组件左滑手势返回处理
if (this.controller.accessStep(-1)) {
// 返回上一层级
this.controller.backward()
// 执行自定义逻辑
return true
} else { // 执行系统默认返回逻辑
return false
}
}
onPageShow(): void { // 页面进入前台
console.log('[页面进入前台]');
// get
let value = WebView.WebCookieManager.fetchCookieSync(this.url);
console.log('[cookie]: ' + value);
// set
WebView.WebCookieManager.configCookieSync('url', 'a=1,b=2,c=3');
}
onPageHide(): void { // 页面进入后台
console.log('[页面进入后台]');
}
/****** 初始化 init 配置相关 ******/
async initUserInfo() {
console.log('[初始化] - 获取用户信息')
userID = await StorageUtils.get('userID') as string
token = await StorageUtils.get('token') as string
instituteId = await StorageUtils.get('instituteId') as string
cellphone = await StorageUtils.get('cellphone') as string
userInfoData = await StorageUtils.get('UserInfoData') as string
}
webDebugMethod(): void {
try {
// 启用网页调试功能
WebView.WebviewController.setWebDebuggingAccess(true);
} catch (error) {
let e: business_error.BusinessError = error as business_error.BusinessError;
console.log(`[Web] ****** Error Code: ${e.code}, Message: ${e.message}`);
// this.controller.refresh(); // 页面异常,刷新
}
}
// 白屏情况可能是权限导致,把权限全部开启,例如本地存储或者 http & https
build() {
Column() {
if (this.navHidden === true) {
HeaderComponent({ title: this.title })
}
if (this.isLoading && !this.url) {
HProgressHUD({ hudContent: '加载中~~~' })
}
if (this.url) {
Web({ src: this.url, controller: this.controller })
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.multiWindowAccess(true)
.javaScriptAccess(true)// 访问本地资源文件
.imageAccess(true)// 权限状态开启
.onlineImageAccess(true)// 权限状态开启
.fileAccess(true)// 权限状态开启
.domStorageAccess(true)// 数据存储权限
.mediaPlayGestureAccess(true)// 媒体权限
.mixedMode(MixedMode.All)// https 加载
.layoutMode(WebLayoutMode.FIT_CONTENT)// 自适应布局
.verticalScrollBarAccess(true)// 滚动条
.horizontalScrollBarAccess(false)// 滚动条
.cacheMode(CacheMode.Default)// 缓存
.zoomAccess(false)// 禁止手势缩放
.geolocationAccess(true)// 定位权限
.onConsole((event) => {
console.log('[交互] - onConsole')
LogUtils.info(event?.message.getMessage())
return false
})
.onPageBegin(() => { // 页面加载中
console.log('[Web] - 页面加载中:', this.url)
})
.onPageEnd(() => {
console.log('[Web] - 页面加载完成:', this.url)
this.isLoading = false
})
.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);
}
}
})
.onAlert((event) => { // 提示框处理相关
AlertDialog.show({
title: '温馨提示',
message: event?.message,
confirm: {
value: '确认',
action: () => {
event?.result.handleConfirm()
}
},
cancel: () => {
event?.result.handleCancel()
}
})
return true;
})
.onConfirm((event) => { // 提示框处理相关
AlertDialog.show({
title: '温馨提示',
message: event?.message,
confirm: {
value: '确认',
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
})
.onLoadIntercept((event) => {
if (event.data.isRedirect()) {
console.log('[重定向]');
}
return false
})
.javaScriptProxy({
// web call app, web 组件初始化调用
// 对象注入 web
object: this.WebCallAppMethod,
name: 'WebCallAppHarmony', // AppCallWeb WebCallAppSsss WebCallApp
methodList: ['WebCallApp', 'WebTest', 'WebTestSync', 'WebTestAsync'],
controller: this.controller
})
} else { // 加载异常,请重试
}
}.width('100%').height('100%')
}
}
/**************************** Web JS Bridge ****************************/
class WebCallAppClass {
private webView: WebView.WebviewController;
constructor(webView: WebviewController) {
this.webView = webView
}
// 方式一: 方法无回调,通过交互协议 WebCallApp => AppCallWeb
WebCallApp(value: string) {
console.log('********* [交互] --- 协议 - HWebView')
console.log(value)
// 解析交互协议
let params: CommandModel = JSON.parse(value)
let sn = params.sn
let command = params.command
let args: object = params.args
console.info('********* ', command)
console.info(sn)
console.info(command)
console.info(JSON.stringify(args))
console.log('********* [交互] - 协议 *********')
// 用户信息中添加机构
let userInfo: UserInfoModal = JSON.parse(userInfoData)
userInfo.instituteId = instituteId
userInfo.genderCode = genderCode
console.log('********* [用户信息]')
console.log(JSON.stringify(userInfo))
// 交互处理
let commandManager = CommandManager.shareInstance()
let res = commandManager.webCallAppCommandWithScriptMessage(value, userInfo, this.webView)
let jsType = res.type
let jsonRes = JSON.stringify(res)
let resData: CommandModel = JSON.parse(jsonRes)
let argsJson = JSON.stringify(res.args)
console.log('[交互回调]:', argsJson)
// App call web 数据格式处理
let appCallWeb = AppCallWeb.shareInstance()
let callbacks = appCallWeb.callbackWithServiceResultSelect(DataType.DataTypeNormal, sn, res, null)
if (jsType == 'Json') {
callbacks = appCallWeb.callbackWithServiceResultSelect(DataType.DataTypeJson, sn, res, null)
} else if (jsType == 'Encode') {
callbacks = appCallWeb.callbackWithServiceResultSelect(DataType.DataTypeJsonEncoded, sn, res, null)
} else if (jsType == 'Basic') {
callbacks = appCallWeb.callbackBasic(sn, res, null)
}
console.log('********* [callbacks]')
console.log(callbacks)
console.log('************')
this.webView.runJavaScript(`Elf.AppCallWeb(${sn}, ${callbacks})`)
}
// 方式二: 方法回调,WebCallApp 直接 return
// WebCallApp(value: string): string { // 直接 return 方式,New_20240703
// console.log('[交互] --- WebCallApp - 测试 - HWebView')
// console.log(value)
//
// let params: CommandModel = JSON.parse(value)
// let command = params.command
// let args: object = params.args
// if (command === 'CmdOpenUrl') {
// let navigation: string = args['navigation']
// let name: string = args['name'] ? args['name'] : ''
// let staticState: string = args['static']
// let url: string = args['url']
// try {
// router.pushUrl({
// url: 'pages/component/HWebView',
// params: {
// title: name,
// navHidden: navigation === '1' ? true : false,
// link: url
// }
// })
// } catch (err) {
// console.error('[Router] - failed, code is ${(err as BusinessError).code}, message is ${(err as BusinessError).message}')
// }
// return ''
// } else {
// // 解析交互协议
// let params: CommandModel = JSON.parse(value)
// let sn = params.sn
// let command = params.command
// let args: object = params.args
// console.info(sn)
// console.info(command)
// console.info(JSON.stringify(args))
// // 用户信息中添加机构
// let userInfo: UserInfoModal = JSON.parse(userInfoData)
// userInfo.instituteId = instituteId
// userInfo.genderCode = genderCode
// console.log(JSON.stringify(userInfo))
// // 交互处理
// let commandManager = CommandManager.shareInstance()
// let res = commandManager.webCallAppCommandWithScriptMessage(value, userInfo, this.webView)
// let jsType = res.type
// let jsonRes = JSON.stringify(res)
// let resData: CommandModel = JSON.parse(jsonRes)
// console.log('[交互回调]:', JSON.stringify(res))
// let argsJson = JSON.stringify(res.args)
// // App call web 数据格式处理
// let appCallWeb = AppCallWeb.shareInstance()
// let callbacks = appCallWeb.callbackWithServiceResultSelect(DataType.DataTypeNormal, sn, res, null)
// if (jsType == 'Json') {
// callbacks = appCallWeb.callbackWithServiceResultSelect(DataType.DataTypeJson, sn, res, null)
// } else if (jsType == 'Encode') {
// callbacks = appCallWeb.callbackWithServiceResultSelect(DataType.DataTypeJsonEncoded, sn, res, null)
// } else if (jsType == 'Basic') {
// callbacks = appCallWeb.callbackBasic(sn, res, null)
// }
// console.log('[callbacks]')
// console.log(callbacks)
// console.log('************')
// return argsJson
// }
// }
WebTestAsync = async (value: string): Promise<string> => { // 测试 - 异步
let userInfo: UserInfoModal = JSON.parse(userInfoData)
userInfo.instituteId = instituteId
userInfo.genderCode = genderCode
let commandManager = CommandManager.shareInstance()
let res = await commandManager.webCallAppCommandWithScriptMessage(value, userInfo, this.webView)
let argsJson = JSON.stringify(res.args)
console.log('[WebTestAsync]')
console.log(argsJson)
return argsJson
}
WebTest(value: string): Promise<string> { // 测试 - promise
let p: Promise<string> = new Promise((resolve, reject) => {
let userInfo: UserInfoModal = JSON.parse(userInfoData)
userInfo.instituteId = instituteId
userInfo.genderCode = genderCode
let commandManager = CommandManager.shareInstance()
let res = commandManager.webCallAppCommandWithScriptMessage(value, userInfo, this.webView)
let argsJson = JSON.stringify(res.args)
resolve('[Callback]:' + argsJson)
})
return p
}
}
二.前端
基于 Vue 2 调试;
1.配置交互消息处理
/* eslint-disable */
import webApp from './index';
import { Toast } from "vant";
Date.prototype.format = function(format) {
var o = {
"M+": this.getMonth() + 1, //month
"d+": this.getDate(), //day
"h+": this.getHours(), //hour
"m+": this.getMinutes(), //minute
"s+": this.getSeconds(), //second
"q+": Math.floor((this.getMonth() + 3) / 3), //quarter
"S": this.getMilliseconds() //millisecond
};
if (/(y+)/.test(format)) {
format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(format)) {
format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
}
}
return format;
};
var AppCallBacks = {},//动态数据流水列表
AppCommendBackHandlers = [],//APP后退监听事件列表
AppCommendRefreshHandlers = [],//刷新监听事件列表
APPCommendReBackHandlers = [],//监听重新回到页面通知
AppCommendNetworkHandlers = [],//监听网络链接状态
AppCommendAppStartingHandlers = [],//监听APP进入后台运行
AppCommendAppReactivateHandlers = [],//监听APP重新进入前台运行
AppCommendKeyboardBounceUp = [],
AppHarmonyHandlers = {}; // 基于 Harmony 适配;
//监听移动端事件
var AppMsgHandlers = {
//页面加载完成(TODO plan)
//"MsgOnReady":function(msg){},
// 移动端软键盘事件触发
"MsgSoftKeyboardBounceUp": function (data) {
if (AppCommendKeyboardBounceUp.length > 0) {
AppCommendKeyboardBounceUp.forEach(item => {
item.call(window,data);
});
}
},
//刷新数据通知(Realized)
"MsgRefresh": function (data) {
//data.type 0 刷新书架和已获得,1只刷新书架,2,只刷新已获得
if (AppCommendRefreshHandlers.length > 0) {
AppCommendRefreshHandlers.forEach(item => {
item.call(window,data);
});
}
},
//后退事件(Realized)
"MsgGoBack": function (data) {
webApp.APPCommendBack(data);
},
//重新返回到界面(Realized)
"MsgReBack": function () {
if (APPCommendReBackHandlers && APPCommendReBackHandlers.length > 0) {
APPCommendReBackHandlers.forEach(item => {
item.call(this);
});
}
},
//网络监测
"MsgNetworkState": function (result) {
if (AppCommendNetworkHandlers && AppCommendNetworkHandlers.length > 0) {
AppCommendNetworkHandlers.forEach(item => {
item.call(this, result);
});
}
},
//App 后台运行
"MsgAppStarting": function (result) {
if (AppCommendAppStartingHandlers && AppCommendAppStartingHandlers.length > 0) {
AppCommendAppStartingHandlers.forEach(item => {
item.call(this, result);
});
}
},
//App重新激活
"MsgAppReactivate": function (result) {
if (AppCommendAppReactivateHandlers && AppCommendAppReactivateHandlers.length > 0) {
AppCommendAppReactivateHandlers.forEach(item => {
item.call(this, result);
});
}
},
};
/*
*
* app对接
* 移动端种植Elf对象
* window => Elf
*
*/
(function () {
if (!window.applicationCache&&typeof(Worker)=='undefined') {
alert("E001-检测到您的环境不支持HTML5,程序终止运行!");//不支持HTML5
return;
}
// iOS & Android
var global = window;//create a pointer to the window root
if (typeof Elf === 'undefined') {
global.Elf = {};//create elf root if not existed
}
Elf.global = global;//add a pointer to window
if (typeof WebCallApp == 'undefined') {
global.WebCallApp = {
WebCallApp: (args) => {},
// WebCallAppHarmony: (args) => {}
};
}
// Harmony
if (typeof WebCallAppHarmony == 'undefined') {
global.WebCallAppHarmony = {
WebCallAppHarmony: (args) => {},
};
}
// 测试
if (typeof WebCallAppTest == 'undefined') {
global.WebCallAppTest = {
WebCallAppTest: (args) => {},
}
}
// global.WebCallApp.Elf = Elf;
WebCallApp.global = global;
WebCallAppHarmony.global = global;
WebCallAppTest.global = global;
})();
if (typeof Elf != "undefined") {
Elf.AppCallWeb = (sn, result) => {
console.log('[鸿蒙] - 测试');
console.log('sn:' + sn);
console.log('res:' + JSON.stringify(result));
if (navigator.userAgent.toLowerCase().indexOf('openharmony') !== -1) { // Harmony
AppCallBacks[sn].callback.call(AppCallBacks[sn].context,result);
} else { // iOS & Android
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);
}
}
};
}
export {
AppCallBacks,
AppCommendBackHandlers,
AppCommendAppStartingHandlers,
APPCommendReBackHandlers,
AppCommendKeyboardBounceUp,
AppMsgHandlers,
AppHarmonyHandlers
}
2.设置 WebCallApp 方法
/* eslint-disable */
import { Toast } from "vant";
import { AppCallBacks, AppCommendBackHandlers, AppHarmonyHandlers } from './AppMsgHandlers'
export default {
/***********************************************************
处理App发送的后退命令
***********************************************************/
APPCommendBack() {
if (AppCommendBackHandlers.length > 0) {
if (typeof AppCommendBackHandlers[ AppCommendBackHandlers.length - 1 ] == "function") {
AppCommendBackHandlers[ AppCommendBackHandlers.length - 1 ].call(window);
}
} else {
if (this.isInApp()) {
if (!this.isEmptyObject(AppCallBacks)) {
//Elf.components.toast({text:""});
} else {
this.WebCallApp("CmdGoBack");
}
} else {
history.back(-1);
}
}
},
WebTestAsync(command, args, callback, context) { // 测试
console.log('WebTestAsync');
console.log(command);
console.log(args);
},
WebTestSync(command, args, callback, context) { // 测试
console.log('WebTestSync');
console.log(command);
console.log(args);
},
WebCallApp(command, args, callback, context) {
/**
* 交互
*
* 协议:command
* 入参:args
* 回调:callback
* 参数:context
* */
if (typeof Elf.AppCallWeb != "undefined") {
context = context || window;//默认为window对象
args = args || {};
let sn = null;
//IOS调用相机--sn特殊处理
if (command == "callCamera") {
sn = "examCamera";
} else {
sn = this.getSerialNumber();//请求App统一加水单号
}
console.log('first:', sn);
let params = {
args : args,
command : command,
sn : sn,
};
//绑定回调函数
if (callback) {
AppCallBacks[ sn ] = {
callback : callback,
context : context
};
}
if (window.webkit && window.webkit.messageHandlers) { // iOS
params.sn = sn;
window.webkit.messageHandlers[ "WebCallApp" ].postMessage(JSON.stringify(params));
} else if (Elf.WebCallApp) { // Android
params.sn = sn;
Elf.WebCallApp(JSON.stringify(params));
} else if (this.isInCef()) { // PC
params.sn = sn;
Elf.WebCallCef(JSON.stringify(params));
} else if (this.isInHarmonyOS()) { // HarmonyOS Next
// 方式一: WebCallApp => AppCallWeb 交互通信方式
params.sn = sn;
WebCallAppHarmony[ 'WebCallApp' ](JSON.stringify(params));
// 方式三: callback 延迟回调
// console.log('sn - 0:', sn);
// let timer = setTimeout(() => {
// console.log('sn - 1:', sn);
// if (callback) {
// console.log('sn - 2:', sn);
// callback(AppHarmonyHandlers.result);
// clearTimeout(timer);
// }
// }, 500);
// let result = WebCallApp[ 'WebCallApp' ](JSON.stringify(params)); // old
// 方式二: WebCallApp 直接交互
// let result = WebCallAppHarmony[ 'WebCallApp' ](JSON.stringify(params)); // 适配考试
// console.log(result);
// callback
// if (result && typeof result == 'string') {
// try {
// result = JSON.parse(result);
// } catch (error) {
// console.log(JSON.parse(result));
// AppCallBacks[ sn ].callback.call(AppCallBacks[ sn ].context, result);
// return
// }
// if (result.sn) {
// AppCallBacks[ sn ].callback.call(AppCallBacks[ sn ].context, result);
// return;
// }
// }
} else {
//直连接口服务器
// if (Config.services[command]) {
// args.token = User.token;
// if (command == "UserLogin") {
// args.token = -1;
// }
// var request = {
// terminalType: "A",
// deviceType: "1",
// serviceModule: Config.services[command].sm,
// serviceNumber: Config.services[command].sn,
// token: command == "UserLogin" ? "-1" : User.token,
// args: args
// };
// options.data = request;
// options.method = 'post';
// options.url = process.env.root;
// options.dataType = 'json';
// axios(options).then(res => {
// Elf.AppCallWeb(sn,data);
// Toast.clear();
// }).catch(
// error => {
// var errorData = { opFlag: false,errorMessage: "总线错误" };
// Elf.AppCallWeb(sn,JSON.stringify(errorData),"JSON");
// }
// );
// }
}
}
},
AppCommendTostInfo(result) {
if (result.msg) {
Toast(result.msg);
}
},
/***********************************************************
App Call Web 入口方法,
All of app to web use that
***********************************************************/
isInApp() {
if (typeof Elf.AppCallWeb != "undefined") {
return !!((window.webkit && window.webkit.messageHandlers) || typeof Elf.WebCallApp == "function" || typeof Elf.WebCallCef == "function" || typeof Elf.getTestDataAsync == "function");
// || typeof Elf.WebCallAppHarmony == "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;
}
},
isInCef() {
if (typeof Elf.AppCallWeb != "undefined") {
return typeof Elf.WebCallCef == "function";
}
},
isEmptyObject(obj) {
let name;
for (name in
obj) {
return false;
}
return true;
},
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('');
},
getSerialNumber() {
// var uuid = this.UUID(3, 8);
// return new Date().format("yyyyMMddhhmmssS") + uuid; // after
return Math.random().toString(); // new
},
}
3.全局设置
跟目录 main.js 中配置为全局
import webApp from '../src/expand/webApp/index';
import { AppCommendBackHandlers } from "./expand/webApp/AppMsgHandlers";
Vue.prototype.webApp = webApp;
Vue.prototype.WebBack = AppCommendBackHandlers;
4.交互调用
this.webApp.WebCallApp('GetAPPDetail', {'abc': '123'}, (res) => { // 测试: 鸿蒙 jsbridge 交互
console.log('[交互] - 回调');
console.log(res);
});
以上便是此次分享的全部内容,希望能对大家有所帮助!
版权归原作者 survivorsfyh 所有, 如有侵权,请联系我们删除。