likes
comments
collection
share

Flutter WebView 小记 (白屏、闪退、内存没有释放)

作者站长头像
站长
· 阅读数 15

转载请注明原文链接:juejin.cn/post/720982…

前置条件

Flutter WebView 的更新频率是很快的,也许文中提到的问题,在后面的版本不会有,所以先说明下环境和版本。 此外,使用 WebView 的方式也可能是出现这些异常的因素,使用 FlutterBoost、嵌套、写死高度等。

Flutter WebView 小记 (白屏、闪退、内存没有释放)

Flutter WebView 小记 (白屏、闪退、内存没有释放)

具体问题

  1. 鸿蒙系统、部分oppo、vivo系统,使用 loadHtmlString 加载含图片的本地富文本出现闪退;
  2. 针对 Android 使用 displayWithHybridComposition 的方式加载存在“第二次打开Flutter页时,出现上次 WebView 残留问题“;

问题定位和解决方案

白屏和闪退

  • 定位:因为上述系统都是“阉割版”升级,系统版本升级到了 23 但是 WebView 内核并没有同步到 Google 官方最新版本,直接导致 TextureSurfaceView 崩溃(参考官方文档:texture-layer-hybrid-composition);

  • 解决方案:

    if (WebViewPlatform.instance is WebKitWebViewPlatform) {
      return WebViewWidget(controller: checkedController);
    } else {
      return WebViewWidget.fromPlatformCreationParams(
        params: AndroidWebViewWidgetCreationParams(
          controller: checkedController.platform,
          //针对鸿蒙系统使用 displayWithHybridComposition 为 true
          displayWithHybridComposition: Constants.isHarmony,
        ),
      );
      // return AndroidWebViewWidget(
      //   AndroidWebViewWidgetCreationParams(
      //     controller: checkedController.platform,
      //     displayWithHybridComposition: true,
      //   ),
      // ).build(context);
    }
    

残留或内存没有释放

  • 定位:这一点没有找到官方解释,有可能是 FlutterBoost 影响了生命周期导致没有释放,也有可能是使用 displayWithHybridComposition 时,Android WebView 是一个单例,也许两者都有,总之是暂未有定论。(之前看到 FlutterBoost 更新说明提到: [Android] Fixes HybridCompositon does not work (#1743),然并卵)

  • 解决方案:(有两个思路)

    • WebView 是单例,那么针对使用Hybird的情况,在每个Flutter页面初始化一个空的 WebView 就可以去掉残留(这个是个坏的解决方案)。

    • 使用 WebViewFlutterAndroidExternalApi ,在原生端获取到Flutter端的WebView,在 Activity onDesroty 时释放 WebView,如下:

      override fun onDestroy() {
          Ulog.i("ToFlutterContainerActivity onDestroy in")
      //exclusiveAppComponent?.
          FlutterNativeBridge.mEngine?.also { flutterEngine ->
                  FlutterNativeBridge.invokeFlutterWebViewIdentifierList { webViewIds ->
                      webViewIds.forEach { identifier ->
                              WebViewFlutterAndroidExternalApi.getWebView(
                                  flutterEngine, identifier
                              )?.also { webView ->
                          ULog.i("ToFlutterContainerActivity in webView.destroy: $identifier")
                         // webView.destroy()
                          if(webView.parent is ViewGroup){
                              ULog.i("ToFlutterContainerActivity in webView.removeView: $identifier")
                              (webView.parent as ViewGroup).removeView(webView)
                              webView.destroy()
                          }
                      }
                  }
              }
          }
          super.onDestroy()
      }
      

小结

有两个点

一个是混编如果可以最好用官方的试试,FlutterBoost 不太放心,而且存在很多和官方设计思维不太匹配的问题;

一个是 WebView 的嵌套实现,由于时间问题,其实不应该这么简单的计算方式,可以试试这个extended_sliver的思路