uniapp加载外部网页

uniapp加载外部网页

在开发app的时候,有些时候需要支持跳转到外部网页,那么就要用到webview来实现。

web-view 是一个 web 浏览器组件,可以用来承载网页的容器,会自动铺满整个页面(nvue 使用需要手动指定宽高)。

最近,有个需求是跳到外部网页,外部网页使用的是react技术。

图1
图2

· 跳转webview

// 获取webview地址
const { webviewUrl,host } = await postWebViewDataConfigSimpleQuery()
				if(!webviewUrl){
					return
				}
				uni.navigateTo({
					url:`/pages/vehicle/secondhand-car/webview-auction/webview-auction?webviewUrl=${webviewUrl}&host=${host}`
				})

· webview样式设置以及设置鉴权

<template>
	<view v-show="isShow">
		<web-view :src="state.src" :webview-styles="state.wbStyles" @message="handlePostMessage"></web-view>
	</view>
</template>

const { proxy } = getCurrentInstance()
const { windowHeight, statusBarHeight } = uni.getSystemInfoSync()

// 用户存储信息
const store = useAuthStore()
let state = reactive({
	title: '聚合拍卖',
	wbStyles: {
		top: statusBarHeight,
		height: windowHeight - statusBarHeight
	},
	src: '',
	host: ''
})
const canBack = ref(false)	// 返回键控制
const isShow = ref(false)

let wv; 
onBackPress(()=> {
	if (wv && canBack.value) {
		wv.back();
		return true;
	}
	return false;
})

onReady(() => {
	setEvalJS()
})

onLoad(async (option) => {
	uni.showLoading()
	state.src = option.webviewUrl
	state.host = option.host
})

/**
 * 设置webview的JS信息
 */
async function setEvalJS(){	
	// #ifdef APP-PLUS
	try {
		let currentWebview = proxy.$scope.$getAppWebview(); //获取当前web-view
		setTimeout(async function() {
			wv = currentWebview.children()[0];
			const {token,ycpSecretKey:secret} = await postYcpTokenEncrypte()
			if(!token || !secret){
				return
			}
			// const needReload = !globalThis.reloadStartTime || (globalThis.reloadStartTime && (Date.now() - globalThis.reloadStartTime > 5 * 60 * 60))	// 跳转网页的时候5小时刷新一次。因为不刷新cookie不能携带到请求头上,但是也无需每次跳转网页都刷新,有设置cookie就间隔一段时间刷新就好
			const needReload = true	// 调试写死
			const reloadFn = needReload ? `setTimeout(function(){location.reload()})` : ``
            // storeCookies是对方页面提供设置cookie的方法
			const js = `storeCookies({host:'${state.host}',token:'${token}',secret:'${secret}'});${reloadFn}`
			if(!globalThis.reloadStartTime){
				globalThis.reloadStartTime = Date.now()
			}
			wv.evalJS(js)
			setTimeout(function(){
				isShow.value = true
				uni.hideLoading()
			},500)
			wv.addEventListener(
                'progressChanged',
                function(e) {
                    wv.canBack
					(function(e) {
                        canBack.value = e.canBack;
                    });
                },
                false
            );
		},1000); //如页面初始化调用需要写延迟
	} catch (error) {		
		proxy.$toast(error)
	}
	// #endif
}

· 处理webview返回操作


// 接收到的webview消息
function handlePostMessage(event) {
	try {
		const data = event.detail.data || []
	    data.forEach((item) => {
	      if(item.eventName === "TopPageBackBtnClicked") {
			wv.close()
			setTimeout(()=>{
				uni.navigateBack()
			},100)
		  }
	    })
	} catch (error) {
		proxy.$toast(error)
	}
}

· 开发中遇到的问题记录

问题1:拼写错误。注意正确拼写evalJS,而非evalJs,刚开始用evalJs一直未能执行webview页面的方法,catch也未捕获到错误代码,在使用evalJS(`alert(123)`)调试,才发现是拼写错误。

问题2:执行先后顺序问题。调用webview页面的storeCookies方法前已经执行了接口请求方法,而接口请求因为没有携带依赖cookie,所以页面弹出来’cookie为空,请重新登录’的提示。

解决方式是先隐藏webview页面,执行storeCookies方法并使用浏览器的reload方法刷新页面,再显示webview页面

图3

问题3:App 端使用 uni.web-view.js 的最低版为 uni.webview.1.5.4.js刚开始使用1.5.2,该版本没有uni.postMessage方法,无法发送事件给app监听。

图4

问题4:webview页面在IOS系统手机与Android系统手势返回行为不一致。进入webview页面的二级页面,Android可以返回到首页,而iOS则返回到了app。解决方案是监听返回行为,重新处理返回。上述代码未解决该问题。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注