Flutter用例生成插件usecase_generator的使用

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

Flutter用例生成插件usecase_generator的使用

插件介绍

usecase_generator 是一个用于从 repository 类生成 usecase 类的生成器包。它需要 usecase_annotation 包来注解类。

使用步骤

  1. 添加依赖项:

    • pubspec.yaml 文件中添加 usecase_annotationusecase_generator 作为 dev_dependencies,同时添加 build_runner 作为 dev_dependencies。
    dependencies:
      flutter:
        sdk: flutter
      usecase_annotation: latest
      usecase_generator: latest
      build_runner: any
    
    dev_dependencies:
      flutter_test:
        sdk: flutter
      build_runner: any
    
  2. 创建 auth_repo.dart 类文件,并使用 @UseCase@UseCase() 注解你的 repo 类以生成每个函数的 `usease 类:

    @UseCase()
    abstract class AuthRepository {
      void m1();
      Future<String> m2(int param1);
    }
    
    class AuthRepositoryImpl implements AuthRepository {
      // Concrete implementation
    }
    
  3. 运行构建命令:

    flutter packages pub run build_runner build --delete-conflicting-outputs
    

    这将生成 auth_repo.uc.dart 文件中的类,如 M1UseCase 调用 authRepository.m1()M2UseCase 调用 authRepository.m2()

  4. 如果希望所有 usecase 文件位于同一目录下,请在 pubspec.yaml 文件旁边创建一个 build.yaml 文件,并在此文件中添加以下内容:

    targets:
      $default:
        builders:
          usecase_generator|usecase_gen:
            options:
              build_extensions:
                "^lib/domain/repositories/{{}}.dart": "lib/domain/usecases/{{}}.uc.dart",
    
  5. 动机 此包遵循 Uncle Bob 的干净架构方法,为您的仓库类创建 usecase 类。

  6. Riverpod DI 该包支持 Riverpod 靠注入。您需要在 pubspec.yaml 文件中添加 flutter_riverpod 包。

    targets:
      $default:
        builders:
          usecase_generator|usecase_gen:
            options:
              isInjectableDI: false
    

    若要关闭河浦 DI,请将 isInjectableDI 设置为 true

  7. Injectable DI 该包也可以与 injectable 包一起工作。首先将 isInjectableDI 设置为 true。 然后,在 build.yaml 文件中添加以下内容:

    targets:
      $default:
        builders:
          injectable_generator:injectable_builder:
            options:
              auto_register: true
              class_name_pattern: "UseCase$"
          usecase_generator|usecase_gen:
            options:
              isInjectableDI: true
    

示例代码

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  // This widget is the home page of your application. It it has a State object
  // (defined below) that contains fields that affect how it looks.

  // This class is the configuration for the state. It it holds the values
  // (in this case the title) provided by the parent (in this case the App widget)
  // and used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          // Column is also a layout widget. it takes a list of children and
          // arranges them vertically. By default, it sizes itself to fit its
          // children horizontally, and tries to be as tall as its parent.
          //
          // Invoke "debug painting" (press "p" in the console, choose the
          // "Toggle Debug Paint" action from the Flutter Inspector in Android
          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
          // to see the wireframe for each widget.
          //
          // Column has various properties to control how it sizes itself and
          // how it positions its children. here we use mainAxisAlignment to
          // center the children vertically; the main axis here is the vertical
          // axis because Columns are vertical (the cross axis would be
          // horizontal).
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

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

1 回复

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


当然,以下是如何在Flutter项目中使用usecase_generator插件的一个代码案例。usecase_generator插件通常用于生成干净架构中的用例(Use Case)代码模板,以简化开发流程。以下是一个基本的设置和使用指南。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加usecase_generator的依赖:

dependencies:
  flutter:
    sdk: flutter
  # 其他依赖...

dev_dependencies:
  build_runner: ^2.1.4
  usecase_generator: ^最新版本号  # 请替换为当前最新版本号

2. 获取最新版本号

由于我无法实时获取最新版本号,你可以访问pub.dev查看最新版本号并替换。

3. 创建用例文件

接下来,你需要定义你的用例。通常,用例文件会包含输入和输出数据类。

定义输入和输出数据类

创建一个data文件夹,并在其中创建两个Dart文件:input.dartoutput.dart

data/input.dart

class GetUserInput {
  final String userId;

  GetUserInput({required this.userId});
}

data/output.dart

class GetUserOutput {
  final String? userName;
  final String? errorMessage;

  GetUserOutput({this.userName, this.errorMessage});

  bool get isSuccess => errorMessage == null;
}

定义用例

创建一个usecases文件夹,并在其中创建一个Dart文件,例如get_user_usecase.dart。在这个文件中,你将使用usecase_generator注解来定义用例。

usecases/get_user_usecase.dart

import 'package:dartz/dartz.dart';
import 'package:usecase_generator/usecase_generator.dart';
import 'package:your_app/data/input.dart';
import 'package:your_app/data/output.dart';

@UseCase(
  inputs: [GetUserInput],
  outputs: [GetUserOutput],
)
class GetUserUseCase {
  Future<Either<String, GetUserOutput>> call(GetUserInput input) async {
    // 模拟获取用户数据的逻辑
    if (input.userId == 'valid_user') {
      return right(GetUserOutput(userName: 'John Doe'));
    } else {
      return left('Invalid user ID');
    }
  }
}

4. 生成用例代码

在项目的根目录下运行以下命令以生成用例代码:

flutter pub run build_runner build

usecase_generator将会根据注解生成相应的用例实现代码。通常,这些生成的代码会放在build/generated文件夹中,但通常你不需要直接操作这些文件,因为插件已经为你处理了大部分样板代码。

5. 使用生成的用例

你可以在需要的地方注入并使用生成的用例。例如,在一个ViewModel或者Repository中:

import 'package:your_app/usecases/get_user_usecase.g.dart'; // 导入生成的用例

class UserViewModel {
  final GetUserUseCase _getUserUseCase;

  UserViewModel(this._getUserUseCase);

  Future<void> fetchUserData(String userId) async {
    final result = await _getUserUseCase(GetUserInput(userId: userId));
    // 处理结果
    if (result.isRight()) {
      print('User Name: ${result.value.userName}');
    } else {
      print('Error: ${result.left}');
    }
  }
}

注意,这里的GetUserUseCase是通过依赖注入的方式传递的,你可以使用你喜欢的依赖注入框架(如get_itprovider)来实现。

总结

通过上述步骤,你可以使用usecase_generator插件来自动生成Flutter项目中的用例代码,从而简化开发流程并保持代码结构清晰。希望这个代码案例对你有所帮助!

回到顶部