由于需要在uniapp开发的app项目中集成游戏,网上查询一些集成的资料得知可以通过webview间接集成,所以就需要学习uniapp项目与webview的通讯,下面记录一下踩坑经验。
首先这是webview官方文档,文档讲述webview的属性是指向网页的链接,我这边没有放服务器,项目内直接集成的本地文件,App 平台是同时支持网络网页和本地网页(小程序仅支持加载网络网页,不支持本地html) ,但本地网页及相关资源(js、css等文件)必须放在 uni-app 项目根目录->hybrid->html 文件夹下或者 static 目录下, 像这样--
然后必须要在html中引入uni.webview.js才能使用uniAPI,其实就是把webview当做与html通讯的子组件了,子组件通过uniAPI派发给uniapp事件进行子传父通讯,下面记录一下两边通讯的方法。
webview向uniapp通讯
接受消息:
在uniapp页面通过监听 web-view 组件的 @message 事件(H5 暂不支持,可以直接使用 window.postMessage),可以在特定时机(后退、组件销毁、分享)触发并收到形参的evt.detail.data拿到消息。如果是nvue页面(必须手动指定宽高),可以直接使用@onPostMessage实时获取消息。
<template>
<view>
<web-view src="/hybrid/html/ceshi.html"
@message="handleMessage"
@onPostMessage="handleMessage"></web-view>
</view>
</template>
<script>
export default {
data() {
return {}
},
methods: {
handleMessage(evt) {
console.log('这里是webview接收到的消息:' + JSON.stringify(evt.detail.data));
}
},
}
</script>
<style scoped lang="scss"></style>
发送消息:
webview向应用发送消息使用uni.postMessage API,传递的消息数据需要写在data中,而且要先监听 UniAppJSBridgeReady 事件触发后,才能安全调用 uni 的 API
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
</head>
<body>
<p>web-view 组件加载网络 html 示例。点击下列按钮,跳转至其它页面。</p>
<button id="navigateTo">navigateTo</button>
<p class="desc">网页向应用发送消息,注意:小程序端应用会在此页面后退时接收到消息。</p>
<button id="postMessage">postMessage</button>
<!-- uni 的 SDK -->
<script type="text/javascript" src="./uniWebView.js">
<script type="text/javascript">
// 待触发 `UniAppJSBridgeReady` 事件后,即可调用 uni 的 API。
document.addEventListener('UniAppJSBridgeReady', function() {
uni.postMessage({
data: {
action: 'message'
}
});
document.getElementById('navigateTo').addEventListener('click', function() {
uni.switchTab({
url: '/pages/tabBar/API/API'
});
});
document.getElementById('postMessage').addEventListener('click', function() {
uni.postMessage({
data: {
action: 'message'
}
});
});
});
</script>
</body>
</html>
uniapp向webview的html通讯
1、nvue页面向webview的通讯
发送消息:
根据官网的通讯示例,为webview组件设定ref属性,通过点击事件调用evalJs函数即可发送消息。
<web-view ref="webviews" :webview-styles="webviewStyles" src="/hybrid/html/ceshi.html"
@message="handleMessage" @onPostMessage="handleMessage"></web-view>
<button class="button" @click="evalJs">evalJs(点击向webview传参)</button>
evalJs() {
this.$refs.webview.evalJs("document.body.style.background ='#00FF00'");
//也可以直接调用webview中的函数传参通讯
this.$refs.webviews.evalJs(`msgFromApp(${this.token})`);
}
接收消息:
直接在UniAppJSBridgeReady事件回调中添加函数,nvue页面在调用evalJs后就会触发,简单方便。
document.addEventListener('UniAppJSBridgeReady', () => {
window.msgFromApp = (ev) => {
alert('接收到uniapp参数' + JSON.stringify(ev))
}
});
2、vue页面向webview的通讯(未实践)
发送消息:
查看官方的webview扩展文档,可以通过this.$scope.$getAppWebview()获取当前应用的所有 WebView 实例,再拿到当前web-view组件对应的js对象后,任意地方即可通过evalJS函数发送消息。
注意:通过这个帖子(为什么evalJS无效,明明官方就是这样写的 - DCloud问答),了解到wv变量要在export default 外面定义才可以;当然也可能现在直接在data中定义也可以,具体没实操。
var wv;//计划创建的webview
export default {
methods: {
setMessage() {
wv.evalJs(`msgFromApp(${this.token})`);
}
},
onReady() {
// #ifdef APP-PLUS
var currentWebview = this.$scope.$getAppWebview()
//此对象相当于html5plus里的plus.webview.currentWebview()。
//在uni-app里vue页面直接使用plus.webview.currentWebview()无效
setTimeout(function() {
wv = currentWebview.children()[0]
}, 1000); //如果是页面初始化调用时,需要延时一下
// #endif
}
};
接受消息:
和nvue一样,直接在html页面中添加函数,vue页面在调用evalJs后就会触发,简单方便。
window.msgFromApp = (ev) => {
alert('接收到uniapp参数' + JSON.stringify(ev))
}
3、vue页面通过web-view的src属性带参数向webview的通讯(未实践)
这种只适合传一次固定参数值的场景,并且是单向通讯,否则不建议。
额外注意URL参数特殊字符要记得先编码转义,html接受时再解码回来。
vue代码传参:
<template>
<view>
<web-view v-if="webViewSrc" :src="webViewSrc"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
webViewSrc: ''
};
},
onload: {
const lat = 123.456; // 示例纬度
const long = 78.910; // 示例经度
this.webViewSrc = `https://xxx.com/home.html?lat=${lat}&long=${long}`;
}
};
</script>
html代码接收:
window.location.search直接获取URL中的参数值,使用URLSearchParams API来解析参数。
const params = new URLSearchParams(window.location.search);
const lat = params.get('lat');
const long = params.get('long');
三、注意事项
1、webview默认铺满整个页面,但在nvue页面在必须手动指定宽高,否则不显示;可以通过webview-styles属性动态绑定宽高,通过更改变量中的width、height实现--
webviewStyles: {
progress: {
color: '#FF3333'
},
width: '750rpx',
height: '700rpx'
},
2、uni的sdk<script type="text/javascript" src="https://gitcode.net/dcloud/uni-app/-/raw/dev/dist/uni.webview.1.5.6.js"></script>直接引用我这边无效,建议复制粘贴放html本地文件或者下载到自己的服务器
3、HBuilderX的终端不会打印html页面的console.log日志,可以使用alert调试。
4、引入的uni的SDK仅支持getEnv、postMessage、navigateBack、navigateTo、reLaunch、redirectTo、switchTab这几种API。
5、App端安卓不用管,iOS有UIWebview和WKWebview两种webview,如果是老HBuilder和HBuilderX 2.2.5之前的版本,则额外要注意此条,简单说就是老版本编译器的web-view组件默认使用UIWebview,App Store已经不接受使用UIWebView的新App,点击查看官方文档。
6、WKWebview有着更严格的跨域访问限制,本地html通过js访问网络及本地文件都算跨域访问(标准的xhr或jq的ajax,都无法跨域)
7、如果H5页面是uni写的,uni方法冲突可以从参考这位博主的改进方法。
四、参考文档
web-view | uni-app官网 (dcloud.net.cn)
在web-view加载的本地及远程HTML中调用uni的API及网页和vue页面通讯 - DCloud问答
uniapp实现与webview之间的相互通讯_uniapp webview 通信-CSDN博客
uniapp向webview中发送消息 - DCloud问答
uni-app实现web-view和App之间的相互通信 - 掘金 (juejin.cn)
欢迎补充交流~