1.背景
应用使用了uniapp开发跨端应用,在uniapp中内嵌webview页面实现页面热更新效果,不需要用户单独重新安装软件即可实现页面的版本更新。
2.webview通知uniapp
在开发过程中我们难会遇到需要uniapp和webview来实现数据通信的场景,接下来介绍一种可行的uniapp和webview的数据通信方案。 在webview中我们可以使用当前webview实例的postMessage方法来触发webview组建的onPostMessage方法来传递数据,重点就需要放在了如何将uniapp的webview实例来加入到webview的h5项目当中。
uniapp官方文档中指出可以使用uni.webview.js 这个js SDK 来将当前的uni对象注入到webview所加载的H5项目当中。
最新版地址:gitcode.net/dcloud/uni-...
1.UniAppJSBridgeReady :
这个是在引入webview的SDK之后,当webview页面被加载完成之后会触发,该事件触发表示着uniapp和webview之间的桥成功搭建,uni对象被成功的注入到当前H5的上下文中。 我们在index.html文件中将SDK引入,这里的SDK引入必须放在body标签下面。
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
...
</head>
<body>
<noscript>
<strong>Please enable JavaScript to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
<!-- uni 的 SDK -->
<!-- 需要把 uni.webview.1.5.6.js 下载到自己的服务器 -->
<script type="text/javascript" src="https://gitcode.net/dcloud/uni-app/-/raw/dev/dist/uni.webview.1.5.6.js"></script>
<script>
document.addEventListener('UniAppJSBridgeReady', function() {
uni.webView.getEnv(function(res) {
console.log('当前环境:' + JSON.stringify(res));
});
// uni.webView.navigateTo(...)
});
</script>
</html>
2.webview中可用的uni API
方法名 | 说明 | 平台差异说明 |
---|---|---|
uni.navigateTo | navigateTo | |
uni.redirectTo | redirectTo | |
uni.reLaunch | reLaunch | |
uni.switchTab | switchTab | |
uni.navigateBack | navigateBack | |
uni.postMessage | 向应用发送消息 | 抖音小程序不支持、H5 暂不支持(可以直接使用 window.postMessage |
uni.getEnv | 获取当前环境 | 抖音小程序与飞书小程序不支持 |
3.发送消息
我们在H5中可以使用uni.postMessage方法来向应用发送消息,应用中的webview的onPostMessage方法会被触发,从而通过参数就可以拿到需要传递的数据。 或者因为可以使用uni.webView获取到当前webview实例,调用实例postMessage方法也可以传递数据。 注意: 这种做法在H5端是不支持的,后续会介绍H5端的处理方式。
3.uniapp 通知webview
uniapp通知webview页面,官方提供了一种巧妙地方式。在H5项目中全局暴露一个用于接收数据的函数,然后在uniapp中去触发这个函数将参数传递过去即可是实现数据的传递。
evalJS
uniapp为每一个webview组件实例挂载了一个evalJS方法,用于为webview页面注入一个可执行的js脚本代码。这段代码会在webview的全局作用域中执行。我们使用evalJS来触发一个特定的函数,在H5的全局作用域中定义对应的函数,并提前写好对应的数据处理逻辑。后续只需要在uniapp中触发evalJS即可实现数据的传递。
注意:这种方式在H5端也是不支持的,后续会介绍。
4.H5中实现数据的通信
上述介绍的webview和uniapp的通信只针对于uniapp编译的代码是非H5环境,如果是H5环境则无效。因此使用postMessage 方案替代 postMessage window.postMessage 是一个非常强大的 Web API,用于在不同窗口或内嵌页面(如 <iframe>
)之间安全地传递消息。它允许跨源通信,即不同域名、协议或端口的页面之间可以互相发送消息。 window.postMessage 方法允许一个窗口向另一个窗口发送消息。消息的接收方可以通过监听 message 事件来接收消息。为了确保安全性,postMessage 方法需要明确指定目标窗口的来源(targetOrigin),以防止消息被发送到不安全的地址。 主页面
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Main Page</title>
</head>
<body>
<h1>Main Page</h1>
<iframe id="myIframe" src="https://other-origin.com/iframe.html" width="600" height="400"></iframe>
<button id="sendMessage">Send Message to Iframe</button>
<script>
// 获取 iframe 的引用
const iframe = document.getElementById('myIframe');
// 监听按钮点击事件,向 iframe 发送消息
document.getElementById('sendMessage').addEventListener('click', () => {
// 确保 iframe 已加载完成
if (iframe.contentWindow) {
iframe.contentWindow.postMessage('Hello from main page!', 'https://other-origin.com');
}
});
// 监听来自 iframe 的消息
window.addEventListener('message', (event) => {
// 验证来源
if (event.origin !== 'https://other-origin.com') return;
console.log('Received message from iframe:', event.data);
});
</script>
</body>
</html>
内嵌页面
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Iframe Page</title>
</head>
<body>
<h1>Iframe Page</h1>
<button id="sendMessage">Send Message to Main Page</button>
<script>
// 监听按钮点击事件,向主页面发送消息
document.getElementById('sendMessage').addEventListener('click', () => {
// 向父窗口发送消息
window.parent.postMessage('Hello from iframe!', '*');
});
// 监听来自主页面的消息
window.addEventListener('message', (event) => {
// 验证来源
if (event.origin !== 'http://main-page-origin.com') return;
console.log('Received message from main page:', event.data);
});
</script>
</body>
</html>