基于uni-app-x 与 uni-app 的安卓与 H5 双向通信完整实现
安卓app---uni-app-x
h5网页---uni-app
一、安卓端代码实现
App 端通过 <web-view> 的 @message 事件接收h5网页的数据。
App端通过Webview实例?.evalJS 向h5网页通信
vue
<template>
<!-- 需要给高度 -->
<web-view ref="myWebview" id="web-view" @message="onMessage" style="height:90%" @load="load" @error="error"
src="h5网页的链接,localhost的时候确保在同一ip地址下"></web-view>
<view style="height:5%" @click="send">点击给H5发送数据</view>
<view style="height:5%" @click="sendAlert">点击让h5弹出提示</view>
</template>
<script setup>
import { ref } from 'vue'
const myWebview = ref<UniWebViewElement | null>(null);
let webviewElement = null as UniWebViewElement | null;
onReady(() => {
webviewElement = uni.getElementById('web-view') as UniWebViewElement
})
onUnload(() => {
webviewElement = null;
})
const load = () => {
console.log("load");
};
// 点击让h5弹出提示
const sendAlert = () => {
console.log("sendAlert");
webviewElement?.evalJS("alert('我被app主动提示了')");
}
const send = () => {
const sendWebview = myWebview.value;
const data =
{
code: 0,
action: "app",
msg: "不吃香菜"
}
;
// 调用 H5 全局函数(H5 需提前定义 window.handleAppReply)
const replyScript = `
if (window.handleAppReply) {
window.handleAppReply(${JSON.stringify(data)});
}
`;
console.log('点击发送数据', sendWebview);
// 通过 evalJS 执行 H5 函数,传递回复数据
sendWebview?.evalJS(replyScript);
}
const error = (e : UniWebViewErrorEvent) => {
console.log("error", e.detail);
};
const onMessage = (e : UniWebViewMessageEvent) => {
const { data } = e.detail;
if (data.length > 0) {
const item = data[0];
const action = item['action'] as string;
if (action == "back") {
console.log("判断结果: true");
uni.showToast({
title: item['msg'] as string,
icon: "none"
})
setTimeout(() => {
uni.navigateBack({
})
}, 1000);
} else {
console.log("判断结果: false, action值为:", action);
}
}
};
</script>
<style>
</style>
二、h5端代码实现
1.准备uni.webview.1.5.8.js
这是h5与app通信的关键源码如下 也可从官网下载,放到项目的static文件夹下
js
!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)}Object.assign({},{unit:"rem",unitRatio:10/320,unitPrecision:5});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(),c="";c=g?g.id:u.id,t.push(c)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}},"__uniapp__service");else{var v=JSON.stringify(i);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(v,",").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){if(a()){var n=navigator.userAgent.includes("uni-app"),i=navigator.userAgent.includes("OpenHarmony"),t={uvue:!0};n&&i&&(t.harmony=!0),e(t)}else 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 c=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var v=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.ascfwebProxy&&window.ascfwebProxy.invokeJsApi&&/ASCF/i.test(navigator.userAgent);var l=window.ks&&window.ks.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var E=window.tt&&window.tt.miniProgram&&/Lark|Feishu/i.test(navigator.userAgent);var y=window.jd&&window.jd.miniProgram&&/jdmp/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}))},b=[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(v)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(g){"loading"!==document.readyState?setTimeout(e,0):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(c)return"loading"!==document.readyState?setTimeout(e,0):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 document.addEventListener("DOMContentLoaded",e),Object.assign({},window.has,window.has.ascfweb)},function(e){if(l)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.ks.miniProgram},function(e){if(E)return"loading"!==document.readyState?setTimeout(e,0):document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(y)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}],P=0;P<b.length&&!(S=b[P](h));P++);S||(S={});var M="undefined"!=typeof uni?uni:{};if(!M.navigateTo)for(var T in S)i(S,T)&&(M[T]=S[T]);return M.webView=S,M}));
2.在项目的index.html中引入并使用
handleAppReply全局回调方法 需要跟app端对应保持一致
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<link rel="icon" href="/static/logo.png" />
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.ts"></script>
<!-- 打包到服务器后 去掉/src -->
<script type="text/javascript" src="/static/uni.webview.1.5.8.js"></script>
<script type="text/javascript">
// 提前定义全局回调
window.handleAppReply = function(data) {
console.log('收到 App 回复', data);
if (data && data.code === 0) {
// 注意:这里不能用 uni.showToast,因为 uni 可能还没初始化
// 用原生方式提示
alert('保存数据: ' + (data.msg || ''));
} else {
alert((data && data.msg) || '未知错误');
}
};
// 验证脚本是否加载成功(调试关键:控制台打印 webViewJs 确认)
const webViewJs = window.uni?.webView;
if (!webViewJs) {
// alert('uni.webview.js 加载失败!请检查路径是否正确');
console.error('uni.webview.js 加载失败!请检查路径是否正确');
} else {
// alert('通信桥梁已就绪11',webViewJs);
console.log('uni.webview.js 加载成功', webViewJs);
// 将 webViewJs 挂载到 window 全局,供 Vue 组件访问
window.webViewJs = webViewJs;
}
</script>
</body>
</html>
以上代码完整实现了 uni-app-x(安卓端)与 uni-app(H5端)之间的双向通信。