前言
众所周知,Flutter 的 WebView 不太友好,用起来不顺手。 我们 Flutter 开发常用的 WebView 库有2个,一个是 Flutter 官方自己出的 webview_flutter ,另一个是比较流行的 flutter_inappwebview 。这两个库其实差不多,flutter_inappwebview 功能比较丰富,封装了很多事件、方法等,但是很多问题这两个库都会遇到。本文以 webview_flutter 为基础库展开讲解相关问题以及解决方案。
问题
白屏、UI错乱
如上图所示
- 测试的时候发现部分手机(如OPPO)会出现白屏现象
- 原生与 Flutter 混编,打开页面会发现页面布局变了,顶部banner变小了 查阅网上的一些解决方案,千篇一律都是:
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
但是,这样设置其实是不对的,还会出现以上问题,真正的解决方案是:
if (Platform.isAndroid) WebView.platform = AndroidWebView();
视频自动播放
由于需求需要,打开页面的时候,列表的第一个视频(YouTube/Facebook 视频)需要自动播放。 但是发现没法自动播放,如下图,会出现播放之后马上暂停的现象。
查阅资料得知,是谷歌浏览器的隐私政策导致的。
- Chrome 的自动播放策略
- 始终允许静音自动播放。
- 在以下情况下允许自动播放声音:
- 用户与域进行了交互(单击、点击等)
- 在桌面上,用户的媒体参与指数阈值已被超过,这意味着用户之前播放过有声视频。
- 用户已将网站添加到移动设备的主屏幕或在桌面设备上安装 PWA。
- 顶级框架可以将自动播放权限委托给其 iframe 以允许自动播放声音。
所以要想视频自动播放,有两种方案:
- 静音播放。
- 在 Web 端调用视频播放器的静音即可自动播放。
- 模拟点击。
- 给 WebView 设置一个 GlobalKey 。
WebView( key: logic.state.videoGlobalKey, ...... ); }
- 然后在 WebView 的 onPageFinished 方法里,通过 GlobalKey 获取 WebView 的位置,从而进行模拟点击,就可以自动播放视频了。
var currentContext = state.videoGlobalKey.currentContext; var offset = (currentContext?.findRenderObject() as RenderBox) .localToGlobal(Offset.zero); //模拟点击 var addPointer = PointerAddedEvent( pointer: 0, position: Offset( offset.dx + 92.w, offset.dy + 92.w), ); var downPointer = PointerDownEvent( pointer: 0, position: Offset( offset.dx + 92.w, offset.dy + 92.w), ); var upPointer = PointerUpEvent( pointer: 0, position: Offset( offset.dx + 92.w, offset.dy + 92.w), ); GestureBinding.instance!.handlePointerEvent(addPointer); GestureBinding.instance!.handlePointerEvent(downPointer); GestureBinding.instance!.handlePointerEvent(upPointer);
- 给 WebView 设置一个 GlobalKey 。
这两种方案各有利弊,方案一无法播放声音(需要用户手动点击开启声音),方案二偶尔会有误触的操作。我们 APP 通过与产品商量最终选取的是方案一的解决方案。
另外 iOS 端自动播放会自动全屏,需要设置以下属性:
WebView(
key: logic.state.videoGlobalKey,
// 允许在线播放(解决iOS播放视频自动全屏)
allowsInlineMediaPlayback: true,
......
);
}
以下是需求完成的完整效果: