Flutter插件功能集成插件merging_builder的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter插件功能集成插件merging_builder的使用

简介

源代码生成在构建和维护大量数据模型、数据访问对象、小部件等时已经成为一种重要的软件开发工具。源代码生成的前提是我们可以在编译时指定(希望是少量的)细节,并在构建过程中充实其余的类和方法。

merging_builder库提供了两个合成输入生成器类:

  • MergingBuilder读取多个输入文件并将合并后的输出写入一个输出文件。该生成器提供按反向拓扑顺序排序输入文件的选项。
  • StandaloneBuilder读取一个或多个输入文件并将独立文件写入自定义位置。这里的“独立”意味着输出文件可以写入自定义文件夹,不仅扩展名,而且输出文件的名称都可以配置。

使用步骤

1. 添加依赖项

在定义生成器的包的pubspec.yaml文件中添加merging_builderbuild作为依赖项。在这个例子中,生成器还需要analyzersource_gen包。

dependencies:
  merging_builder: ^latest_version
  build: ^latest_version
  analyzer: ^latest_version
  source_gen: ^latest_version

2. 创建自定义生成器

创建一个继承自MergingGenerator的自定义生成器。用户需要实现generateItemForAnnotatedElementgenerateMergedContent方法。

import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart' show BuildStep;
import 'package:merging_builder/merging_builder.dart';
import 'package:quote_buffer/quote_buffer.dart';
import 'package:source_gen/source_gen.dart' show ConstantReader;
import '../annotations/add_names.dart';

class AddNamesGenerator extends MergingGenerator<List<String>, AddNames> {
  static String get header => '/// Added names.';
  static String get footer => '/// This is the footer.';

  @override
  List<String> generateStreamItemForAnnotatedElement(
    Element element,
    ConstantReader annotation,
    BuildStep buildStep,
  ) {
    final result = <String>[];
    if (element is ClassElement) {
      final nameObjects = element.getField('names')?.computeConstantValue()?.toListValue();
      for (final nameObj in nameObjects ?? []) {
        result.add(nameObj.toStringValue());
      }
      return result;
    }
    return <String>['Could not read name'];
  }

  @override
  FutureOr<String> generateMergedContent(Stream<List<String>> stream) async {
    final b = StringBuffer();
    var i = 0;
    final allNames = <List<String>>[];
    await for (final names in stream) {
      b.write('final name$i = [');
      b.writelnAllQ(names, separator2: ',');
      b.writeln('];');
      ++i;
      allNames.add(names);
    }

    b.writeln('');
    b.writeln('final List<List<String>> names = [');
    for (var names in allNames) {
      b.writeln('  [');
      b.writelnAllQ(names, separator2: ',');
      b.writeln('  ],');
    }
    b.writeln('];');
    return b.toString();
  }
}

3. 创建MergingBuilder实例

通常将生成器放置在一个名为builder.dart的文件中,位于生成器包的lib文件夹中。

import 'package:build/build.dart';
import 'package:merging_builder/merging_builder.dart';

import 'src/generators/add_names_generator.dart';
import 'src/generators/assistant_generator.dart';

Builder addNamesBuilder(BuilderOptions options) {
  BuilderOptions defaultOptions = BuilderOptions({
    'input_files': 'lib/*.dart',
    'output_file': 'lib/output.dart',
    'header': AddNamesGenerator.header,
    'footer': AddNamesGenerator.footer,
    'sort_assets': true,
  });

  options = defaultOptions.overrideWith(options);
  return MergingBuilder<List<String>, LibDir>(
    generator: AddNamesGenerator(),
    inputFiles: options.config['input_files'],
    outputFile: options.config['output_file'],
    header: options.config['header'],
    footer: options.config['footer'],
    sortAssets: options.config['sort_assets'],
  );
}

Builder assistantBuilder(BuilderOptions options) {
  BuilderOptions defaultOptions = BuilderOptions({
    'input_files': 'lib/*.dart',
    'output_files': 'lib/output/assistant_(*).dart',
    'header': AssistantGenerator.header,
    'footer': AssistantGenerator.footer,
    'root': ''
  });
  options = defaultOptions.overrideWith(options);
  return StandaloneBuilder<LibDir>(
      generator: AssistantGenerator(),
      inputFiles: options.config['input_files'],
      outputFiles: options.config['output_files'],
      root: options.config['root']);
}

4. 配置生成器

在定义生成器的包中添加生成器配置。

builders:
  add_names_builder:
    import: "package:researcher_builder/builder.dart"
    builder_factories: ["addNamesBuilder"]
    build_extensions: {"lib/$lib$": ["lib/output.dart"]}
    auto_apply: root_package
    build_to: source
  assistant_builder:
    import: "package:researcher_builder/builder.dart"
    builder_factories: ["assistantBuilder"]
    build_extensions: {"lib/$lib$": ["*.dart"]}
    auto_apply: root_package
    build_to: source

5. 在使用生成器的包中配置build.yaml

targets:
  $default:
    builders:
      researcher_builder|add_names_builder:
        enabled: true
        options:
          input_files: 'lib/input/*.dart'
          output_file: 'lib/output/researchers.dart'
          sort_assets: false
          header: '// Header specified in build.yaml.'
          footer: '// Footer specified in build.yaml.'
      researcher_builder|assistant_builder:
        enabled: true
        options:
          input_files: 'lib/input/*.dart'
          output_files: 'lib/output/assistant_(*).dart'
          root: ''

6. 添加依赖项到使用生成器的包

在使用生成器的包的pubspec.yaml文件中添加researcher_builderbuild_runner作为开发依赖项。

name: researcher
description: Example demonstrating how to use the library merging_builder.

environment:
  sdk: '>=2.17.0 <3.0.0'

dev_dependencies:
  build_runner: ^1.10.0
  researcher_builder:
    path: ../researcher_builder

7. 启动构建过程

运行以下命令启动构建过程:

dart run build_runner build --delete-conflicting-outputs --verbose

示例项目结构

以下是示例项目的完整结构:

example/
├── researcher/
│   ├── lib/
│   │   └── input/
│   │       ├── researcher_a.dart
│   │       └── researcher_b.dart
│   └── pubspec.yaml
└── researcher_builder/
    ├── lib/
    │   ├── builder.dart
    │   └── generators/
    │       ├── add_names_generator.dart
    │       └── assistant_generator.dart
    └── pubspec.yaml

更多关于Flutter插件功能集成插件merging_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter插件功能集成插件merging_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter项目中集成和使用merging_builder插件,可以按照以下步骤进行。merging_builder插件通常用于在Flutter项目中合并多个构建配置或资源文件,但需要注意的是,具体的插件功能和API可能会因插件版本的不同而有所变化。下面是一个基本的集成和使用示例,但请务必查阅最新的插件文档以确保准确性。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加merging_builder插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  # 其他依赖...
  merging_builder: ^x.y.z  # 替换为最新版本号

dev_dependencies:
  build_runner: ^x.y.z  # 确保你使用的版本与插件兼容
  # 其他开发依赖...

然后,运行flutter pub get来安装依赖。

2. 配置build.yaml

接下来,你需要在项目的根目录下创建一个build.yaml文件,用于配置merging_builder插件。以下是一个示例配置,它将多个JSON文件合并为一个:

targets:
  $default:
    builders:
      merging_builder:
        enabled: true
        options:
          input_extension: .json
          output_extension: .merged.json
          output_file: merged_data.json

在这个配置中,input_extension指定了要合并的文件的扩展名(这里是.json),output_extension指定了输出文件的扩展名(这里是.merged.json,但在这个例子中实际上不会用到,因为output_file直接指定了输出文件名),output_file指定了合并后的输出文件名。

3. 准备输入文件

在你的项目目录中创建一个文件夹(例如assets/data),并在其中放置一些要合并的JSON文件,如data1.jsondata2.json

assets/data/data1.json:

{
  "key1": "value1",
  "key2": "value2"
}

assets/data/data2.json:

{
  "key3": "value3",
  "key4": "value4"
}

4. 运行构建脚本

在终端中,运行以下命令来执行merging_builder

flutter pub run build_runner build

如果配置正确,你应该会在项目的根目录下看到一个名为merged_data.json的文件,其内容将是data1.jsondata2.json的合并结果:

{
  "key1": "value1",
  "key2": "value2",
  "key3": "value3",
  "key4": "value4"
}

5. 在Flutter代码中使用合并后的文件

现在,你可以在Flutter代码中加载并使用这个合并后的JSON文件。例如,使用rootBundle来读取文件:

import 'dart:convert';
import 'package:flutter/services.dart';

Future<Map<String, dynamic>> loadMergedData() async {
  final String response = await rootBundle.loadString('merged_data.json');
  return jsonDecode(response) as Map<String, dynamic>;
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Merged Data Example'),
        ),
        body: FutureBuilder<Map<String, dynamic>>(
          future: loadMergedData(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              } else {
                Map<String, dynamic> data = snapshot.data!;
                // 使用合并后的数据...
                return ListView.builder(
                  itemCount: data.keys.length,
                  itemBuilder: (context, index) {
                    Map.Entry<String, dynamic> entry = data.entries.elementAt(index);
                    return ListTile(
                      title: Text('${entry.key}: ${entry.value}'),
                    );
                  },
                );
              }
            } else {
              return CircularProgressIndicator();
            }
          },
        ),
      ),
    );
  }
}

这个示例代码展示了如何在Flutter应用中加载并使用合并后的JSON数据。请确保你已经正确配置了pubspec.yamlbuild.yaml文件,并且已经运行了构建脚本。

注意:以上代码和配置是基于一个假设的插件功能和API。实际使用时,请查阅merging_builder插件的官方文档以获取最新的配置和使用方法。

回到顶部