一步到位:用 Very Good CLI × Bloc × go_router 打好 Flutter 工程地基

目录

  1. 创建flutter项目
  2. [国际化:l10n 带来的不仅是翻译](#国际化:l10n 带来的不仅是翻译 "#2-%E5%9B%BD%E9%99%85%E5%8C%96l10n-%E5%B8%A6%E6%9D%A5%E7%9A%84%E4%B8%8D%E4%BB%85%E6%98%AF%E7%BF%BB%E8%AF%91")
  3. [路由:为什么选 go_router?](#路由:为什么选 go_router? "#3-%E8%B7%AF%E7%94%B1%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89-go_router")
  4. [状态管理:Cubit + Bloc + Repository 分层模型](#状态管理:Cubit + Bloc + Repository 分层模型 "#4-%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86cubit--bloc--repository-%E5%88%86%E5%B1%82%E6%A8%A1%E5%9E%8B")
  5. 错误提示策略:SnackbarMessage
  6. [资源管理:flutter_gen 的价值](#资源管理:flutter_gen 的价值 "#6-%E8%B5%84%E6%BA%90%E7%AE%A1%E7%90%86flutter_gen-%E7%9A%84%E4%BB%B7%E5%80%BC")
  7. 调试与可观测性

在开发一个 Flutter 应用时,通常需要考虑以下几个方面:

  • 国际化(i18n):支持多语言,提升用户体验;
  • 状态管理:管理页面之间或组件之间的数据状态;
  • 资源引入:如图片、字体等静态资源的管理与使用;
  • 路由管理:实现页面跳转和导航逻辑;
  • 用户状态切换:处理未登录到已登录状态的转变;
  • 错误提示机制:如登录失败时的错误反馈展示。

本文将以一个 Instagram 登录页为例,从 0 开始搭建一个 Flutter 项目,逐步实现上述功能,构建一个可持续开发的项目架构。本文完整代码:github.com/wutao23yzd/... 中的Demo5,效果如下:

1.创建flutter项目

创建flutter项目,采用very_good_cli,(pub.dev/packages/ve... 创建 Flutter 项目的好处在于,它提供了规范化的项目结构、严格的代码分析规则、内建测试和 CI 支持,帮助开发者快速搭建高质量、可维护的应用,特别适合团队协作和企业级项目开发。通过如下指令,可以创建一个指定组织名和包名的flutter应用

css 复制代码
very_good create flutter_app flutter_instagram_clone_app --org "com.flutter" --application-id "com.flutter.futter_instagram_clone"

2. 国际化 (l10n)

l10n 是 "localization" 的缩写(l + 10个字母 + n),即"本地化/国际化"。very_good_cli创建好项目后,会自动生成国际化相关文件,但没有中文,可以这样子添加:

  • 在 pubspec.yaml 中确保已经添加了 flutter_localizations 依赖。
  • 在 l10n.yaml 配置文件中添加中文(zh)支持。
markdown 复制代码
# 添加中文支持
preferred-supported-locales:
  - en
  - zh
  • 在 arb 目录下添加中文的 ARB 文件(如 app_localizations_zh.arb),并翻译内容
  • 添加新的文案时,使用flutter gen-l10n 重新生成本地化代码。

3. 路由:为什么选 go_router

路由使用go_routterpub.dev/packages/go... 是 Flutter 官方推荐的路由管理库,,支持嵌套路由、参数传递、URL 同步、重定向和导航守卫等高级功能。相比传统的 Navigator,它结构更清晰、代码更简洁,而且支持基于用户登录状态的路由重定向逻辑,比如登录、登出,可以通过如下代码跳转:

ini 复制代码
  redirect: (context, state) {
      final authenticated = appBloc.state.status == AppStatus.authenticated;
      final authenticating = state.matchedLocation == AppRoutes.auth.route;

      if (!authenticated) return AppRoutes.auth.route;
      if (authenticating && authenticated) return AppRoutes.home.route;

      return null;
  }

4. 状态管理:Cubit + Bloc + Repository 分层模型

在 Flutter 项目中,采用 Cubit + Bloc + Repository 的分层模型 是一种清晰、可维护性强的架构设计。它将业务逻辑、状态管理和数据访问进行职责分离(pub.dev/packages/bl...

  • Repository 层负责与数据源(如 API、数据库、缓存)交互,提供统一的数据获取接口。
  • Bloc/Cubit 层负责管理状态和业务逻辑,从 Repository 获取数据并根据用户行为更新状态。
  • **UI 层(Widget)**只关心状态展示,通过监听 Bloc/Cubit 提供的状态流进行响应式更新。

在提供的Demo中,AuthRepository 统一产出 用户身份流,任何需要身份信息的层(AppBloc)都只订阅这一个来源。

scala 复制代码
class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return RepositoryProvider(
      // 全局唯一的数据层
      create: (_) => AuthRepository(),
      child: BlocProvider(
        create: (context) => AppBloc(
          authRepository: context.read<AuthRepository>(),
        ),
        child: const AppView(),
      ),
    );
  }
}
  • app.dart 顶层依赖注入,暴露一个Stream表示全局身份状态。
  • LoginCubit 只负责表单状态与调用 AuthRepository.login
  • AppBloc 只订阅 AuthRepository.user,再映射成 authenticated / unauthenticated

这样 UI ↔︎ 业务 ↔︎ 数据 的依赖方向清晰且单向。


5. 错误提示策略:SnackbarMessage 队列化

使用BlocListener<LoginCubit, LoginState>监听当前状态,如果出现错误,则顶部弹出提示;使用clearIfQueue 清除旧消息 。

dart 复制代码
BlocListener<LoginCubit, LoginState>(
  listenWhen: (p, c) => p.status != c.status && c.status.isError,
  listener: (_, s) => openSnackbar(
    SnackbarMessage.error(title: '错误', description: s.message!),
    clearIfQueue: true,
  ),
  child: const LoginForm(),
);

6. 资源管理:flutter_gen 的价值

首先要要安装flutter_gen 依赖,同时在dev_dependencies中,需要安装

makefile 复制代码
build_runner: ^2.5.4
flutter_gen_runner: ^5.10.0

对于svg的文件,还需要安装依赖flutter_svg;然后按照demo中所示,在pubspec.yaml中提供资源所示路径;最后,执行dart run build_runner build自动生成assets.gen.dart 文件,引用资源文件如下所示:

dart 复制代码
Image.asset(Assets.images.logoPng.path);
FontFamily(Assets.fonts.montserrat);  // 类型安全 + IDE 自动补全
  • 不再担心路径拼写错误
  • 对 Lottie / SVG 同样适用

7. 调试与可观测性

dart 复制代码
class AppBlocObserver extends BlocObserver {
  @override
  void onChange(BlocBase bloc, Change change) =>
      log('[Bloc] ${bloc.runtimeType} $change');
}
  • 实时跟踪 Bloc / Cubit 状态变迁
  • Flutter DevTools:开启 "Enhance tracing for user widgets"

写在最后

Demo大量代码使用了www.youtube.com/watch?v=xr5...

相关推荐
笑尘pyrotechnic8 小时前
DocC的简单使用
ios·objective-c
谈吐大方的鹏sir9 小时前
SwiftUI-Text组件学习
ios
你听得到1110 小时前
Flutter - 手搓一个日历组件,集成单日选择、日期范围选择、国际化、农历和节气显示
前端·flutter·架构
不自律的笨鸟11 小时前
iOS 26,双版本更新来了
ios·iphone
RaidenLiu14 小时前
Flutter Shader预热技术解析与实践指南
flutter·前端框架
归辞...16 小时前
「iOS」————消息传递和消息转发
ios
他们都不看好你,偏偏你最不争气1 天前
iOS —— 天气预报仿写总结
ios
ITfeib1 天前
Flutter基础
flutter
RaidenLiu1 天前
RepaintBoundary是什么?怎么用?
flutter
白玉cfc1 天前
【iOS】网易云仿写
ui·ios·objective-c