敞开成长之旅!这是我参加「日新计划 12 月更文应战」的第10天,点击检查活动概况
承接上文:《从零开端|构建 Flutter 多引擎烘托组件:先导篇》
前文咱们讲了根底环境装备,以及需求提前了解的 Flutter 官方 Demo,但官方 Demo 的工程结构并不可取。
怎么更高雅的建造归于 Flutter 多引擎烘托组件的工程结构是非常重要的事,咱们希望 Flutter 多引擎烘托组件是非常独立的,能够跟原生 UI 无痕组合,也能够跟任何架构方案不发生冲突,比方 flutter_boost。当然咱们也是这样完成的,先展现下咱们现已完成了哪一些:
(视频转成 gif,帧数不行所以看起来有些卡顿)
上图中, fgui
(FGUI 是内部代号)是任意项目都能运用的通用型组件包,part_home
表明是主页的事务组件包,part_video
是视频编辑器的事务组件包。Example 工程也是独立可运行,且可在 Web 上开发调试来进步效率。
展现作用是为了增强读者的信心,完全是能够做出一套相似前端 vant
的跨端 UI 组件库,也是咱们的目标,开源的话后续会考虑,当然你在读完本系列后,也能够很简单的构建出归于自己项目的组件库。
读者将会本文中得到:
- 防止多引擎组件开发的思想误区
- 从零开端建立 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》,有单独发文的这个系列里不会细讲 ~
工程化
那现在咱们需求建立归于自己的组件工程了,先看一下咱们的目录结构:
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 文件放入到相应的文件夹中。
生成完毕后,也需求创立上文 export
的 ui_components.dart
这也是一个进口文件,用于聚合组件库内部的各个组件。
以非常常用的 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 侧工程建造,所以详细代码暂时不提。
引进 pigeon
组件就绪,咱们现在需求把通讯层运用上。
添加依靠
在 fgui 的 pubspec.yaml
中添加
dev_dependencies:
pigeon:
源文件进口
构建文件 .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/.caches
,ios/Classes/APIs
,android/src/main/java/com/gaoding/apis
目录是否已存在,不存在需求创立。
能够看出,这脚本非常的繁琐,且不会帮助咱们主动创立相应的目录,而且生成上只能一次履行1个文件,这也坚定了咱们后续把跨端东西链先做起来的决计。
成功生成后,咱们就在 pigeon
的帮助下,把通讯层的 API 建造出来了
生成代码解说
Flutter
lib/.caches/alert_dialog.api.dart
咱们界说的点击确认回调,能够看到通讯原理便是构建了一个 BasicMessageChannel
把音讯发送给 Native 侧。
Native 调用 Flutter,进程是相反的。所以这儿生成的是一个 setup()
用于监听 Native 发送的音讯回调。假如不必 pigeon
上述的通讯进程就要自己完成,非常繁琐。
iOS
直接看 .m 文件 FGUIAlertDialogAPI.m
图上便是 iOS 监听 onClickConfirm
事件回调,原理便是等待 BasicMessageChannel
从 Flutter 发送过来的音讯,然后回调给 onClickConfirmWithError:
署理。
onClickConfirmWithError:
署理界说当然在 .h 文件中
iOS 调用 Flutter 办法:
直接调用相应的 API 即可。
Android
Android 上也是相似的,setup
供给 Android 监听事件回调的办法。
api.onClickConfirm()
是 interface
, 需求外部完成。
Android 调用 Flutter 办法,也是很简单,直接调用即可。
模型映射
除开通讯 MessageChannel
的封装,pigeon 做的更多的一件事便是模型映射了。这点其实和调用后端 API 相似了,传输进程都仍是 JSON Map 目标,各端供给序列化/反序列化办法完成各端模型一致性。
Flutter:
Android:
iOS:
能够看到,其实也都是硬转化的,没有用什么反射办法,也符合 Flutter 的设计。当然这些对主动生成的东西链来说很简单,甚至性能比反射还更好些。
但也能看出经过这种办法,是要防止传输重型目标的,比方 Bitmap 等等。就算是杂乱的组件也应该拥有简化的 API ~
后续
总结一下,本文怎么完成多引擎烘托组件 Flutter 工程化及进口建造,以及对 pigeon 生成文件的解析。即进口层、通讯层这两个部分完成。
下一篇将会批注咱们是怎么把多引擎烘托组件跟 pigeon 生成的文件结合起来的。即 Flutter Widget 基类的作用。
传送门
《从零开端|构建 Flutter 多引擎烘托组件:Flutter 代码篇》
感谢阅览,假如对你有用请点个赞 ❤️