uniapp实现内部容易与外部的html实现双向通信
以下提供完整的实现uniapp内部的容器获取到坐标,实现外部的网页html发起获取坐标的信号,然后uniapp获取到本机的坐标后,将获取到的坐标传递给外部的html上并且弹窗显示的整个过程,代码百分百正确,且能够实现双向传递信息!!!
1.内部vue的代码截图:



2.HBuilderX内的vue的代码如下:
bash
<template>
<view class="container">
<web-view
id="remoteH5"
:src="h5Url"
@message="handleH5Message"
></web-view>
</view>
</template>
<script>
export default {
data() {
return {
h5Url: 'http://192.168.0.242/Location.html',
subWebview: null
};
},
mounted() {
// #ifdef APP-PLUS
this.waitForSubWebview();
// #endif
},
methods: {
// 🔁 轮询获取子 webview(直到成功或超时)
waitForSubWebview(maxRetry = 20, interval = 100) {
let attempts = 0;
const check = () => {
if (this.subWebview) return; // 已获取,退出
const pages = getCurrentPages();
const page = pages[pages.length - 1];
const currentWebview = page.$getAppWebview();
const children = currentWebview.children();
if (children && children.length > 0) {
this.subWebview = children[0];
console.log('[UniApp] ✅ 成功获取子 webview:', this.subWebview.getURL());
// 可选:监听子页 loaded(更保险)
this.subWebview.onloaded = () => {
console.log('[UniApp] 🟢 子页面 DOM 已加载完成');
};
} else if (attempts < maxRetry) {
attempts++;
setTimeout(check, interval);
} else {
console.error('[UniApp] ❌ 超时:未能获取子 webview');
}
};
check(); // 立即首次检查
},
handleH5Message(e) {
const msg = e.detail.data?.[0];
if (!msg || !msg.action) return;
console.log('[UniApp] 📥 收到 HTML 消息:', msg);
if (msg.action === 'requestLocation') {
this.getLocationAndSendToH5();
}
},
getLocationAndSendToH5() {
uni.showLoading({ title: '定位中...' });
uni.getLocation({
type: 'gcj02',
success: (res) => {
uni.hideLoading();
const { latitude, longitude } = res;
// ✅ 关键:用子 webview evalJS,调用 HTML 的 receiveFromUniApp
// #ifdef APP-PLUS
if (this.subWebview) {
const data = {
action: 'locationResult',
latitude: latitude,
longitude: longitude,
accuracy: res.accuracy
};
const script = `typeof receiveFromUniApp === 'function' ? receiveFromUniApp(${JSON.stringify(data)}) : console.error('[H5] receiveFromUniApp 未定义!')`;
this.subWebview.evalJS(script);
console.log('[UniApp] ✅ 坐标已注入 HTML');
} else {
// 若仍无子页,走 fallback:延迟重试
setTimeout(() => {
if (this.subWebview) {
this.getLocationAndSendToH5(); // 重试一次
} else {
uni.showToast({ title: '页面未就绪,请稍后重试', icon: 'none', duration: 2000 });
}
}, 500);
}
// #endif
},
fail: (err) => {
uni.hideLoading();
// #ifdef APP-PLUS
if (this.subWebview) {
this.subWebview.evalJS(`receiveFromUniApp({ action: 'locationError', message: ${JSON.stringify(err.errMsg)} })`);
}
// #endif
}
});
}
}
};
</script>
<style>
.container { width: 100%; height: 100vh; }
</style>
3.外部的html中的代码的部分截图:



uni.webview.1.5.5.js内的代码(自己创建,负责进去百分百可以用):
bash
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function i(e,i){return n.call(e,i)}var t=[];function o(){return window.__dcloud_weex_postMessage||window.__dcloud_weex_}function a(){return window.__uniapp_x_postMessage||window.__uniapp_x_}var r=function(e,n){var i={options:{timestamp:+new Date},name:e,arg:n};if(a()){if("postMessage"===e){var r={data:n};return window.__uniapp_x_postMessage?window.__uniapp_x_postMessage(r):window.__uniapp_x_.postMessage(JSON.stringify(r))}var d={type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}};window.__uniapp_x_postMessage?window.__uniapp_x_postMessageToService(d):window.__uniapp_x_.postMessageToService(JSON.stringify(d))}else if(o()){if("postMessage"===e){var s={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(s):window.__dcloud_weex_.postMessage(JSON.stringify(s))}var w={type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(w):window.__dcloud_weex_.postMessageToService(JSON.stringify(w))}else{if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:i,pageId:""},"*");if(0===t.length){var u=plus.webview.currentWebview();if(!u)throw new Error("plus.webview.currentWebview() is undefined");var g=u.parent(),v="";v=g?g.id:u.id,t.push(v)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}},"__uniapp__service");else{var c=JSON.stringify(i);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(c,",").concat(JSON.stringify(t),");"))}}},d={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;r("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("redirectTo",{url:encodeURI(n)})},getEnv:function(e){a()?e({uvue:!0}):o()?e({nvue:!0}):window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};r("postMessage",e.data||{})}},s=/uni-app/i.test(navigator.userAgent),w=/Html5Plus/i.test(navigator.userAgent),u=/complete|loaded|interactive/;var g=window.my&&navigator.userAgent.indexOf(["t","n","e","i","l","C","y","a","p","i","l","A"].reverse().join(""))>-1;var v=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var c=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var _=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var m=window.qa&&/quickapp/i.test(navigator.userAgent);var f=window.ks&&window.ks.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var l=window.tt&&window.tt.miniProgram&&/Lark|Feishu/i.test(navigator.userAgent);var E=window.jd&&window.jd.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var x=window.xhs&&window.xhs.miniProgram&&/xhsminiapp/i.test(navigator.userAgent);for(var S,h=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},y=[function(e){if(s||w)return window.__uniapp_x_postMessage||window.__uniapp_x_||window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&u.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),d},function(e){if(_)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(c)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(g){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(v)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(p)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(m){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(f)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.ks.miniProgram},function(e){if(l)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(E)return window.JDJSBridgeReady&&window.JDJSBridgeReady.invoke?setTimeout(e,0):document.addEventListener("JDJSBridgeReady",e),window.jd.miniProgram},function(e){if(x)return window.xhs.miniProgram},function(e){return document.addEventListener("DOMContentLoaded",e),d}],M=0;M<y.length&&!(S=y[M](h));M++);S||(S={});var P="undefined"!=typeof uni?uni:{};if(!P.navigateTo)for(var b in S)i(S,b)&&(P[b]=S[b]);return P.webView=S,P}));
function uniPostMessage(Key,Value){
uni.postMessage({data:{key:Key,data:Value}});
}
4.外部的html中的代码截图:
bash
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UniApp 通信测试 - 初始化参数支持</title>
<style>
body {
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
line-height: 1.6;
}
.btn {
padding: 10px 20px;
background: #007aff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin: 8px 0;
font-size: 16px;
}
#log {
margin-top: 20px;
padding: 15px;
background: #f9f9f9;
border: 1px solid #eee;
border-radius: 6px;
white-space: pre-wrap;
font-family: 'Courier New', monospace;
max-height: 400px;
overflow-y: auto;
font-size: 14px;
}
.highlight { background-color: #e6f7ff; }
</style>
</head>
<body>
<h3>📍 UniApp 双向通信测试(含初始化参数)</h3>
<p>✅ 页面加载时将自动接收 UniApp 传入的参数并弹窗</p>
<button class="btn" onclick="requestLocation()">🔄 获取 UniApp 定位</button>
<div id="log">日志输出:</div>
</body>
<!-- ⚠️ 关键:receiveFromUniApp 必须在 SDK 加载前定义! -->
<script>
// 💡 【第一优先级】暴露全局接收函数(必须早于 uni.webview.js!)
window.receiveFromUniApp = function(data) {
const logEl = document.getElementById('log');
const now = new Date().toLocaleTimeString();
// 日志记录
const line = `[${now}] 📥 收到 UniApp 消息: ${JSON.stringify(data, null, 2)}`;
logEl.innerHTML += '\n' + line;
logEl.scrollTop = logEl.scrollHeight;
console.log('[H5] receiveFromUniApp called with:', data);
console.log('[H5] receiveFromUniApp called with 转为json:', `${JSON.stringify(data, null, 2)}`);
// 🔑 【核心】处理初始化参数
if (data.action === 'initParams') {
const payload = data.payload;
console.log('✅✅✅ 成功获取 UniApp 初始化参数:', payload);
// 👇 弹窗显示(按你需求)
const msg = `【UniApp 初始化参数】\n` +
`👤 用户ID:${payload.userId}\n` +
`🔑 Token:${payload.token}\n` +
`🌐 环境:${payload.env}\n` +
`⏱ 时间戳:${payload.timestamp}`;
alert(msg); // 或改用更美观的 modal
// 📤 回传确认(触发 UniApp 的 echoReceivedData 逻辑)
if (window.uni && typeof uni.postMessage === 'function') {
uni.postMessage({
data: {
action: 'echoReceivedData',
payload: data
}
});
console.log('[H5] 📤 已回传 initParams 确认');
}
return;
}
// 处理定位结果
if (data.action === 'locationResult') {
const { latitude, longitude, accuracy } = data;
const msg = `\n🟢 定位成功!\n纬度: ${latitude}\n经度: ${longitude}\n精度: ${accuracy}米`;
logEl.innerHTML += msg;
alert(`✅ 定位成功!\n纬度:${latitude}\n经度:${longitude}`);
return;
}
// 处理定位失败
if (data.action === 'locationError') {
logEl.innerHTML += `\n🔴 定位失败:${data.message}`;
alert('❌ 定位失败:' + data.message);
return;
}
// 兜底处理
console.warn('[H5] 未知消息类型:', data.action);
};
</script>
<!-- ✅ 加载 Uni Webview SDK(建议本地化!) -->
<script src="./uni.webview.1.5.5.js"></script>
<!-- 若坚持用 CDN(局域网需确保能访问) -->
<!-- <script src="https://js.cdn.aliyun.com/uniapp/1.5.5/uni.webview.1.5.5.js "></script> -->
<script>
// 【增强】监听桥接就绪,并主动通知 UniApp
document.addEventListener('UniAppJSBridgeReady', function() {
log('[H5] 🟢 UniAppJSBridgeReady 触发 --- 桥已就绪');
// 等待 100ms 确保 receiveFromUniApp 已定义(虽已前置,仍保守)
setTimeout(() => {
if (typeof uni !== 'undefined' && uni.postMessage) {
uni.postMessage({
data: { action: 'h5Ready' }
});
log('[H5] 📤 已通知 UniApp:H5 页面就绪,等待初始化参数...');
} else {
log('[H5] ❗uni 未定义,postMessage 不可用');
}
}, 100);
});
// 【兜底】监听 window.postMessage(某些 Android 基座会走此通道)
window.addEventListener('message', function(e) {
if (e.data && e.data.action && typeof window.receiveFromUniApp === 'function') {
log('[H5] 📥 通过 window.postMessage 收到消息(兜底通道)');
receiveFromUniApp(e.data);
}
});
// 按钮功能
function requestLocation() {
if (!window.uni) return alert('❌ 请在 UniApp App 中打开本页面!(当前无 uni 对象)');
uni.postMessage({
data: { action: 'requestLocation' }
});
log('[H5] 📤 已请求定位');
}
// 通用日志函数
function log(msg) {
const el = document.getElementById('log');
el.innerHTML += '\n' + msg;
el.scrollTop = el.scrollHeight;
}
// 页面 load 兜底检查
window.addEventListener('load', () => {
log('[H5] 🟡 页面 load 完成');
if (typeof receiveFromUniApp !== 'function') {
log('[H5] ❗严重错误:receiveFromUniApp 未定义!请检查 JS 加载顺序');
}
});
</script>
</html>
结果展示:
实现双向通信,内部与外部进行数据通信,传递参数:
