flutter_boost 键盘释放导致的崩溃问题

980 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情

日更计划,掏空自己。这篇对最新的 Flutter 版本也还有用,所以放出来给大家避坑。

起因

在之前 Flutter 2.5.3 升级 Flutter 2.10.5 之后的 App 版本,新增了一个奇怪的崩溃问题,如下图

image2022-6-9_15-11-15.png

过程

Flutter 源码定位

看崩溃记录,是在 Flutter 源码上,从 Flutter 源码中找到问题暴露的代码所在处 main 分支下 FlutterTextInputPlugin

崩溃所在代码下图所示:

image2022-6-9_15-14-47.png

看起来问题只能出在 _viewController 上了,_viewController 在这里获取的时候消失了 ...

Why?

想到这个版本之后是升级过 Flutter 版本号,所以就找到相应未升级前的版本(2.5.3)来对比,源码在这:2.5.3 tag 下的 FlutterTextInputPlugin

没有找到 - (UIView *)hostView 的定义,经代码分析得出,以前用的是 - (UIView *)keyWindow 这个方法,如下图:

image2022-6-9_15-17-50.png

那这个差异会导致问题吗?

但测试了几个 Flutter 需要输入框的地方,并没有复现问题。那崩溃是出在哪里?

日志分析

从几个用户的崩溃前日志来辅助排查问题,崩溃是在 Flutter 登录、抠图等,并没有特别的地方。

看了一下它前面的路由日志,发现是从搜索页进入的,搜索页也是 Flutter 开发的,而且搜索栏也会弹出键盘,立马试了一下:

normal-video123.gif

问题复现了,是必现的问题。

而且如果手动隐藏掉第一个键盘,就不会产生崩溃。

问题原因

为什么 hostView 会消失呢?

究其原因,是被 flutter_boost 释放掉了。

看 flutter_boost 的源码,在这里:master 分支下 FBFlutterViewContainer

image.png

如上所示,在 dismiss的时候,会执行以上方法,ENGINE.viewController 会设置为 nil。

由于 flutter_boost 单引擎设计,这个 viewController 就是上一个页面的 viewController,这时候导致上一个页面的 FlutterTextInputPlugin 也丢失了 viewController,导致崩溃。

而在 Flutter 2.5.3 中因为使用的是 keyWindowkeyWindow 对象一直会存在,所以就不会崩溃。

修复方式

flutter_boost 单引擎机制导致不能从根本上解决这个问题的。

只能是检查 flutter_boost 开发的页面中,当页面因为 pushpresent 导致的被隐藏或者失去焦点时,先把键盘释放掉,再执行相应跳转。

我司的修复方式,监听页面跳转事件,然后全局失去焦点,如下:


class AppGlobalPageVisibilityObserver extends GlobalPageVisibilityObserver {
  ...
  
  @override
  void onPagePush(Route route) {
    super.onPagePush(route);

    /// 规避 flutter boost 键盘崩溃
    FocusManager.instance.primaryFocus.unfocus();
  }
  ...
}

这确实是个隐患,不能确定后续开发过程中是否还会重复这样的崩溃问题,也不能确定是否还有类似的问题没有被发现。

后续

确定了 iOS 必现后,后面测试了 Android 上的情况,结果意外是正常的。

所以就了解了一下 flutter_boost Android 上的实现代码

image2022-6-9_15-39-19.png

可以看出,在 Android 上,flutter_boost 是用 detachFromActivity 从 Activity 上移除,而不是简单粗暴的设置 nil ... 所以这坑只有 iOS 会踩上,Android 跳了过去~


感谢阅读,如果对你有用请点个赞 ❤️

中秋节GIF动图引导在看提示.gif