在 Flutter 里混合原生平台的控件需要通过 PlatformView
进行接入实现,在这方面 iOS 的实现方式一直变化不大,但是在 Android 上不同版本到目前就出现了三种实现逻辑,所以本篇主要介绍 Android 平台如何选择合适的 PlatformView
方案。
抛开最早期如 flutter_webview_plugin 这种直接进行覆盖原生控件的实现不谈, PlatformView
在 Android 上目前官方提供的就有三种实现方式:
VirtualDisplays
:类似于一个虚拟显示区域,将虚拟显示区域的内容渲染在一个内存Surface
上,然后同步纹理到 Engine ,事实上控件并不在渲染位置。
HybridComposition
: 通过addView
直接添加原生平台控件,需要层级覆盖时利用FlutterImageView
承载 Flutter 控件的渲染进行堆叠,原生控件会在渲染位置。
TextureLayer
:在渲染位置通过原生的透明PlatformViewWrapper
做容器,然后通过替换 Canvas 将原生控件的纹理渲染到特定 Surface 上,控件不在渲染位置,但是可以通过父容器做事件拦截。
是不是看完有点懵?不怕后面会有对应的例子解释,不理解也不要紧,这一篇是教你如何选,所以也并不需要真的理解内部是如何实现。
但是上面介绍的这三种实现也是有前提条件的,比如:
- Flutter 1.2 之前,你只能用
VirtualDisplays
- Flutter 3.0 之前,你只能用
VirtualDisplays
和HybridComposition
- Flutter 3.3 之前,你只能用
TextureLayer
和HybridComposition
- Flutter 3.3 开始,你能用
VirtualDisplays
、TextureLayer
和HybridComposition
是不是觉得有些奇怪,为什么会有奇怪的排列方式?这里面的故事线大概是这样的:
- 因为
VirtualDisplays
存在触摸事件和键盘等问题,所以通过addView
进行原生堆叠的HybridComposition
出现,解决了手势和键盘等问题 - 因为
HybridComposition
存在一些场景缺陷,比如列表卡顿,渲染线程不同步导致闪动等问题,所以VirtualDisplays
得以继续服役 - 3.0 开始默认
VirtualDisplays
和HybridComposition
被替换为TextureLayer
,但是HybridComposition
实现依旧保留,在使用时需要显式执行PlatformViewsService.initExpensiveAndroidView
才能使用,因为TextureLayer
存在没办法替代原生控件 Canvas 的场景,同时TextureLayer
要求 Flutter Mini SDK API 23 - 3.3 开始
VirtualDisplays
实现又回来了,因为需要支持 Mini SDK API 23 以下的场景,同时比如SurfaceView
机制原因,这类场景TextureLayer
实现没办法直接兼容,所以 3.3 开始在遇到SurfaceView
实现时TextureLayer
会切换为VirtualDisplays
模式
这里面固然有实现成本的问题,同时也有社区把控的问题,才造成了这样“混乱”的局面。
上面这么说可能有些抽象,我们再看具体例子,首先看官方的 webview_flutter 实现, 如下表格所示,最初的时候 WebView 插件默认是使用了 AndroidWebView
,也就是 VirtualDisplays
相关的实现;后来有了 HybridComposition
之后就新增了 SurfaceAndroidWebView
,用户在需要时可以根据场景自行切换。
默认判断 | VirtualDisplays | HybridComposition |
---|---|---|
这里就不得不提以前的 issue ,如果你的 WebView 存在触摸或者键盘问题就可以通过下述代码来解决,因为正如前面说过, HybridComposition
是通过 addView
的方式添加原生控件,所以能尽可能保存控件本身的特性。
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
复制代码
而后来 webview_flutter 在更新迭代里默认实现里也修改为了 SurfaceAndroidWebView
,因为 HybridComposition
确实更适合 WebView 的场景,比如 H5 的详情页。
默认判断 | TextureLayer | HybridComposition |
---|---|---|
上面的例子可能还不够典型,接着我们再看一个典型的例子: MapView ,如下所示,目前国内 Flutter 里常见的地图实现有:
虽然他们都是采用了 PlatformView
的实现,但是选择的实现方式却存在一定差异,而通过这些差异也可以很好比对 PlatformView
实现的区别:
- 高德 Flutter 插件采用的是
AndroidView
的实现方式,也就是在 3.0 以下是VirtualDisplays
,在 3.0 以上是TextureLayer
, 从表中的图 2 也可以看到在 Flutter 3.0 MapView 父容器对应的TextureLayer
的PlatformViewWrapper
。
dart 实现 | TextureLayer |
---|---|
这里额外需要注意的是:由于隐私政策等原因,现在基本地图框架都需要做一定的隐私相关适配,高德也不例外,所以如果想正常使用 SDK ,就需要注意初始化时的适配问题。
对隐私和权限问题感兴趣可以看 《2022 年 App 上架审核问题集锦,全面踩坑上线不迷路》
- 华为 Flutter 地图插件选择的则是
HybridComposition
的实现方式,注意下图代码里的initExpensiveAndroidView
,因为现在使用PlatforViewLink
已经不能作为是否使用HybridComposition
的判定标准,3.0 开始必须显式配置了initExpensiveAndroidView
才是HybridComposition
。
3.0之前 PlatforViewLink | 3.0之后 PlatforViewLink + initSurfaceAndroidView | 3.0之后 PlatforViewLink + initExpensiveAndroidVie |
---|---|---|
HybridComposition | TextureLayer | HybridComposition |
对
HybridComposition
详细实现感兴趣的可以了解:混合开发下 HybridComposition 和 VirtualDisplay 的实现与未来演进 和 《1.20 下的 Hybrid Composition 深度解析》
- 百度 Flutter 地图插件采用的是
AndroidView
的实现方式,但是原生端提供了TextureView
和SurfaceView
两种实现选择,这又产生了不同的组合结果。
3.0之前 | 3.0 | 3.0之后 |
---|---|---|
VirtualDisplays | TextureLayer ( SurfaceView 方案无法工作) | VirtualDisplays (SurfaceView)/ TextureLayer (TextureView) |
从下方的 Layout Inspector 可以看到,在 Flutter 3.3 下,百度地图插件如果使用了 MapSurfaceView
就会采用 VirtualDisplays
,而如果使用了 MapTextureView
就会采用 TextureLayer
,这是为什么呢?
SurfaceView | TextureView |
---|---|
前面我们不是说过,Flutter 在 3.0 的时候通过 TextureLayer
取代了 VirtualDisplays
,而 TextureLayer
的实现方式就是通过 PlatformViewWrapper
来替换 child 的 Canvas 从而提取纹理,但是在某些场景下就会有问题,例如 SurfaceView
。
简单来说,
SurfaceView
是比较特殊的场景,本身它具备双缓冲机制,类似于两个Canvas
,同时在 WMS 有独立的WindowState
, 所以渲染逻辑其实是脱离了原本的 View hierachy ,因此 Flutter 3.0 下的TextureLayer
的 hook Canvas 实现没办法兼容。
所以在 Flutter 3.3 中 VirtualDisplays
又回来了,作为多年服役的"老将",当运行平台低于 23 或者原生控件是 SurfaceView
时,就会继续降级采用 VirtualDisplays
的相关实现,这也算是折中的实现。
SurfaceView | TextureView |
---|---|
如果对这部分感兴趣的可以查阅 Flutter 3.0下的混合开发演进 / Flutter 深入探索混合开发的技术演进
所以现在知道为什么要做这一期了吧?Flutter 的 PlatformView
实现因为历史包袱留下了很多“坑”,不理清楚这些坑,很可能就会让你在遇到问题时找不到方向,总结一下:
VirtualDisplays
老骥伏枥,采用的是虚拟显示提取纹理的方式,可能存在手势和键盘问题,适合列表和小控件场景,在 3.0 版本中缺席HybridComposition
在 1.2 版本之后出现,因为是通过addView
和层级堆叠实现混合,能尽可能保证控件的“原汁原味”,但是性能开销会比较大,不适合列表里使用,在 3.0 之后需要显式调用initExpensiveAndroidView
TextureLayer
在 3.0 版本开始出现,通过 Hook 住控件 Canvas 的方式实现纹理提取,但是需要 miniSDK 23 ,适用于替代VirtualDisplays
的场景,但是在 3.3 开始遇到SurfaceView
时会降级为VirtualDisplays
。
其实我有预感,在之后的版本这部分逻辑还会出现变化,但是可能 3.0 和 3.3 的发布一样,并不会将这种变更放在 release note 里。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新**
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-Bb7MIMqB-1712834614158)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!