累赘的序言
Flutter 2.0 正式发布时,其中倍受我们关注之一的内容是 Add-to-App 相关的预览,即使除「热预览」以外,Flutter 倍受我们非议的是「混和合作开发新体验」不太好。
❝为什么不太好呢?即使 「Flutter 的命令行图形直接瓦解了原生植物网络平台,也是不论网页栈和图形树都分立于网络平台运转」,这虽说给 Flutter 带来了良好的跨网络平台新体验,但也造成了在和原生植物网络平台混和时存有高生产成本的难题。
❞虽说在已近的是原生植物工程项目中软件系统 Flutter ,是眼下在 Flutter 中软件系统原生植物命令行的 PlatformView 和 Hybrid Composition新体验也是尚待提高,总之“有全力支持”和“能用”就已经是很极好的重大进展。
「因此 Flutter 2.0 在翘首企盼中正式发布了 FlutterEngineGroup 用于全力支持非正式的 Add Flutter to existing app 计划。」
在此计划出现之前,类似于的服务器端全力支持有 flutter_boost 、 mix_stack 、 flutter_thrio之类 ,它们是否称心这里不探讨,但这些计划都要直面的难题是:
❝非非正式的全力支持必定存在每一版需要网络连接的难题,而按照 Flutter 现阶段的 issue closed 和 pr merge 的速率,很可能每一会计年度的版都存有较大的发生变动,「因此如果合作开发人员不保护或者保护不及时处理,那么侵入性很强的此类架构很难就成为工程项目的困局」。
❞而非正式提供更多的 FlutterEngineGroup 计划是不是瑕疵?的确有的是,它现阶段看上去更像被造就出来的状况,各方面的难题还是有的是,比如说这类地方还存有不能 destroy 的难题。 (总之那个难题以及在 master 组成部分 merge 了)
但非正式提供更多的计划,就意味著那个结构设计得到了 Flutter 非正式的确保,「在未来的版中常有相容的竞争优势」。
「FlutterEngineGroup 计划使用了多 Engine 混和商业模式,非正式声称除两个 Engine 第一类以外,先期每一 Engine 第一类在 Android 和 iOS 上仅挤占 180kB」 。
❝从前的计划每多两个Engine ,可能就会多出 19MB Android 和 13MB iOS 的挤占。
❞从 Flutter 非正式提供更多的例子上看,FlutterEngineGroup 的 API 十分简单,「多个 Engine 实例的内部都是分立保护自己的内部导航栈」,因此可以做到每一 Engine 对应两个分立的模块。
因此使用 FlutterEngineGroup 之后,FlutterEngine 都将由 FlutterEngineGroup 去生成,生成的 FlutterEngine 可以分立应用于 FlutterActivity/FlutterViewController,甚至是 FlutterFragment :
❝因此就像例子上所示,你可以在两个 Activity 上显示两个分立的 FlutterView 。
❞这其实得益于通过 FlutterEngineGroup 生成的 FlutterEngine 可以「共享 GPU 上下文, font metrics 和 isolate group snapshot」 ,从而实现了更快的初始速率和更低的内存挤占。
❝「下图是使用非正式实例打开16个网页之后的内存使用情况,并且每一网页成功返回且没有出现黑屏。」
❞简单的使用介绍
使用 FlutterEngineGroup 首先需要创建两个 FlutterEngineGroup 单例第一类,之后每当需要创建 Engine 时,就通过它的 createAndRunEngine(activity, dartEntrypoint) 来创建对应的 FlutterEngine 。
以非正式 Demo 的这段代码为例子:
1、首先通过 findAppBundlePath 和 entrypoint 创建出 DartEntrypoint 第一类,这里的 「findAppBundlePath 主要是默认的 flutter_assets 目录」;而 「entrypoint其实是 dart 代码里启动方法的名称」;也是绑定了在 dart 中 runApp 的方法。
2、通过上面创建的 dartEntrypoint 和 context ,使用 FlutterEngineGroup 就可以创建出对应的 FlutterEngine ,其实在内部是通过FlutterJNI.nativeSpawn 和原有的是引擎交互,得到新的 Long 地址 id。
❝在 C++ 层类似于于原有的是 RunBundleAndSnapshotFromLibrary 方法,但它不能更改包路径或者 asset ,因此只能加载同一份 AOT 文件,这里得到的指针地址是两个新的 AndroidShellHolder 。
❞3、最后利用生成的 FlutterEngine 的 binaryMessenger 来得到两个 MethodChannel 用于原生植物和 dart 之间的通信。
通过上述流程得到的 Engine ,自然就可以直接用于图形运转新的 Flutter UI,比如说直接继承 FlutterActivity ,然后 override provideFlutterEngine 方法返回得到的 Engine 。
是不是很简单?这么简单的接入后:
在 dart 层面可以通过 MethodChannel 打开原始网页;在原生植物层可以通过新建 FlutterEngine 打开新的 Flutter 网页;甚至你还可以在原生植物层打开两个 FlutterView 的 Dialog;当然,到这里你可能已经注意到了,即使每一 Flutter 网页都是两个分立的 Engine ,由于 dart isolate 的结构设计理念,「每一分立 Engine 的 Flutter 网页内存是无法共享的」。
也是说,当你需要共享数据时,只能在原生植物层持有数据,然后注入或者传递到每一 Flutter 网页中,就像非正式所说的,「每一 Flutter 网页更像两个分立 Flutter 模块」。
❝总之这也造成了一些不必要的麻烦,比如说:「同一张图片,在原生植物层、不同 Flutter Engine 会出现多次加载的难题」,这种难题可能就需要你针对 Flutter 的图片加载使用外界纹理,来实现在原生植物层统一的内存管理等。
❞另外现阶段我发现难题还有: Android 11 上的 ARM TBI 难题 ,不过通过这次尝试,相信 FlutterEngineGroup 的重大进展将会越来越明朗,更早的被应用到生产环境中。