手把手教你入门Fair之脚本篇

240 阅读4分钟

Fair4.0更新已经有一段时间了,这次更新的一些新特性能够帮助我们更加高效地开发,这次就来简单聊聊目前Fair团队开源的脚本的使用方法。

生成Fair产物的脚本

我们知道,Fair是将 Dart 源文件转译成 DSL 通过下发 JSON 和 JS 来分别实现布局动态化和逻辑动态化,那么如何获得这个JSON和JS文件呢?首先我们需要用 @FairPatch注解标注想要实现动态化的组件,如果这个组件需要入参那么可以通过被 @FairProps标注的fairProps拿到(fairProps可以改成别的变量名,只要用 @FairProps标注就可以)。接着只需要运行脚本就可以在生成fair产物啦,那么这个脚本在哪获得呢?主要有两种途径。

  1. 从Fair项目里把build_runner.sh拷贝到自己的项目里
  2. 拷贝下面的代码到自己的项目里
 # 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系统组件/方法映射,具体使用方法如下:

  1. 从Fair项目库中拷贝example/bin目录下的全部内容到自己的项目中
  2. 设置好项目的flutter版本
  3. 运行bin/generated_module/flutter.dart
  4. flutter.dart会生成两个文件flutter.bindings.dartflutter.function.dart,如下图:

image-20241213172019437.png

其中flutter.bindings.dart是生成的flutter系统组件的映射,flutter.function.dart是flutter系统函数的映射。可以看到上面两个文件都有报错,没有关系,脚本并不是100%正确的,还有一部分错误需要我们自己处理

常见的错误类型有以下几种:

  • 缺少默认值

image-20241213172717227.png

这时候我们只需要点击进入文档里,看看对应的值是什么,将它复制出来就行

image-20241213173253481.png

修改后代码如下:

 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类型

image-20241213174959109.png

 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;
   }
 }
  • 类型转换错误,根据提示转换为正确类型即可

image-20241213174336004.png

 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

  1. 首先是在pubspec.yaml中导入第三方库,这里以下拉刷新库pull_to_refresh为例

image-20241213180945949.png

  1. 接着在bin/generated_module/binding.dart中导入第三方库的组件

image-20241213181311479.png 3. 然后运行bin/generated_module/packages.dart,生成packages.bindings.dartpackages.function.dart

  1. 手动处理报错

生成自定义组件/方法映射

导入自定义组件的方式跟导入第三方库非常类似,这次我们需要用到的脚本是bin/generated_module/app.dart

  1. 正常编写自定义组件
  2. bin/generated_module/binding.dart中导入组件
  3. 运行并处理报错

总结

本文介绍了Fair4.0提供的4个脚本的使用方法,能够帮助读者快速上手Fair,简化开发流程,降低使用成本。