Xcode12.3适配iOS12.4+应用中WKWebView内JS动画锁屏后冻结问题咨询
问题核心根因
- 系统层面对WKWebView的调度存在场景差异:iOS12.4~iOS14.x版本区间(刚好对应Xcode12.3的适配范围)下,普通Home键切后台和锁屏操作虽然触发的UIApplication生命周期回调完全一致,但系统对WKWebView所属的WebContent渲染进程的处理逻辑天差地别。普通切后台时,系统只会给应用施加CPU、网络的配额限制,不会冻结WebKit的渲染线程任务队列和JS事件循环;但锁屏属于系统级安全状态变更,系统会直接挂起WebContent进程的GPU合成权限、冻结所有待执行的渲染帧任务和JS定时器队列——整个过程不会向应用层抛出任何区分性的额外回调,这也是你排查时觉得两个场景完全没差异的核心原因。
- 动画冻结的直接触发机制:你的页面动画是通过动态给DOM元素添加
start/finish/状态值对应的CSS class触发实现的,这类CSS动画的执行完全依赖WebKit渲染线程的帧回调调度。一旦锁屏触发进程冻结,已经入队的渲染任务会被整体挂起,解锁返回前台后被冻结的任务队列不会自动恢复执行,最终就表现为动画停转、所有前端实时更新逻辑全部冻结。 - 现有业务逻辑的放大效应:当前的动画触发逻辑是在Framework侧完成数据处理后,通过一次性JS注入同步修改DOM class来完成的,既没有在应用回到前台时做渲染状态的一致性校验,也没有配套的唤醒兜底逻辑,导致一旦渲染线程被冻结,哪怕后续JS上下文可以正常执行,之前被挂起的渲染状态也无法自动恢复。
适配环境的可落地方案(支持iOS12.4+、Xcode12.3)
- 独立识别锁屏场景,绕开通用生命周期的混淆:既然两个场景的通用生命周期完全一致,就不要靠
didEnterBackground/willEnterForeground这类通用回调做判断,直接注册系统针对受保护数据访问权限的专属通知来识别锁屏/解锁流程,普通Home键切后台完全不会触发这两个通知:- 锁屏触发通知:
UIApplication.protectedDataWillBecomeUnavailableNotification - 解锁回前台通知:
UIApplication.protectedDataDidBecomeAvailableNotification
- 锁屏触发通知:
- 解锁事件触发时做WebView的强制唤醒:
- 解锁检测到后,首先通过JS注入执行一段强制渲染调度的代码,比如
setTimeout(() => { void document.body.offsetHeight }, 0),强制WebKit重新唤起被冻结的渲染线程任务队列,打破进程挂起状态。 - 重新执行一次你现有的状态同步JS注入流程,把当前页面应该展示的class状态、实时数值重新同步到DOM上——之前注入的class修改操作虽然会写入DOM属性,但对应的CSS动画计算在冻结状态下没有完成,重新触发一次class的移除、再添加操作,可以强制动画重新计算渲染状态。
- 针对iOS12.x上的WKWebView已知bug,可以短暂将WKWebView的
isHidden属性设为YES再恢复为NO,强制WebKit重新挂载渲染图层,这个操作在低版本iOS上的唤醒效率比单纯的JS注入更高。
- 解锁检测到后,首先通过JS注入执行一段强制渲染调度的代码,比如
- 前端侧的兜底适配:在HTML页面代码中增加
visibilitychange事件监听,当页面从隐藏状态切回可见状态时,主动记录所有正在运行的动画的当前进度,清空之前被冻结的动画队列,根据当前存储的状态值重新计算动画进度,不要依赖已经被冻结的旧队列继续执行逻辑。 - 注意规避常见误区:不要通过重载整个页面的方式解决这个问题,重载会直接丢失当前页面的所有交互状态,用户体验损耗非常大。
内容的提问来源于stack exchange,提问作者Kouv
相关产品推荐
相关产品推荐

