敞开成长之旅!这是我参加「日新计划 12 月更文应战」的第10天,点击检查活动概况

承接上文:《从零开端|构建 Flutter 多引擎烘托组件:先导篇》

前文咱们讲了根底环境装备,以及需求提前了解的 Flutter 官方 Demo,但官方 Demo 的工程结构并不可取。

怎么更高雅的建造归于 Flutter 多引擎烘托组件的工程结构是非常重要的事,咱们希望 Flutter 多引擎烘托组件是非常独立的,能够跟原生 UI 无痕组合,也能够跟任何架构方案不发生冲突,比方 flutter_boost。当然咱们也是这样完成的,先展现下咱们现已完成了哪一些:

(视频转成 gif,帧数不行所以看起来有些卡顿)

上图中, fgui(FGUI 是内部代号)是任意项目都能运用的通用型组件包,part_home 表明是主页的事务组件包,part_video 是视频编辑器的事务组件包。Example 工程也是独立可运行,且可在 Web 上开发调试来进步效率。

展现作用是为了增强读者的信心,完全是能够做出一套相似前端 vant 的跨端 UI 组件库,也是咱们的目标,开源的话后续会考虑,当然你在读完本系列后,也能够很简单的构建出归于自己项目的组件库。

读者将会本文中得到:

  1. 防止多引擎组件开发的思想误区
  2. 从零开端建立 Flutter 多引擎组件工程

思想误区

本来想把误区放在建立进程中讲,但的确很重要,怕咱们忽视了,所以说到最开端说。

留意 FlutterEngine 生命周期

在以前单引擎时代,运用 flutter_boost 等结构做 app_to_app 混合开发时,咱们其实并不重视 FlutterEngine 的生命周期的,由于它会是一个单例,加载后不必释放。而在多引擎烘托中,实质上是经过 FlutterEngineGroup 创立出多个 FlutterEngine 实例,而这些实例从内存安全的视点考虑,是需求咱们去办理生命周期的。

不要经过 Plugin 跟 Native 通讯

在平常的 Flutter 开发中,咱们现已非常习惯构建各种 Plugin 来进行 App 与 Flutter 的通讯,大多数常用的三方库运用的也都是一样。

但在 Flutter 多引擎下,这实际上是不可行的。原因便是以前是1对1的链接关系,现在是1对多了(对应多个 FlutterEngine)。假如运用 Plugin 做多引擎烘托的通讯完成,必须考虑怎么去做 FlutterEngine 的区别和音讯阻隔,代码很简单变得臃肿和难以理解,这无疑大大添加了开发成本。

那咱们要怎么做呢?

官网推荐直接用 channel 或许用 pigeon 东西链。用 channel 需求咱们做更多的事(Channel 绑定、模型映射),所以咱们选择用 pigeon

有一点上篇文章没有讲到的,pigeon 生成后其实便是 messageChannel 通讯,而且它的生命周期在咱们的完成中相当于跟 FlutterEngine 绑定了,不仅做到内存安全,而且天然是相互阻隔的。

在开发上肯定还会用到一些第三方库,防止不了出现运用 Plugin 的情况,能够看下这篇 《Flutter 多引擎烘托,组件支持 FlutterPlugin》,有单独发文的这个系列里不会细讲 ~

工程化

那现在咱们需求建立归于自己的组件工程了,先看一下咱们的目录结构:

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

component_foundations 存放通用的东西类、根底 UI 等。

fgui 通用组件库

part_home 主页事务组件库

part_video 视频事务组件库

examples 示例工程

建立进口

开端着手,先创立进口项目

flutter create components --template=package

进口项目的作用相当于 main,只负责聚合依靠各个组件库。

components.dart 完成也很简单,仅仅把组件库的进口持续 export

export 'package:part_home/ui_components.dart';
export 'package:fgui/ui_components.dart';
export 'package:part_video/ui_components.dart';

创立组件库

fgui 组件库为例:

flutter create fgui --ios-language=objc --android-language=java --template=plugin --platforms=ios,android

有仔细看上文的同学肯定会问,为什么不能运用 plugin 还要用 plugin 的办法创立呢?

这主要是省劲,虽然咱们不会运用 plugin,也不会修正生成的 plugin 文件,但咱们会把 pigeon 生成的 iOS、Android 文件放入到相应的文件夹中。

生成完毕后,也需求创立上文 exportui_components.dart

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

这也是一个进口文件,用于聚合组件库内部的各个组件。

以非常常用的 Alert 组件为例:

import/export (略)
// 露出 componentAlertDialog 给 Native
@pragma('vm:entry-point')
void componentAlertDialog() { 
  SwitchConfigMaker.runByMutiEngines = true; // 可先疏忽,意思是表明当前调用办法是在多引擎
  return runApp(const fgui_alert_dialog.AlertDialog()); 
}
...

构建组件

// StatefulWidget ,组件的状态由外部控制
class AlertDialog extends StatefulWidget {
  const AlertDialog({
    Key? key,
    ...
  }) : super(
          key: key,
          ...
        );
  @override
  _AlertDialogState createState() {
    return _AlertDialogState();
  }
}
class _AlertDialogState extends State<AlertDialog> {
  @override
  Widget build(BuildContext context) {
    // 这儿需留意用 Directionality 
    return Directionality(
      textDirection: TextDirection.ltr,
      child: ...,
    }
  }
  ...
}

Directionality 是笔者推荐运用的根结点,由于很多 Flutter 官方组件都是需求这个文字次序的,以前开发为什么不需求,是由于 MaterialApp 都帮咱们做掉了,但在 multiple_flutters 中,不允许根结点为 MaterialApp,这也是很合理的,但的确会给开发者带来很多麻烦。

后续会推荐运用更完善的封装界说(MeterialWidget),有兴趣的同学能够看下这篇《Flutter 多引擎烘托,TextField 踩坑指南》

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

本篇着重讲 Flutter 侧工程建造,所以详细代码暂时不提。

引进 pigeon

组件就绪,咱们现在需求把通讯层运用上。

添加依靠

在 fgui 的 pubspec.yaml 中添加

dev_dependencies:
  pigeon:

源文件进口

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

构建文件 .api/alert_dialog.dart

为什么是躲藏文件?由于咱们并不需求手动输出这个文件,后续在跨端东西链一节中会讲到。这儿先用手动创立的办法,理解它的工作原理。

import 'package:pigeon/pigeon.dart';
class AlertDialogConfig {
  /// 对话框标题
  String? title;
  /// 对话框内容
  String? content;
  /// 确认按钮案牍
  String? confirmText;
  /// 是否显示撤销按钮
  bool? showCancel;
  /// 撤销按钮案牍
  String? cancelText;
}
@HostApi()
abstract class AlertDialogHostAPI {
  /// 点击确认
  void onClickConfirm();
  /// 点击撤销
  void onClickCancel();
}
@FlutterApi()
abstract class AlertDialogFlutterAPI {
  /// 初始化装备
  void config(AlertDialogConfig maker);
  /// 关闭弹窗
  void dismiss();
  /// 更新确认按钮是否可点击
  void updateConfirmEnable(bool enable);
}

AlertDialogConfig 是构造的初始化装备类

AlertDialogHostAPI 界说了组件的回调办法

AlertDialogFlutterAPI 界说了调用组件的办法

履行脚本

履行脚本,生成 Flutter、iOS、Android 的通讯层

flutter pub run pigeon \
  --input .api/alert_dialog.dart \
  --dart_out lib/.caches/alert_dialog.api.dart \
  --objc_header_out ios/Classes/APIs/FGUIAlertDialogAPI.h \
  --objc_source_out ios/Classes/APIs/FGUIAlertDialogAPI.m \
  --objc_prefix FGUI \
  --java_out  android/src/main/java/com/gaoding/apis/FGUIAlertDialogAPI.java \
  --java_package "com.gaoding.flutter.components.api"

在履行脚本之前,还需求检查 lib/.cachesios/Classes/APIsandroid/src/main/java/com/gaoding/apis 目录是否已存在,不存在需求创立。

能够看出,这脚本非常的繁琐,且不会帮助咱们主动创立相应的目录,而且生成上只能一次履行1个文件,这也坚定了咱们后续把跨端东西链先做起来的决计。

成功生成后,咱们就在 pigeon 的帮助下,把通讯层的 API 建造出来了

生成代码解说

Flutter

lib/.caches/alert_dialog.api.dart

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

咱们界说的点击确认回调,能够看到通讯原理便是构建了一个 BasicMessageChannel 把音讯发送给 Native 侧。

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

Native 调用 Flutter,进程是相反的。所以这儿生成的是一个 setup() 用于监听 Native 发送的音讯回调。假如不必 pigeon 上述的通讯进程就要自己完成,非常繁琐。

iOS

直接看 .m 文件 FGUIAlertDialogAPI.m

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

图上便是 iOS 监听 onClickConfirm 事件回调,原理便是等待 BasicMessageChannel 从 Flutter 发送过来的音讯,然后回调给 onClickConfirmWithError: 署理。

onClickConfirmWithError: 署理界说当然在 .h 文件中

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

iOS 调用 Flutter 办法:

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

直接调用相应的 API 即可。

Android

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

Android 上也是相似的,setup 供给 Android 监听事件回调的办法。

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

api.onClickConfirm()interface, 需求外部完成。

Android 调用 Flutter 办法,也是很简单,直接调用即可。

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

模型映射

除开通讯 MessageChannel 的封装,pigeon 做的更多的一件事便是模型映射了。这点其实和调用后端 API 相似了,传输进程都仍是 JSON Map 目标,各端供给序列化/反序列化办法完成各端模型一致性。

Flutter:

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

Android:

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

iOS:

从零开始|构建 Flutter 多引擎渲染组件:Flutter 工程篇

能够看到,其实也都是硬转化的,没有用什么反射办法,也符合 Flutter 的设计。当然这些对主动生成的东西链来说很简单,甚至性能比反射还更好些。

但也能看出经过这种办法,是要防止传输重型目标的,比方 Bitmap 等等。就算是杂乱的组件也应该拥有简化的 API ~

后续

总结一下,本文怎么完成多引擎烘托组件 Flutter 工程化及进口建造,以及对 pigeon 生成文件的解析。即进口层、通讯层这两个部分完成。

下一篇将会批注咱们是怎么把多引擎烘托组件跟 pigeon 生成的文件结合起来的。即 Flutter Widget 基类的作用。

传送门

《从零开端|构建 Flutter 多引擎烘托组件:Flutter 代码篇》


感谢阅览,假如对你有用请点个赞 ❤️