关于 Flutter 混合 PlatformView 的完结已经介绍过两次,跟着 5 月份谷歌 IO 的接近,新的 PlatformView 完结应该也会随之而来,本次就自始至终来一个具体的关于 PlatformView 的演进总结。

Flutter 作为新一代的跨渠道框架,经过自定义烘托引擎的立异大大提高了跨渠道的功能和一致性,但也正是由于这点, 相比之下 Flutter 在混合开发时关于原生控件的支撑成本更高。

Flutter 混合开发的难点

首要 Flutter 在混合开发中最大的难点就在于它独立的烘托引擎,举一个不是很恰当的比方:

Flutter 里混合开发相似与把原生控件烘托到 WebView 里。

大致上在 Flutter 里混合开发的感觉便是这样,由于 Flutter UI 不会转换为原生控件,而是由 Flutter Engine 运用 Skia 直接烘托在 Surface

所以 Flutter 在最早出来时并不支撑 WebViewMapView 这些常用的控件,这也导致了其时 Flutter 一度的风评不大好,所以衍生出了第一代非官方的混合开发支撑,例如: flutter_webview_plugin

在官方 WebView 控件支撑出来之前 ,第三方是直接在 FlutterView 上掩盖了一个新的原生控件,利用 Dart 中的占位控件来传递方位和巨细

Flutter 里简直一切烘托都是烘托到 FlutterView 这样一个单页面上,所以直接掩盖一个新的原生 WebView 只能说缓解燃眉之急。

如下图,在 Flutter 端 push 出来一个 设定好方位和巨细SingleChildRenderObjectWidget ,然后得到需求显现的巨细和方位,将这些信息经过 MethodChannel 传递到原生层,在原生层 addContentView 一个指定巨细和方位的 WebView

Flutter 深入探索混合开发的技术演进

这样看起来就像是在 Flutter 中增加了 WebView ,但实际这样的操作只能说是“救急”,由于这样的行为脱离了 Flutter 的烘托树,其间一个问题便是:

当你跳转 Flutter 其他页面的时分会被当时原生的 WebView 挡住;而且打开页面的动画时AppbarWebView 难以保持一致,由于 AppbarWebView 是出于两个动画体系和烘托体系。

就比方打开了新的 Flutter UI 2 页面,可是由于它仍是在 FlutterView 内,所以它会被 WebView 所遮挡。

Flutter 深入探索混合开发的技术演进

可是这个“占位”显现的思路,也起到了必定的作用,在后续 Flutter 支撑原生 PlatformView 上起到了带头的作用。

Flutter 开始支撑原生控件

为了让 Flutter 真实走向大众化,官方开始推出了官方基于 PlatformView 的系列完结,比方: webview_flutter ,而这个完结 “缝缝补补” 也被沿用至今,成了 Flutter 接入原生的方法 之一。

Android

PlatformView 的整个完结中 Android 坑一直是最多的,由于一开始 Android 上首要是经过 AndroidView 做完结这项作业,而它的 Virtual Displays 完结其实并不友好。

在 Flutter 中会将 AndroidView 需求烘托的内容制作到 VirtualDisplays 中 ,然后在 VirtualDisplay 对应的内存中,制作的画面就能够经过其 Surface 获取得到

VirtualDisplay 相似于一个虚拟显现区域,需求结合 DisplayManager 一同调用,一般在副屏显现或许录屏场景下会用到,在 VirtualDisplay 里会将虚拟显现区域的内容烘托在一个 Surface 上。

Flutter 深入探索混合开发的技术演进

如上图所示,简略来说便是原生控件的内容被制作到内存里,然后 Flutter Engine 经过相对应的 textureId 就能够获取到控件的烘托数据并显现出来,这个过程 AndroidView 这个占位控件供给了 size、offset 等方位和巨细参数。

经过从 VirtualDisplay 获取纹路,并将其和 Flutter 原有的 UI 烘托树混合,使得 Flutter 能够在自己的 Flutter Widget tree 中以图形方法刺进 Android 原生控件。

iOS

在 iOS 渠道上就不运用相似 VirtualDisplay 的方法,而是经过将 Flutter UI 分为两个透明纹路来完结组合:一个在 iOS 渠道视图之下,一个在其上面

所以这样的优点便是:

  • 需求在 “iOS渠道” 视图下方呈现的Flutter UI,终究会被制作到其下方的纹路上;
  • 而需求在 “渠道” 上方呈现的 Flutter UI,终究会被制作在其上方的纹路;

iOS 上它们只需求在最终组合起来就能够了,一般这种方法更好,由于这意味着 Native View 能够直接增加到 Flutter 的 UI 层次结构中,可是可惜一开始 Android 渠道并不支撑这种模式。

问题

尽管前面能够运用 VirtualDisplay 将 Android 控件嵌入到 Flutter UI 中 ,但这种 VirtualDisplay 这种介入还有其他麻烦的问题需求处理。

接触作业

默许状况下, PlatformViews 是没方法接收接触作业,由于 AndroidView 其实是被烘托在 VirtualDisplay 中 ,而每逢用户点击看到的 "AndroidView" 时,其实他们就真实”点击的是正在烘托的 Flutter 纹路 ,用户发生的接触作业是直接发送到 Flutter View 中,而不是他们实际点击的 AndroidView

所以 AndroidView 运用 Flutter Framework 中检测用户的接触是否在需求的特殊处理的区域内:

当接触成功时会向 Android embedding 发送一条音讯,其间包括 touch 作业的具体信息。

这就变成有些本末倒置,接触作业从原生-Flutter-原生,中心的转化导致某些信息被丢掉,也导致了响应的延迟。

文字输入

AndroidView 是无法获取到文本输入,由于 VirtualDisplay 地点的方位会始终被认为是 unfocused 的状况

所以需求做一套代理来处理 InputConnections 做输入,乃至这个行为在 WebView 上更杂乱,由于 WebView 具有自己内部的逻辑来创建和设置输入连接,而这些输入连接并没有彻底遵循 Android 的协议。

同步问题

另外还需求处理各种同步问题,比方官方就创建了一个 SurfaceTextureWrapper 用于处理同步的问题。

由于当承载 AndroidViewSurfaceTexture 被释放时,由于 SurfaceTexture.release 是在 platform 线程被调用,而 attachToGLContext 是在 raster 线程被调用,不同线程调用时或许导致:attachToGLContext 被调用时 texture 已经被释放了,所以需求 SurfaceTextureWrapper 用于完结 Java 里同步锁的作用

Flutter Hybrid Composition

所以阅历了 Virtual Display 的摧残之后,官方终于在后续推出了更为合理的完结。

完结逻辑

hybrid composition 的呈现给 Flutter 供给了一种新的混合思路,那便是直接把原生控件增加到 Flutter 里一同组合烘托

首要简略介绍下运用,比起 Virtual Display 直接运用 AndroidViewhybrid composition 相对会杂乱一点点,dart 里运用到 PlatformViewLinkAndroidViewSurfacePlatformViewsService 这三个对象。

正常在 dart 层面,运用 hybrid composition 接入原生控件:

  • 经过 PlatformViewLinkviewType 注册了一个和原生层对应的注册称号,这和之前的 PlatformView 注册相同;
  • 然后在 surfaceFactory 返回一个 AndroidViewSurface 用于处理制作和接收接触作业,一起也是一个相似占位的作用;
  • 最终在 onCreatePlatformView 方法运用 PlatformViewsService 初始化 AndroidViewSurface 和初始化所需求的参数,一起经过 Engine 去触发原生层的显现。
Widget build(BuildContext context) {
  // This is used in the platform side to register the view.
  final String viewType = 'hybrid-view-type';
  // Pass parameters to the platform side.
  final Map<String, dynamic> creationParams = <String, dynamic>{};
  return PlatformViewLink(
    viewType: viewType, 
    surfaceFactory:
        (BuildContext context, PlatformViewController controller) {
      return AndroidViewSurface(
        controller: controller,
        gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
        hitTestBehavior: PlatformViewHitTestBehavior.opaque,
      );
    },
    onCreatePlatformView: (PlatformViewCreationParams params) {
      return PlatformViewsService.initSurfaceAndroidView(
        id: params.id,
        viewType: viewType,
        layoutDirection: TextDirection.ltr,
        creationParams: creationParams,
        creationParamsCodec: StandardMessageCodec(),
      )
        ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
        ..create();
    },
  );
}

看起来好像是把一个 AndroidView 完结的作业变得相对杂乱了,可是其实 hybrid composition 的完结相比其实更好理解。

运用 hybrid composition 之后, PlatformView 就直接经过 FlutterMutatorView(一个特殊的 FrameLayout) 把原生控件 addViewFlutterView上,然后再经过 FlutterImageView 的才能去完结多图层的混合

不理解吗?没事,咱们后面会具体介绍,先简略解说便是:

Flutter 只直接经过原生的 addView 方法将 PlatformView 增加到 FlutterView ,这就不需求什么 surface 烘托再去获取的开支,而当你还需求再 PlatformView 上烘托 Flutter 自己的 Widget 时,Flutter 就会经过再叠加一个 FlutterImageView 来承载这个 Flutter Widget 。

Flutter 深入探索混合开发的技术演进

深化比方详解

接下来让咱们从实际比方去理解 Hybrid Composition ,结合 Andriod Studio 的 Layout Inspector,并敞开手机的制作鸿沟来看会更直观。

如下代码所示,一般状况下咱们运转之后会看到一片黑色,由于这时分 FlutterView 只要一个 FlutterSurfaceView 的子控件存在,此刻尽管咱们画面上是有一个 Flutter 的赤色 RE 文本控件 ,不过由于是由 Flutter 直接在 Surface 直接制作,所以 Layout Inspector 看不到只显现黑色。

Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment.center,
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    )
  ],
)

Flutter 深入探索混合开发的技术演进

此刻咱们增加一个经过 Hybrid Composition 完结一个原生的 TextView 控件,经过 PlatformView 在 Flutter 上烘托出一个灰色 RE 文本。

Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(-0.6, -0.6),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment.center,
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    )
  ],
)

Flutter 深入探索混合开发的技术演进

能够看到,如上图所示,在咱们的显现布局鸿沟上能够清晰看到它的信息:

TextView 经过 FlutterMutatorView 被增加到 FlutterView 上被直接显现出来。

所以 TextView 是直接在原生代码上被 add 到 FlutterView 上,而不是提取纹路,另外能够看到,左边栏里多了一个 FlutterImageView ,而且之前看不到的 Flutter 控件赤色 RE 文本也呈现了,布景也变成了 Flutter 上的白色。

咱们先暂时疏忽新呈现的 FlutterImageView 和 Flutter UI 能够呈现在 Layout Inspector 的原因,留到后面再来剖析,此刻咱们再新增加以一个赤色的 Flutter RE 控件到 Stack 里,坐落 PlatformView 的灰色 RE 下。

Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(-0.4, -0.4),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    ),
    Align(
      alignment: Alignment(-0.6, -0.6),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment.center,
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    )
  ],
)

Flutter 深入探索混合开发的技术演进

如上图所示,能够看到布局和烘托作用正常,Flutter 的赤色 RE 被上面的 PlatformView 灰色 RE 遮挡了部分,这是契合代码的烘托作用。

假如这时分咱们把新增加的第二个赤色 RE 放到灰色 PlatformView 灰色 RE 上,会发生什么状况?

 Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(-0.6, -0.6),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(-0.4, -0.4),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    ),
    Align(
      alignment: Alignment.center,
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    )
  ],
)

Flutter 深入探索混合开发的技术演进

能够看到赤色的 RE 成功被烘托到灰色 RE 上 ,而之所以能够烘托上去的原因,是由于这个和 PlatformView 有交集的 Text ,被烘托到一个新增的 FlutterImageView 控件上, 也便是 Flutter 判断了此刻新赤色 RE 文本需求烘托到 PlatformView 上,所以增加了一个 FlutterImageView 用于承载这部分烘托内容。

假如这时分挪动第二个赤色的 RE 让它和 PlatformView 没有交集,可是仍是在 Stack 里坐落 PlatformView 之上会怎么?

Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(-0.6, -0.6),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(-0.8, -0.8),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 50, color: Colors.red),
      ),
    ),
    Align(
      alignment: Alignment.center,
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    )
  ],
)

Flutter 深入探索混合开发的技术演进

能够看到尽管 FlutterImageView 没了,第二个赤色的 RE 也回到了默许的 Surface上,所以这便是 Hybrid Composition 混合原生控件的最基础设计理念:

  • 直接把原生控件增加到 FlutterView 之上
  • 原生和 Flutter 控件混合堆叠时,用新的 FlutterImageView 来完结层级掩盖;
  • 假如没有交集就不需求新的 FlutterImageView

关于 FlutterImageView 后面再打开,咱们持续这个比方,让两个 Flutter 的赤色 RE 都烘托到 PlatformView 的灰色的RE 上会是什么状况?

Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(0.6, 0),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(0.6, 0),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 50, color: Colors.red),
      ),
    ),
    Align(
      alignment: Alignment.center,
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    )
  ],
)

Flutter 深入探索混合开发的技术演进

如上图所示,能够看到两个赤色的 Flutter RE 控件同享了一个 FlutterImageView ,这里能够得到一个新的定论:**和 PlatformView 有交集的同层级 Flutter 控件会同享同一个 FlutterImageView 。 **

咱们持续调整示例,如下代码咱们新增多一个 PlatformView 的灰色 RE 控件,然后调整方位,可是 Flutter 控件都在一个层级上,运转之后能够看到,只要 Flutter 控件都在同一个层级,就同享同一个 FlutterImageView

Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(-0.2, 0),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(0.2, 0),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(0, -0.1),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 50, color: Colors.red),
      ),
    ),
    Align(
      alignment: Alignment(0,  0.2),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    )
  ],
)

Flutter 深入探索混合开发的技术演进

可是假如不在一个层级呢?咱们调整两个灰色 RE 的方位,让 PlatformView 的灰色 RE 和 Flutter 的赤色 RE 替换呈现。

Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(-0.2, 0),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(0, -0.1),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 50, color: Colors.red),
      ),
    ),
    Align(
      alignment: Alignment(0.2, 0),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(0,  0.2),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 100, color: Colors.red),
      ),
    )
  ],
)

Flutter 深入探索混合开发的技术演进

能够看到,两个赤色的 Flutter RE 控件都独自被烘托都一个 FlutterImageView 上,所以咱们有新的定论:PlatformView 有交集的 Flutter 控件假如在不同层级,就需求不同的 FlutterImageView 来承载。

所以一般在运用 PlatformView 的场景上,不主张有过多的层级堆叠或许过于杂乱的 UI 场景。

接着咱们持续测验,还记得前面说过 Virtual Display 上关于接触作业的问题,所以此刻咱们直接给 PlatformView 的 灰色 RE 在原生层增加点击作业弹出 Toast 测验。

 Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(-0.7, 0),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(0.8, 0),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 50, color: Colors.red),
      ),
    ),
    Align(
      alignment: Alignment.center,
      child: Container(
        color: Colors.amber,
        child: new Text(
          "RE",
          style: TextStyle(fontSize: 100, color: Colors.red),
        ),
      ),
    ),
  ],
)

Flutter 深入探索混合开发的技术演进

能够看到运转后点击能够正常弹出 Toast ,所以关于 PlatformView 来说自身的点击和接触是能够正常保存,然后咱们调整下赤色大 RE 和灰色 RE 让他们发生交集,一起给赤色的大 RE 也增加点击作业,弹出 SnackBar

Stack(
  fit: StackFit.expand,
  children: [
    Align(
      alignment: Alignment(-0.3, 0),
      child: SizedBox(
        height: 100,
        width: 100,
        child: NativeView(),
      ),
    ),
    Align(
      alignment: Alignment(0.8, 0),
      child: new Text(
        "RE",
        style: TextStyle(fontSize: 50, color: Colors.red),
      ),
    ),
    Align(
      alignment: Alignment.center,
      child: InkWell(
        onTap: () {
          ScaffoldMessenger.of(context)
              .showSnackBar(SnackBar(content: new Text("Re Click")));
        },
        child: Container(
          color: Colors.amber,
          child: new Text(
            "RE",
            style: TextStyle(fontSize: 100, color: Colors.red),
          ),
        ),
      ),
    ),
  ],
)

Flutter 深入探索混合开发的技术演进

运转之后能够看到,点击没有被掩盖的灰色部分,仍是能够弹出 Toast ,点击赤色 RE 和灰色 RE 的交集处,能够正常弹出 SnackBar

所以能够看到 Hybrid Composition 上这种完结,能更原汁原味地保流下原生控件的作业和特性,由于从原生 视点,它便是原生层面的物理堆叠

现在咱们应该大致关于 Hybrid Composition 有了必定理解,那回到前面那个一开始 Layout InSpector 黑屏 ,后来又能烘托出界面的原因,这就和首次增加 Hybrid Composition 时多出来的 FlutterImageView 有关系。

如下图所示,能够看到此刻原生的灰色 RE 和 Flutter 的赤色 RE 是没有交集的,为什么会多出来一个 FlutterImageView 呢?

Flutter 深入探索混合开发的技术演进

这就需求说到 flutterView.convertToImageView() 这个方法。

在 Flutter 烘托 Hybrid CompositionPlatformView 时,会有一个 flutterView.convertToImageView() 的操作,这个操作是:把默许的 FlutterSurfaceView 烘托切换到 FlutterImageView ,所以此刻会有一个 新增的 FlutterImageView 呈现在 FlutterSurfaceView 之上。

为什么需求 FlutterImageView ?那就要先理解下 FlutterImageView 是怎么作业的,由于在前面咱们说过,和 PlatformView 有交集的时分 Flutter 的控件也会被烘托到 FlutterImageView 上。

FlutterImageView 自身是一个原生的 Android View 控件,它的内部有几个关键对象:

  • imageReader :供给一个 surface ,而且能够直接访问到 surface 里的图画数据;
  • flutterRenderer : 外部传入的 Flutter 烘托类,这里用于切换/供给 Flutter Engine 里的烘托所需 surface ;
  • currentImage : 从 imageReader 里提取出来的 Image 画面;
  • currentBitmap :将 Image 转为 Bitmap ,用于 onDraw 时制作;

所以简略地说 FlutterImageView 作业机制便是:经过 imageReader 供给 surface 给 Engine 烘托,然后把 imageReader 里的画面提取出来,烘托到 FlutterImageViewonDraw

所以回归到前面的 flutterView.convertToImageView() ,在 Flutter 烘托 Hybrid CompositionPlatformView 时,会先把自己也变成了一个 FlutterImageView ,然后进入新的烘托流程:

  • Flutter 在 onEndFrame 时,也便是每帧结束时,会判断当时界面是否还有 PlatformView ,假如没有就会切换会默许的 FlutterSurfaceView
  • 假如还存在 PlatformView ,就会调用 acquireLatestImage 去获取当时 imageReader 里的画面,得到新的 currentBitmap ,然后触发 invalidate
  • invalidate 会导致 FlutterSurfaceView 履行 onDraw ,然后把 currentBitmap 里的内容制作出来。

Flutter 深入探索混合开发的技术演进

所以咱们搞清楚了 FlutterImageView 的作用,也搞清楚了为什么有了 Hybrid CompositionPlatformView 之后,在 Android Studio 的 Layout Inspector 里能够看到 Flutter 控件的原因:

由于有 Hybrid Composition 之后, FlutterSurfaceView 变成了 FlutterImageView ,而 FlutterImageView 制作是经过 onDraw ,所以能够在 Layout Inspector 里呈现。

那为什么会有把 FlutterSurfaceView 变成了 FlutterImageView 这样的操作?原因其实是为了更好的动画同步和烘托作用

由于前面说过,Hybrid Composition 是直接把增加到 FlutterView 上面,所以走的仍是原生的烘托流程和时机,而这时分经过把 FlutterSurfaceView 变成了 FlutterImageView ,也便是把 Flutter 控件烘托也同步到原生的 OnDraw 上,这样关于画面同步会更好。

那有人就要说了,我就不喜爱 FlutterImageView 的完结,有没有方法不在运用 Hybrid Composition 时把 FlutterSurfaceView 变成了 FlutterImageView 呢?

有的,官方在 PlatformViewsService 内供给了对应的设置支撑:

 PlatformViewsService.synchronizeToNativeViewHierarchy(false);

在设置为 false 之后,能够看到只要 Hybrid CompositionPlatformView 的内容才能在 Layout Inspector 上看到,而 FlutterSurfaceView 看起来便是黑色空白。

Flutter 深入探索混合开发的技术演进

Flutter 深入探索混合开发的技术演进

问题

Hybrid Composition 便是完美吗? 肯定不是,事实上 Hybrid Composition 也有许多小问题,其间就比方功能问题。

例如在不运用 Hybrid Composition 的状况下,Flutter App 中 UI 是在特定的光栅线程运转,所以 Flutter 上 App 自身的主线程很少受到堵塞。

可是在 Hybrid Composition 下,Flutter UI 会由渠道的 onDraw 制作,这或许会导致必定程度上需求消耗渠道功能和占用通讯的开支

例如在 Android 10 之前, Hybrid Composition 需求将内存中的每个 Flutter 制作的帧数据仿制到主内存,之后再从 GPU 烘托仿制回来 ,所以也会导致 Hybrid Composition 在 Android 10 之前的功能表现更差,例如在滚动列表里每个 Item 嵌套一个 Hybrid CompositionPlatformView

具体体现在 ImageReader 创建时,大于 29 的能够运用 HardwareBuffer ,而HardwareBuffer 允许在不同的应用程序进程之间同享缓冲区,经过 HardwareBuffers 能够映射各种硬件体系的可访问 memory,例如 GPU。

Flutter 深入探索混合开发的技术演进

所以假如当 Flutter 呈现动画卡顿时,或许你就应该考虑运用 Virtual Display 或许禁止 FlutterSurfaceView 变成了 FlutterImageView

事实上 Virtual Display 的功能也欠好,由于它的每个像素都需求经过额定的中心图形缓冲区。

未来变化

在现在 master 的 #31198 这个合并上,提出了新的完结方法用于替代现有的 Virtual Display

这个还未发布到正式本的调整上, Hybrid Composition 根本没有变化,首要是调整了一些命名,首要逻辑仍是在于 createForTextureLayer ,现在还无法确保它后续的发展,现在还有 一部分进度在 #97628 ,所以先简略介绍下它的状况。

在这个新的完结上,Virtual Display 的逻辑变成了 PlatformViewWrapper PlatformViewWrapper 自身是一个 FrameLayout ,同样是 flutterView.addView(); ,根本逻辑和 Hybrid Composition 很像,只不过现在增加的是 PlatformViewWrapper

Flutter 深入探索混合开发的技术演进

在这里 Virtual Display 没有了,本来 Virtual Display 创建的 Surface 被设置到 PlatformViewWrapper 里边。

简略介绍下:PlatformViewWrapper 里,会经过 surface.lockHardwareCanvas(); 获取到当时 SurfaceCanvas ,而且经过 draw(surfaceCanvas) 传递给了 child

所以 child 的 UI 就被制作到传入的 Surface 上,而 Flutter Engine 依据 Surface 的 id 又能够获取到对应的数据,经过一个不可视的 PlatformViewWrapper 完结了制作切换而无需运用 VirtualDisplay

当然,现在在测验中接收到的反应里有还不如曾经的功能好,所以后续会怎么调整仍是需求看测验结果。

PS ,假如这个修正正式发布,或许 Flutter 的 Android miniSDK 版别就需求到 23 起步了。由于 lockHardwareCanvas() 需求 23 起,而不必兼容更低渠道的原因是 lockCanvas() 归于 CPU copy ,功能上会慢许多

Flutter 深入探索混合开发的技术演进