转载请注明原文链接:juejin.cn/post/720982…
前置条件
Flutter WebView 的更新频率是很快的,也许文中提到的问题,在后面的版本不会有,所以先说明下环境和版本。 此外,使用 WebView 的方式也可能是出现这些异常的因素,使用 FlutterBoost、嵌套、写死高度等。
-
使用 FlutterBoost 混编版本:4.2.0
-
Flutter 版本:Flutter 3.7.2 • channel stable
-
Dart版本: Dart 2.19.2 • DevTools 2.20.1
-
Flutter Pub:
- webview_flutter: ^4.0.6
- webview_flutter_android: ^3.4.2
- webview_flutter_wkwebview: ^3.2.1
- webview_flutter_platform_interface: ^2.0.2
-
WebView 嵌套在 Sliver 中:
具体问题
- 鸿蒙系统、部分oppo、vivo系统,使用 loadHtmlString 加载含图片的本地富文本出现闪退;
- 针对 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的思路