基于uni-app-x 与 uni-app 的安卓与 H5 双向通信完整实现

基于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端)之间的双向通信。

相关推荐
十六年开源服务商1 小时前
2026年WordPress建站新趋势与实战解决方案
android
光影少年1 小时前
react中的Context 为什么会导致性能问题?
前端·javascript·react.js
Z_Wonderful1 小时前
react部署更新后旧 chunk 404、用户浏览器缓存旧页面的问题与(路由跳转使用相对路径而不是绝对路径的关系)分析,并提供解决方案
javascript·react.js·缓存
__Witheart__1 小时前
RK Android OTA USB Upgrade Guide
android
千里马学框架1 小时前
安卓车载手机原生多屏闪黑问题分析及修复成果展示
android·智能手机·性能·多屏·系统开发·aosp·framework工程师
ImTryCatchException1 小时前
Android 渲染流水线全解析:从 Choreographer 到 SurfaceFlinger
android
__Witheart__1 小时前
RK3588 Android15 .gitignore
android
kiritomzzz2 小时前
Vue 插槽(Slot)全解析:从 Vue2 到 Vue3 核心用法与案例
前端·javascript·vue.js
漂流瓶jz10 小时前
Webpack如何实现万物皆可import?loader的使用/配置/手写实践
前端·javascript·webpack