前言
最近Uniapp也更新了鸿蒙系统的打包,然后本人开发鸿蒙app时候发现webview的通信方式,与安卓、ios略有不同,踩坑好久才解决,发现网上对于这个问题解决方案基本没有,所以记录下来,帮助新入坑的同学。
环境
- Hbuilder:4.29
- H5引用的uni-webview版本:1.5.5
- uni:uniapp vue3 版本(注意非uniapp-x)
首先H5向APP发送消息
- H5不管向鸿蒙APP发消息还是安卓ios发消息,方式都是一样的,首先要引用uni.webview.1.5.5.js文件,我是放在了static目录下,然后在index.html引用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/>
<!-- 微信 JS-SDK 如果不需要兼容小程序,则无需引用此 JS 文件。 -->
<script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<title>XJU App</title>
</head>
<body>
<!-- uni 的 SDK,必须引用。 -->
<script type="text/javascript" src="/uni.webview.1.5.5.js"></script>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
- 封装一个jsbridge.js文件,用来向APP发送消息,并且能收到对应的回调消息
class NativeInstance {
customInvoke(data) {
const tp = new Date().getTime().toString()
data = {
type: 'customInvoke',
...data,
tp
}
// 发送消息
uni.postMessage(
{
data
},
'*'
)
return new Promise((resolve, reject) => {
window[`invokeResolve${tp}`] = resolve
window[`invokeReject${tp}`] = reject
})
}
}
let instance: any = null
export default () => {
if (!instance) {
instance = new NativeInstance()
}
return instance
}
- 使用方法
<script setup lang="ts">
import getNativeInstance from '@/utils/JSBridge'
const getAppToken = () => {
getNativeInstance()
.customInvoke({
action: 'oauth',
data: {
a: 123123
}
})
.then((res) => {
console.log(res)
})
}
</script>
鸿蒙、安卓、ios接受H5消息
- APP中,使用web-view标签
- 注意必须要设置id
<template>
<div class="openUrl">
<web-view id="webviewId" ref="webviewRef" :update-title="false" @message="onMessage" v-if="visible" :src="url"></web-view>
</div>
</template>
- 获取webview实例
onReady() {
// #ifdef APP-HARMONY
//!!! webview标签必须设置id并且是webviewId,this必传
this.currentWebview = uni.createWebviewContext('webviewId', this)
// #endif
// #ifndef APP-HARMONY
// #ifdef APP || MP-WEIXIN
let wv = this.$scope.$getAppWebview()
setTimeout(() => {
this.currentWebview = wv.children()[0]
}, 1000);
// #endif
// #endif
}
注意鸿蒙和安卓、ios获取实例的方式不一样,鸿蒙没有plus对象,所以要通过uni.createWebviewContext('webviewId', this) 获取,并且都要从onReady 生命周期获取
- 接受H5消息,并向H5发送回调消息
onMessage(e) {
console.log(`【UNILOG】-【onGetH5Message】`);
console.log('【UNILOG】', JSON.stringify(e.detail.data));
let action = null
let data = null
let tp = null
// #ifdef APP || MP-WEIXIN
action = e.detail.data[0].action
data = e.detail.data[0].data
tp = e.detail.data[0].tp
// #endif
// #ifdef APP-HARMONY
// 鸿蒙通信里面会多套一层data
action = e.detail.data[0].data.action
data = e.detail.data[0].data.data
tp = e.detail.data[0].data.tp
// #endif
// #ifdef APP-HARMONY
//!!! webview标签必须设置id并且是webviewId,this必传
this.currentWebview.evalJs(`invokeResolve${tp}('3213asd')`)
// #endif
// #ifndef APP-HARMONY
// #ifdef APP || MP-WEIXIN
this.currentWebview.evalJS(`invokeResolve${tp}('3213asd')`)
// #endif
// #endif
}
- 注意
在接受消息时候,鸿蒙会多嵌套一层data
在发送消息时候,鸿蒙发送方法是evalJs,而安卓是大写evalJS
完整代码
<template>
<div class="openUrl">
<up-loadmore status="loading" />
<!-- <up-navbar :title="name" :autoBack="true"></up-navbar> -->
<web-view id="webviewId" ref="webviewRef" :update-title="false" @message="onMessage" v-if="visible" :src="url"></web-view>
</div>
</template>
<script>
import { forEach } from 'lodash'
import { useUserStore } from '@/store/user'
export default {
data() {
return {
url: null,
name: null,
visible: false,
statusBarHeight: 0,
height: 0,
currentWebview: null // 安卓、ios、鸿蒙
}
},
onReady() {
// #ifdef APP-HARMONY
//!!! webview标签必须设置id并且是webviewId,this必传
this.currentWebview = uni.createWebviewContext('webviewId', this)
// #endif
// #ifndef APP-HARMONY
// #ifdef APP || MP-WEIXIN
let wv = this.$scope.$getAppWebview()
setTimeout(() => {
this.currentWebview = wv.children()[0]
}, 1000);
// #endif
// #endif
if(this.name) {
uni.setNavigationBarTitle({
title: this.name
})
}
},
onLoad(options) {
console.log('options: ',options);
if(options.paramsUrl) {
// 如果传入的Url本身就要带参数则需要这种格式:paramsUrl=encodeURIComponent(['https://www.baidu.com?a=123$b=123'])
const urlStr = decodeURIComponent(options.paramsUrl)
console.log('paramsUrl: ',urlStr);
this.url = urlStr
} else {
// 常规Url:url=https://www.baidu.com
this.url = options.url
}
this.name = options.name
this.visible = true
},
methods: {
onMessage(e) {
console.log(`【UNILOG】-【onGetH5Message】`);
console.log('【UNILOG】', JSON.stringify(e.detail.data));
let action = null
let data = null
let tp = null
// #ifdef APP || MP-WEIXIN
action = e.detail.data[0].action
data = e.detail.data[0].data
tp = e.detail.data[0].tp
// #endif
// #ifdef APP-HARMONY
// 鸿蒙通信里面会多套一层data
action = e.detail.data[0].data.action
data = e.detail.data[0].data.data
tp = e.detail.data[0].data.tp
// #endif
const userStore = useUserStore()
const token = userStore.userInfo['xjuToken']
// #ifdef APP-HARMONY
//!!! webview标签必须设置id并且是webviewId,this必传
this.currentWebview.evalJs(`invokeResolve${tp}('${token}')`)
// #endif
// #ifndef APP-HARMONY
// #ifdef APP || MP-WEIXIN
this.currentWebview.evalJS(`invokeResolve${tp}('${token}')`)
// #endif
// #endif
}
}
}
</script>
<style lang="scss" scoped>
.openUrl {}
</style>