Fair4.0更新已经有一段时间了,这次更新的一些新特性能够帮助我们更加高效地开发,这次就来简单聊聊目前Fair团队开源的脚本的使用方法。
生成Fair产物的脚本
我们知道,Fair是将 Dart 源文件转译成 DSL 通过下发 JSON 和 JS 来分别实现布局动态化和逻辑动态化,那么如何获得这个JSON和JS文件呢?首先我们需要用 @FairPatch注解标注想要实现动态化的组件,如果这个组件需要入参那么可以通过被 @FairProps标注的fairProps拿到(fairProps可以改成别的变量名,只要用 @FairProps标注就可以)。接着只需要运行脚本就可以在生成fair产物啦,那么这个脚本在哪获得呢?主要有两种途径。
- 从Fair项目里把build_runner.sh拷贝到自己的项目里
- 拷贝下面的代码到自己的项目里
# build_runner.sh
fvm flutter --version
echo "----- flutter version -----"
fvm flutter clean
echo "----- flutter clean finish -----"
fvm flutter pub get
#
#echo "----- flutter pub get finish -----"
#
fvm flutter pub run build_runner build --delete-conflicting-outputs
echo "----- flutter pub run build_runner build finish -----"
#rm -rf assets/fair
#mkdir assets/fair
for file in build/fair/*
do
if [ "${file##*.}"x = "json"x ] || [ "${file##*.}"x = "js"x ] || [ "${file##*.}"x = "bin"x ]
then
cp $file assets/fair
fi
done
echo "----- copy build/fair/* into assets/fair finish -----"
建议使用方法2,该脚本能够将生成的产物移动到asserts/fair
目录下,无需手动移动
生成flutter系统组件/方法映射
之前Fair能够使用的flutter版本有限,依赖于Fair团队适配的flutter版本,但是本次Fair4.0的更新支持用户自己使用脚本根据当前flutter版本生成flutter系统组件/方法映射,具体使用方法如下:
- 从Fair项目库中拷贝example/bin目录下的全部内容到自己的项目中
- 设置好项目的flutter版本
- 运行
bin/generated_module/flutter.dart
flutter.dart
会生成两个文件flutter.bindings.dart
和flutter.function.dart
,如下图:
其中flutter.bindings.dart是生成的flutter系统组件的映射,flutter.function.dart是flutter系统函数的映射。可以看到上面两个文件都有报错,没有关系,脚本并不是100%正确的,还有一部分错误需要我们自己处理
常见的错误类型有以下几种:
- 缺少默认值
这时候我们只需要点击进入文档里,看看对应的值是什么,将它复制出来就行
修改后代码如下:
const TextScaler _kUnspecifiedTextScaler = _UnspecifiedTextScaler();
// TODO(LongCatIsLooong): Remove once `MediaQueryData.textScaleFactor` is
// removed: https://github.com/flutter/flutter/issues/128825.
class _UnspecifiedTextScaler implements TextScaler {
const _UnspecifiedTextScaler();
@override
TextScaler clamp({double minScaleFactor = 0, double maxScaleFactor = double.infinity}) => throw UnimplementedError();
@override
double scale(double fontSize) => throw UnimplementedError();
@override
double get textScaleFactor => throw UnimplementedError();
}
Map<String, dynamic> flutterComponents = {
// 上边省略...
'MediaQueryData': (props) => MediaQueryData(
size: props['size'] ?? Size.zero,
devicePixelRatio: props['devicePixelRatio']?.toDouble() ?? 1.0,
textScaleFactor: props['textScaleFactor']?.toDouble() ?? 1.0,
textScaler: props['textScaler'] ?? _kUnspecifiedTextScaler,
platformBrightness: props['platformBrightness'] ?? Brightness.light,
padding: props['padding'] ?? EdgeInsets.zero,
viewInsets: props['viewInsets'] ?? EdgeInsets.zero,
systemGestureInsets: props['systemGestureInsets'] ?? EdgeInsets.zero,
viewPadding: props['viewPadding'] ?? EdgeInsets.zero,
alwaysUse24HourFormat: props['alwaysUse24HourFormat'] ?? false,
accessibleNavigation: props['accessibleNavigation'] ?? false,
invertColors: props['invertColors'] ?? false,
highContrast: props['highContrast'] ?? false,
onOffSwitchLabels: props['onOffSwitchLabels'] ?? false,
disableAnimations: props['disableAnimations'] ?? false,
boldText: props['boldText'] ?? false,
navigationMode: props['navigationMode'] ?? NavigationMode.traditional,
gestureSettings: props['gestureSettings'] ??
const DeviceGestureSettings(touchSlop: kTouchSlop),
displayFeatures: as<DisplayFeature>(props['displayFeatures']) ??
const <ui.DisplayFeature>[]),
// 下边省略...
}
- 导包错误
定位到对应位置手动导包即可
- 返回类型报错,当生成的产物带泛型T时,由于无法识别就会报错,可以修改为dynamic类型
mixin FlutterFunctionDynamicWidgetBuilder on DynamicWidgetBuilder {
dynamic convertFlutterFunction(BuildContext context, Map map, Map? methodMap,
{Domain? domain}) {
var name = map[tag];
if (name == 'FairFunction') {
var tag = FunctionDomain.getTag(map);
switch (tag) {
// 上边省略...
case 'T Function(Set<WidgetState>)':
List functionPaParameters = FunctionDomain.pa(map);
dynamic Function(Set<WidgetState>) builder = (p0) {
return pa0Value(
FunctionDomain.getBody(map),
methodMap,
context,
FunctionDomain(
{functionPaParameters[0]: p0},
parent: domain,
),
);
};
return builder;
// 下边省略
default:
}
}
return null;
}
}
- 类型转换错误,根据提示转换为正确类型即可
Map<String, dynamic> flutterComponents = {
// 上边省略...
'TwoDimensionalChildListDelegate': (props) => TwoDimensionalChildListDelegate(
addRepaintBoundaries: props['addRepaintBoundaries'] ?? true,
addAutomaticKeepAlives: props['addAutomaticKeepAlives'] ?? true,
children: as<List<Widget>>(props['children']) ?? const []),
// 下边省略...
}
生成第三方库组件/方法映射
大部分时候我们需要使用第三方库来实现一些功能,Fair4.0也支持使用脚本自动生成第三方库的组件/方法映射。大致的使用方法跟生成系统映射时类似,不过这次我们要用的是bin/generated_module/packages.dart
- 首先是在
pubspec.yaml
中导入第三方库,这里以下拉刷新库pull_to_refresh
为例
- 接着在
bin/generated_module/binding.dart
中导入第三方库的组件
3. 然后运行
bin/generated_module/packages.dart
,生成packages.bindings.dart
和packages.function.dart
- 手动处理报错
生成自定义组件/方法映射
导入自定义组件的方式跟导入第三方库非常类似,这次我们需要用到的脚本是bin/generated_module/app.dart
- 正常编写自定义组件
- 在
bin/generated_module/binding.dart
中导入组件 - 运行并处理报错
总结
本文介绍了Fair4.0提供的4个脚本的使用方法,能够帮助读者快速上手Fair,简化开发流程,降低使用成本。