移动端开发踩坑记录(持续记录中···)

2023-10-10 13:10

本文主要是介绍移动端开发踩坑记录(持续记录中···),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这里记录一下近期开发移动端时遇到的一些坑,以前没这个意识,现在突然想总结一下!
在这里插入图片描述

一、微信页面或者内嵌h5页面,上传图片时候,页面刷新闪退或者webview直接刷新,最终导致页面填充数据丢失问题

现象:
1、在上传组件中(哪怕是最简单的),当选择好本地图片或者调取系统摄像头拍好照片后,网页被刷新。这一问题无法100%重现,但概率不低,在如红米等低端安卓机上发生的概率会比较高。
2、与用系统自带的浏览器打开的情况相比,在微信中打开的情况下该问题出现的更为频繁。
3、与选择本地图片上传相比,调取系统摄像头拍照上传的情况下该问题出现的更为频繁。

原因:
1、当在Android的浏览器上调用文件上传功能时,Android系统将把当前进程从“浏览器”切换到“文件选择器”(根据不同的用户选择,这一新的进程可能是图片选择器,也可能是系统摄像头,或者其它别的),此时浏览器进程将变为后台进程。
2、由于Android操作系统的设计缺陷,此时浏览器进程的留存优先级(不被系统kill掉的优先级)与所有其它的后台进程是一样的,因此如果操作系统认为内存不足需要进行清理,此时浏览器进程将不会得到任何保护 – 很不幸,因为浏览器占用内存一般都比较大,所以这次kill操作很容易kill掉浏览器进程。
3、当用户选择好图片返回浏览器时,浏览器进程已经不复存在了,按照Android的机制,浏览器进程将进行恢复,试图恢复到kill之前的状态 – 很不幸,恢复到什么状态是由浏览器来决定的,而浏览器不可能100%恢复到选择文件之前的那个状态。因此最终用户所看到的现象就是:选择文件完成后,浏览器刷新了一下,而刷新到什么状态由浏览器决定。
4、对于这一问题,Android技术团队的态度是回避(将bug标记为obsolete) – 可能是因为此bug涉及了OS底层进程切换的机制,修复起来风险太高;而随着手机设备内存容量的增大,这一问题所发生的概率会越来越小。
5、理解了问题的原因,对问题的一些表征也就有了合理的解释:低端安卓机的内存更小,因此发生问题的频率更高;而与选择本地图片相比,调取系统摄像头所耗的内存更大(当拍摄有大量文字的图片时尤其如此),因此调取摄像头时问题发生的更加频繁;当用户已经开了很多别的App时,问题发生的概率更大。

解决办法:
目前感觉也没什么好的解决办法,前端针对此问题,只能尽可能的去优化用户体验了;
建议做法是,监控用户上传图片的操作,在上传图片之前,对表单数据进行缓存。这样可以针对上传之后的表现去做相应的处理;
如果上传的时候,页面闪退了或者webview刷新了,再次进入此页面的时候,判断缓存存在,则弹出用户内存太小,请清除内存再操作上传图片等友好提示,然后回填数据(将上传图片改为不必填)后,将缓存清除;
如果上传的时候,没有出现闪退刷新情况,则在上传图片完成之后,清除缓存即可;

二、微信、企微内嵌h5登录授权重定向之后,退出应用需要后撤两次问题

现象以及原因:
1、这里要提一下h5微信登录授权的流程:
(1)微信或者企微跳转到h5线上地址,h5空白授权页或者路由守卫中判断当前url中是否含有code;
(2)code存在,则通过code向后台获取token实现登录;code不存在,则拼接微信授权地址并通过location.href进行跳转
location.href = https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect
(3)location.href跳转之后,微信授权成功后,会拼接code跳回h5,h5拿到code通过code获取token登录成功;
在这里插入图片描述
2、登录成功之后,由于授权的这一系列重定向操作,使得当前路由历史栈中多了一个微信授权地址的路由,导致在h5应用中,点击后退按钮或者手势退出时,会回到微信授权地址,出现无限重复授权的情况,需要操作两次后退才能退出当前h5应用
在这里插入图片描述

不使用location.replace的原因:
刚开始是考虑使用location.replace()来替代location.href跳转,后面发现怎么调试都没有效果,根本原因是因为location.replace在微信浏览器中不生效,而且ios,安卓,微信开发者工具里使用location.replace的表现不一致
ios真机:location.replace完全不起作用,效果等同于location.href , 页面栈中会存在一个无code的授权页,有code的授权页
在这里插入图片描述
安卓真机与微信开发者工具:页面栈中会存在一个无code的授权页
在这里插入图片描述
从location.replace产生的页面栈其实也可以看出来,解决这个问题的关键在于,在知道用户执行了返回操作时,根据页面栈的数量,执行js方面的页面后撤多次并关闭应用即可。
这里就涉及到了如何去知道用户在首页或者说第一个子页面中,执行了返回操作
若是在react项目中,没有路由守卫,那肯定是有一个空白授权页存在的,即微信授权登录逻辑所在的页面。
若是在vue项目中,一般都是在路由守卫中拦截并执行微信授权登录逻辑的。
这里延申一个知识点,那就是window.history.pushState(state, title, url);,这个方法可以在不刷新页面的情况下,直接更改页面的url,然后可以通过window.addEventListener(‘popstate’, handleGoBack, false)事件去监控页面url的回退,所以可以用这个办法来监控页面的回退,但是这个方法也存在一个缺陷,那就是在安卓端微信浏览器中,如果页面无交互,则默认不会触发onPopstate事件,在ios中则无影响······

const useReturnApp = () => {let timer = setTimeout(() => {document.addEventListener('WeixinJSBridgeReady',() => {if (window.WeixinJSBridge) window.WeixinJSBridge.call('closeWindow')},false,)if (window.WeixinJSBridge) window.WeixinJSBridge.call('closeWindow')clearTimeout(timer)timer = null}, 100)const router = useRouter()if (ios) {router.go(-2)} else {router.go(-1)}
}// vue3中自定义hook,使用pushState结合popstate事件监控页面操作退出
// 不过popstate在安卓端微信浏览器中,如果页面无交互,则默认不会触发
export const useFixExitApp = (props) => {const { onGoBack, isListen = true } = props || {}const handleGoBack = () => {if (onGoBack && onGoBack instanceof Function) {onGoBack()} else {useReturnApp()}}const AddListenPopstate = () => {const flag =isListen && isListen instanceof Function ? !!isListen() : !!isListenif (window.history && window.history.pushState && flag) {// 该方法仅可解决安卓机型下x5内核webview浏览器中的popstate默认不触发的bug// https://developers.weixin.qq.com/community/develop/doc/000a2a57968cc0bc9d7aa0b6b5b800const { type } = useGetAppType()if (type !== 'IOS') {try {window.tbs_bridge.nativeExec('network', 'type', 0, null)} catch (e) {console.error('weixin network:', e)}}window.history.pushState(null, null, document.URL)window.addEventListener('popstate', handleGoBack, false)}}const removeListenPopstate = () => {window.removeEventListener('popstate', handleGoBack, false)}onMounted(() => {AddListenPopstate()})onUnmounted(() => {removeListenPopstate()})
}// 在有code的页面调用登录接口成功之后,我们向sessionStorage中存一个临时值再跳转到子页面,然后修改空白授权页的初始化逻辑即可:
// 演示代码
const code = getSearchParams("code") // 获取url search中的code
const signValue = sessionStorage.getItem(signValueKey)
if (signValue) {// 进行返回逻辑sessionStorage.removeItem(‘key’)useReturnApp()
} else {if (!code) {// 没有code,跳转微信授权oauth地址location.replace("微信授权地址")}else {// 有code,调用登录接口$.ajax(login_api, {data: {code}}).then(res => {// 储存临时值sessionStorage.setItem(‘key’, code)// 跳转到子页面location.replace(子页面地址)])}
}

三、移动端h5页面布局,ios中布局存在差异问题,归根结底还是底部安全距离和position:fixed问题

现象以及解决办法:
1、在移动端h5项目中,ios刘海屏系列手机,会出现一个包含在100vh中的底部遮挡区域,这块区域则是所谓的安全距离

// 比如经常用到的底部安全距离样式设置
height: calc(100vh - constant(safe-area-inset-bottom));
height: calc(100vh - env(safe-area-inset-bottom));
// or
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);

2、在移动端h5项目中,ios不支持fixed定位,会导致fixed的元素位置错乱,这时候结合业务实际,可以使用postion:absolute来替代

四、移动端h5在ios特有的橡皮筋效果,有时候会导致底部按钮,在页面滚动到底部的时候,一直往上拉,出现橡皮筋效果,导致按钮被遮挡等体验不好的问题

现象以及解决办法:
1、现象如上,这里推荐使用inobounce插件,禁用橡皮筋效果来解决此问题

// npm install inobounce -s
import inobounce from 'inobounce'onMounted(() => {// 开启禁用if (appType === 'IOS') inobounce.enable()
})onUnmounted(() => {// 关闭禁用if (appType === 'IOS') inobounce.disable()
})

五、移动端h5内容比较多,产生滚动条的时候,在textarea元素上滚动,会因为textarea自带的滚动事件与页面的滚动事件重叠,导致滚动失效,造成卡顿现象的问题

现象以及解决办法:
1、现象如上,这里只需要在textarea上设置overflow: hidden即可解决此问题;

在这里插入图片描述

这篇关于移动端开发踩坑记录(持续记录中···)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/180647

相关文章

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

统一返回JsonResult踩坑的记录

《统一返回JsonResult踩坑的记录》:本文主要介绍统一返回JsonResult踩坑的记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录统一返回jsonResult踩坑定义了一个统一返回类在使用时,JsonResult没有get/set方法时响应总结统一返回

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

java对接海康摄像头的完整步骤记录

《java对接海康摄像头的完整步骤记录》在Java中调用海康威视摄像头通常需要使用海康威视提供的SDK,下面这篇文章主要给大家介绍了关于java对接海康摄像头的完整步骤,文中通过代码介绍的非常详细,需... 目录一、开发环境准备二、实现Java调用设备接口(一)加载动态链接库(二)结构体、接口重定义1.类型

基于Python开发一个有趣的工作时长计算器

《基于Python开发一个有趣的工作时长计算器》随着远程办公和弹性工作制的兴起,个人及团队对于工作时长的准确统计需求日益增长,本文将使用Python和PyQt5打造一个工作时长计算器,感兴趣的小伙伴可... 目录概述功能介绍界面展示php软件使用步骤说明代码详解1.窗口初始化与布局2.工作时长计算核心逻辑3

apache的commons-pool2原理与使用实践记录

《apache的commons-pool2原理与使用实践记录》ApacheCommonsPool2是一个高效的对象池化框架,通过复用昂贵资源(如数据库连接、线程、网络连接)优化系统性能,这篇文章主... 目录一、核心原理与组件二、使用步骤详解(以数据库连接池为例)三、高级配置与优化四、典型应用场景五、注意事

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1

SpringBoot实现文件记录日志及日志文件自动归档和压缩

《SpringBoot实现文件记录日志及日志文件自动归档和压缩》Logback是Java日志框架,通过Logger收集日志并经Appender输出至控制台、文件等,SpringBoot配置logbac... 目录1、什么是Logback2、SpringBoot实现文件记录日志,日志文件自动归档和压缩2.1、