App使用webview套壳引入h5(三)——解决打包为app后在安卓机可物理返回但是在苹果手机无法测滑返回的问题

发布于:2025-06-06 ⋅ 阅读:(22) ⋅ 点赞:(0)

话不多说,直接放最终版本代码。

解决思路是:如果设备是ios设备在myH5中监听 touchstart 和touchend事件

经过 App使用webview套壳引入h5的最终代码如下
myApp中,entry.vue代码如下:

<template>
	<view class="entry-page" :style="{ paddingTop: safeAreaInsets.top + 'px' }">
		<web-view :webview-styles="webviewStyles" :src="webviewUrl" @message="getH5Message" ref="webViewRef"></web-view>
	</view>
</template>

<script>
export default {
	data() {
		return {
			statusBarHeight: 100,
			safeAreaInsets: {},
			webviewUrl: 'myLink', 
			hasBottomSafeArea: false,
			webviewStyles: {
				progress: {
					color: '#007aff',
					top: 0
				},
				// iOS侧滑返回配置
				ios: {
					allowsBackForwardNavigationGestures: true, // 启用WKWebView侧滑手势
					bounces: false // 禁用弹性效果
				}
			},
			webview: '',
			isIOS: false,          // 判断是否为iOS设备
			webviewCanBack: false  // WebView是否可返回
		};
	},
	onReady() {
		var currentWebview = this.$scope.$getAppWebview().children()[0];
		this.webview = currentWebview; // 缓存WebView实例
		
		currentWebview.addEventListener('loaded', () => {			currentWebview.evalJS('$("ul.fed-part-rows a[href*=\'resource.i847.cn\']").parent().hide();');

		});
	},
	onLoad(options) {
		// #ifdef APP-PLUS
		this.isIOS = uni.getSystemInfoSync().platform === 'ios'; // 检测iOS设备
		
		let _this = this;
		let height = 0;
		let statusbar = 0;
		const sysInfo = uni.getSystemInfoSync();
		this.safeAreaInsets = sysInfo.safeAreaInsets;
		console.log('top--------', sysInfo);
		this.statusBarHeight = sysInfo.statusBarHeight;
		height = sysInfo.windowHeight;
		let currentWebview = this.$scope.$getAppWebview();
		
		setTimeout(() => {
			var wv = currentWebview.children()[0];
			console.log('top--------222222222', _this.statusBarHeight);
			wv.setStyle({
				top: _this.statusBarHeight,
				height: height - _this.statusBarHeight,
				scalable: false
			});

		}, 200);
		// #endif
	},
	onBackPress(e) {
		// 响应返回事件(关键修改,此处测试发行仅在打包为安卓的情况下可响应onBackPress)
		if (this.isIOS) {
			// iOS设备:优先WebView内部返回
			if (this.webviewCanBack) {
				this.webview.back(); // WebView返回上一级H5页面
				return true; // 拦截默认返回
			}
		}
		
		// 其他情况执行原有逻辑
		this.webView = this.$mp.page.$getAppWebview().children()[0];
		this.webView.evalJS('window.getPageUrl()');
		return true;
	},
	methods: {
		test() {
			console.log('test webview');
		},
		dealBackEvent() {
			console.log('dealBackEvent webview');
		},
		showCurrentPage(pageInfo) {
			console.log('showCurrentPage', pageInfo);
			if (pageInfo.pathname) {
				const targetArray = ['pages/index/index', 'tab页2', 'tab页3'];
				const processedString = pageInfo.pathname.replace('myLink地址中的页面公共路径', '');
				const exists = targetArray.includes(processedString);

				if (exists) {
					console.log('showCurrentPage ----------1');
					uni.showModal({
						title: '提示',
						content: '确定要退出吗?',
						success: (res) => {
							if (res.confirm) {
								plus.runtime.quit();
							}
						}
					});
				} else {
					console.log('showCurrentPage ----------2');
					// 优先WebView返回(关键修改)
					if (this.webviewCanBack) {
						this.webview.back();
					} else {
						this.webView.back();
					}
				}
			}
		},
		getH5Message(e) {
			console.log('来自webview的消息*******************', e);
			var item = e.detail.data[0];
			switch (item.type) {
				case 'back':
					this.operation();
					break;
				case 'outApp':
					this.back();
					break;
				case 'isFun':
					this[item.action](item.message);
					break;
				case 'historyChange':
					// 接收H5历史变化通知(关键修改)
					this.webviewCanBack = item.data.canBack;
					break;
				case 'iosBack':
					// 接收iOS返回通知(关键修改)
					if (!item.data.canBack) {
						uni.navigateBack();
					}
					break;
				default:
					uni.showToast({
						title: item.message,
						duration: 2000
					});
					break;
			}
		},
		operation() {
			// #ifdef APP-PLUS
			this.webView = this.$mp.page.$getAppWebview().children()[0];
			console.log('operation********', this.webView);
			// #endif
		},
		back() {
			uni.showModal({
				title: '提示',
				content: '是否退出系统?',
				success: function (res) {
					if (res.confirm) {
						plus.runtime.quit();
					} else if (res.cancel) {
						console.log('用户点击取消');
					}
				}
			});
		}
	}
};
</script>

<style>
.entry-page {
	background-color: #f8f8f8;
}

.webview-container {
	flex: 1;
	width: 100%;
}
</style>

myH5项目中
记得引入webviewJs,参考 App使用webview套壳引入h5(一)
App.vue的代码如下

<script>
	export default {
		data() {
			return {
				isIos: false,
				transitionName: '', // 过渡动画的名称
				startPosition: {
					x: 0,
					y: 0
				}, // 手势开始时的位置
			};
		},
		created() {
			console.log("at app created---0", this.startPosition);
			// 初始化数据
			this.startPosition = {
				x: 0,
				y: 0
			};
			this.isIOS = uni.getSystemInfoSync().platform === 'ios'; // 检测iOS设备
			console.log("at app created---1", this.startPosition,this.isIOS);
		},
		mounted() {
			console.log("at app mounted---0", this.startPosition);
			let that = this
			// 使用$nextTick确保DOM和数据完全初始化后执行
			this.$nextTick(() => {
				console.log("at app mounted---1", that.startPosition);
				console.log("at app mounted---2", that.startPosition.x);

				// 初始化事件监听
				that.initEventListeners();
			});
		},
		methods: {
			// 将事件监听逻辑提取为单独的方法
			initEventListeners() {
				if (this.isIOS) {
					// 监听touchstart事件
					window.addEventListener('touchstart', (event) => {
						this.handleTouchStart(event);
					});

					// 监听touchend事件
					window.addEventListener('touchend', (event) => {
						this.handleTouchEnd(event);
					});
				}
				// 确保uni对象存在后执行初始化
				this.initUniAppBridge();

			},

			// 处理touchstart事件
			handleTouchStart(event) {
				this.startPosition.x = event.touches[0].pageX;
				this.startPosition.y = event.touches[0].pageY;
			},

			// 处理touchend事件
			handleTouchEnd(event) {
				const endPosition = {
					x: event.changedTouches[0].pageX,
					y: event.changedTouches[0].pageY,
				};

				// 计算手势滑动的距离
				const deltaX = endPosition.x - this.startPosition.x;
				const deltaY = endPosition.y - this.startPosition.y;
				console.log("touchend---------2");
				// 判断滑动方向与滑动距离是否符合返回操作的条件
				if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 30) {
					if (deltaX > 0) {
						// 获取当前路由栈的长度
						const pages = getCurrentPages();
						const stackLength = pages.length;
						console.log('[H5] popstate触发,历史长度:', window.history.length, this.$router, stackLength);
						// 向右滑动,执行返回上一页的操作
						this.transitionName = 'slide-right';
						// this.$router.go(-1);
						uni.navigateBack()
					}
					// else if (deltaX < 0) {
					//         // 向左滑动,执行前进一页的操作
					//         this.transitionName = 'slide-left';
					//         this.$router.go(1);
					//       }
				}
			},

			// 初始化与uni-app的桥接
			initUniAppBridge() {
				// 和webview进行网页通信
				document.addEventListener('UniAppJSBridgeReady', () => {
					uni.webView.getEnv((res) => {
						console.log('当前环境:' + JSON.stringify(res));
					});
					uni.webView.postMessage({
						data: {
							message: '我是来自H5的消息',
							action: 'test',
							type: 'isFun'
						}
					});
				});

				window.getPageUrl = (arg) => {
					uni.webView.postMessage({
						data: {
							action: 'showCurrentPage',
							message: location,
							type: 'isFun',
						}
					});
				};
			},
		},
		beforeDestroy() {
			if (this.isIos) {
				// 移除所有事件监听
				window.removeEventListener('touchstart', this.handleTouchStart);
				window.removeEventListener('touchend', this.handleTouchEnd);
			}
		}
	}
</script>

<style lang="scss">
</style>

网站公告

今日签到

点亮在社区的每一天
去签到