前端 JavaScript 與鴻蒙 Web 組件間相互通信的方式;
注:此案例采用兩端間雙向模式機(jī)制進(jìn)行通信;
單向模式可參考 前端 Web 與原生應(yīng)用端 WebView 通信交互
官方文檔傳送門如下:
WebCall
AppCallWeb
一.鴻蒙端
1.設(shè)置 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
}
// 方式一: 方法無回調(diào),通過交互協(xié)議 WebCallApp => AppCallWeb
WebCallApp(value: string) {
console.log('********* [交互] --- 協(xié)議 - HWebView')
// 接收 Web 端數(shù)據(jù)源
console.log(value)
// 交互數(shù)據(jù)處理
do something ...
// 如果需要數(shù)據(jù)回調(diào),則通過如下 callback 方法將處理后的數(shù)據(jù)回調(diào)至 Web
// 如果不需要數(shù)據(jù)回調(diào),則執(zhí)行其它業(yè)務(wù)邏輯即可,無需調(diào)用如下 callback 方法
this.webView.runJavaScript(value)
}
// 方式二: 方法回調(diào),WebCallApp 直接 return
// WebCallApp(value: string): string { // 直接 return 方式
// console.log('[交互] --- WebCallApp - 測試 - HWebView')
// // 接收 Web 端數(shù)據(jù)源
// console.log(value)
//
// // 交互數(shù)據(jù)處理
// 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 的代理方法與前端通信接發(fā)消息;
1).name 兩端交互的協(xié)議 key
2).object 對應(yīng)的是 WebCallApp 的交互接收方法
3).methodList 基于 object 的 WebCallApp 中交互具體實現(xiàn)的若干函數(shù)方法
4).controller 組件
Web({ src: this.url, controller: this.controller })
.width('100%')
.height('100%')
.backgroundColor(Color.White)
.multiWindowAccess(true)
.javaScriptAccess(true)// 訪問本地資源文件
.imageAccess(true)// 權(quán)限狀態(tài)開啟
.onlineImageAccess(true)// 權(quán)限狀態(tài)開啟
.fileAccess(true)// 權(quán)限狀態(tài)開啟
.domStorageAccess(true)// 數(shù)據(jù)存儲權(quán)限
.mediaPlayGestureAccess(true)// 媒體權(quán)限
.mixedMode(MixedMode.All)// https 加載
.layoutMode(WebLayoutMode.FIT_CONTENT)// 自適應(yīng)布局
.verticalScrollBarAccess(true)// 滾動條
.horizontalScrollBarAccess(false)// 滾動條
.cacheMode(CacheMode.Default)// 緩存
.zoomAccess(false)// 禁止手勢縮放
.geolocationAccess(true)// 定位權(quán)限
.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) => { // 異常: 無網(wǎng)絡(luò),頁面加載錯誤時
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) => { // 異常: 網(wǎng)頁加載資源 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) => { // 提示框處理相關(guān)
AlertDialog.show({
title: '溫馨提示',
message: event?.message,
confirm: {
value: '確認(rèn)',
action: () => {
event?.result.handleConfirm()
}
},
cancel: () => {
event?.result.handleCancel()
}
})
return true;
})
.onConfirm((event) => { // 提示框處理相關(guān)
AlertDialog.show({
title: '溫馨提示',
message: event?.message,
confirm: {
value: '確認(rèn)',
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 組件初始化調(diào)用
// 對象注入 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
// 用戶信息相關(guān)
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)
// 標(biāo)題
@State title: string = ''
// 導(dǎo)航欄是否顯示(默認(rèn)顯示 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()
// 執(zhí)行自定義邏輯
return true
} else { // 執(zhí)行系統(tǒng)默認(rèn)返回邏輯
return false
}
}
onPageShow(): void { // 頁面進(jìn)入前臺
console.log('[頁面進(jìn)入前臺]');
// 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 { // 頁面進(jìn)入后臺
console.log('[頁面進(jìn)入后臺]');
}
/****** 初始化 init 配置相關(guān) ******/
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 {
// 啟用網(wǎng)頁調(diào)試功能
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(); // 頁面異常,刷新
}
}
// 白屏情況可能是權(quán)限導(dǎo)致,把權(quán)限全部開啟,例如本地存儲或者 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)// 權(quán)限狀態(tài)開啟
.onlineImageAccess(true)// 權(quán)限狀態(tài)開啟
.fileAccess(true)// 權(quán)限狀態(tài)開啟
.domStorageAccess(true)// 數(shù)據(jù)存儲權(quán)限
.mediaPlayGestureAccess(true)// 媒體權(quán)限
.mixedMode(MixedMode.All)// https 加載
.layoutMode(WebLayoutMode.FIT_CONTENT)// 自適應(yīng)布局
.verticalScrollBarAccess(true)// 滾動條
.horizontalScrollBarAccess(false)// 滾動條
.cacheMode(CacheMode.Default)// 緩存
.zoomAccess(false)// 禁止手勢縮放
.geolocationAccess(true)// 定位權(quán)限
.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) => { // 異常: 無網(wǎng)絡(luò),頁面加載錯誤時
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) => { // 異常: 網(wǎng)頁加載資源 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) => { // 提示框處理相關(guān)
AlertDialog.show({
title: '溫馨提示',
message: event?.message,
confirm: {
value: '確認(rèn)',
action: () => {
event?.result.handleConfirm()
}
},
cancel: () => {
event?.result.handleCancel()
}
})
return true;
})
.onConfirm((event) => { // 提示框處理相關(guān)
AlertDialog.show({
title: '溫馨提示',
message: event?.message,
confirm: {
value: '確認(rèn)',
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 組件初始化調(diào)用
// 對象注入 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
}
// 方式一: 方法無回調(diào),通過交互協(xié)議 WebCallApp => AppCallWeb
WebCallApp(value: string) {
console.log('********* [交互] --- 協(xié)議 - HWebView')
console.log(value)
// 解析交互協(xié)議
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('********* [交互] - 協(xié)議 *********')
// 用戶信息中添加機(jī)構(gòu)
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('[交互回調(diào)]:', argsJson)
// App call web 數(shù)據(jù)格式處理
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})`)
}
// 方式二: 方法回調(diào),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 {
// // 解析交互協(xié)議
// 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))
// // 用戶信息中添加機(jī)構(gòu)
// 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('[交互回調(diào)]:', JSON.stringify(res))
// let argsJson = JSON.stringify(res.args)
// // App call web 數(shù)據(jù)格式處理
// 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 調(diào)試;
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 = {},//動態(tài)數(shù)據(jù)流水列表
AppCommendBackHandlers = [],//APP后退監(jiān)聽事件列表
AppCommendRefreshHandlers = [],//刷新監(jiān)聽事件列表
APPCommendReBackHandlers = [],//監(jiān)聽重新回到頁面通知
AppCommendNetworkHandlers = [],//監(jiān)聽網(wǎng)絡(luò)鏈接狀態(tài)
AppCommendAppStartingHandlers = [],//監(jiān)聽APP進(jìn)入后臺運行
AppCommendAppReactivateHandlers = [],//監(jiān)聽APP重新進(jìn)入前臺運行
AppCommendKeyboardBounceUp = [],
AppHarmonyHandlers = {}; // 基于 Harmony 適配;
//監(jiān)聽移動端事件
var AppMsgHandlers = {
//頁面加載完成(TODO plan)
//"MsgOnReady":function(msg){},
// 移動端軟鍵盤事件觸發(fā)
"MsgSoftKeyboardBounceUp": function (data) {
if (AppCommendKeyboardBounceUp.length > 0) {
AppCommendKeyboardBounceUp.forEach(item => {
item.call(window,data);
});
}
},
//刷新數(shù)據(jù)通知(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);
});
}
},
//網(wǎng)絡(luò)監(jiān)測
"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-檢測到您的環(huán)境不支持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)) {
//執(zhí)行對應(yīng)回調(diào)
AppCallBacks[sn].callback.call(AppCallBacks[sn].context,(typeof result.serviceResult == "string") ? JSON.parse(result.serviceResult) : result.serviceResult);
} else {
//接口調(diào)用返回失敗信息,統(tǒng)一處理錯誤消息
Toast(result.errorMessage ? result.errorMessage : "服務(wù)器異常!");
}
//調(diào)用完成刪除對象
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.設(shè)置 WebCallApp 方法
/* eslint-disable */
import { Toast } from "vant";
import { AppCallBacks, AppCommendBackHandlers, AppHarmonyHandlers } from './AppMsgHandlers'
export default {
/***********************************************************
處理App發(fā)送的后退命令
***********************************************************/
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) {
/**
* 交互
*
* 協(xié)議:command
* 入?yún)?args
* 回調(diào):callback
* 參數(shù):context
* */
if (typeof Elf.AppCallWeb != "undefined") {
context = context || window;//默認(rèn)為window對象
args = args || {};
let sn = null;
//IOS調(diào)用相機(jī)--sn特殊處理
if (command == "callCamera") {
sn = "examCamera";
} else {
sn = this.getSerialNumber();//請求App統(tǒng)一加水單號
}
console.log('first:', sn);
let params = {
args : args,
command : command,
sn : sn,
};
//綁定回調(diào)函數(shù)
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 延遲回調(diào)
// 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 {
//直連接口服務(wù)器
// 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.全局設(shè)置
跟目錄 main.js 中配置為全局
import webApp from '../src/expand/webApp/index';
import { AppCommendBackHandlers } from "./expand/webApp/AppMsgHandlers";
Vue.prototype.webApp = webApp;
Vue.prototype.WebBack = AppCommendBackHandlers;
4.交互調(diào)用
this.webApp.WebCallApp('GetAPPDetail', {'abc': '123'}, (res) => { // 測試: 鴻蒙 jsbridge 交互
console.log('[交互] - 回調(diào)');
console.log(res);
});
以上便是此次分享的全部內(nèi)容,希望能對大家有所幫助!