2025 Flutter Boilerplate 实战指南:7步构建企业级跨平台应用架构

【免费下载链接】flutter_boilerplate_project A boilerplate project created in flutter using MobX and Provider. 【免费下载链接】flutter_boilerplate_project 项目地址: https://gitcode.com/gh_mirrors/fl/flutter_boilerplate_project

开篇:为什么你需要这套架构解决方案?

你是否还在为Flutter项目的状态管理混乱而头疼?
是否每次新建项目都要重复搭建路由、网络、存储等基础模块?
是否因团队协作时代码风格不统一而降低开发效率?

本文将带你基于 Flutter Boilerplate 项目(集成MobX+Provider架构),通过7个实战步骤从零构建可直接投入生产的应用框架。读完本文你将掌握
✅ 企业级项目目录规范与依赖注入实现
✅ 响应式状态管理(MobX)与表单验证全流程
✅ 多主题切换与国际化方案
✅ 网络请求封装与本地数据持久化
✅ 性能优化与代码生成技巧

项目速览:架构设计与核心优势

技术栈选型

模块功能 技术选型 核心优势
状态管理 MobX + Provider 响应式编程,减少样板代码
依赖注入 GetIt 松耦合架构,便于单元测试
网络请求 Dio 拦截器支持,统一错误处理
本地存储 Sembast + SharedPreferences 轻量级NoSQL,支持加密存储
路由管理 自定义路由表 集中式路由配置,支持深层链接
代码生成 build_runner + mobx_codegen 自动生成状态管理代码

架构流程图

mermaid

注:采用Clean Architecture分层思想,实现数据层与UI层完全解耦

步骤1:环境搭建与项目初始化

开发环境要求

# pubspec.yaml 核心依赖节选
environment:
  sdk: '>=3.0.6 <4.0.0'
  
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  dio: ^5.1.1                # 网络请求
  mobx: ^2.1.4               # 状态管理核心
  flutter_mobx: ^2.0.6+5     # Flutter状态管理
  get_it: ^7.2.0             # 依赖注入
  sembast: ^3.4.4            # 本地数据库
  shared_preferences: ^2.1.0 # 轻量级存储

快速启动命令

# 克隆项目
git clone https://gitcode.com/gh_mirrors/fl/flutter_boilerplate_project.git
cd flutter_boilerplate_project

# 安装依赖
flutter pub get

# 生成必要文件(状态管理、路由等)
flutter packages pub run build_runner build --delete-conflicting-outputs

# 运行项目
flutter run

⚠️ 注意:首次运行需执行代码生成命令,否则会报MobX相关错误

步骤2:项目结构深度解析

lib/
├── constants/        # 应用常量(主题、尺寸、字符串)
├── core/             # 核心模块(网络、存储、状态管理)
├── data/             # 数据层(仓库实现、数据源)
├── domain/           # 领域层(实体、用例、仓库接口)
├── presentation/     # 表现层(页面、组件、状态)
├── di/               # 依赖注入配置
└── utils/            # 工具类

关键目录说明

目录 作用说明 核心文件示例
core/stores MobX状态管理 login_store.dart
data/repository 数据仓库实现 post_repository_impl.dart
domain/usecase 业务逻辑用例 login_usecase.dart
di 依赖注入配置 service_locator.dart

步骤3:依赖注入实现与服务定位

依赖注入(DI)是实现松耦合架构的关键,本项目使用GetIt实现服务定位:

// lib/di/service_locator.dart
final getIt = GetIt.instance;

mixin ServiceLocator {
  static Future<void> configureDependencies() async {
    // 数据层注入
    await DataLayerInjection.configureDataLayerInjection();
    // 领域层注入
    await DomainLayerInjection.configureDomainLayerInjection();
    // 表现层注入
    await PresentationLayerInjection.configurePresentationLayerInjection();
  }
}

注入示例:注册登录用例

// 注册单例
getIt.registerLazySingleton<LoginUseCase>(
  () => LoginUseCase(
    repository: getIt<AuthRepository>(),
  ),
);

// 使用方式
final loginUseCase = getIt<LoginUseCase>();

优势:测试时可轻松替换为Mock实现,无需修改业务代码

步骤4:状态管理与表单验证(MobX实战)

登录状态管理实现

// lib/presentation/login/store/login_store.dart
part 'login_store.g.dart';

class UserStore = _UserStore with _$UserStore;

abstract class _UserStore with Store {
  final LoginUseCase _loginUseCase;

  @observable
  bool isLoading = false;

  @observable
  String errorMessage = '';

  @action
  Future login(String email, String password) async {
    isLoading = true;
    errorMessage = '';
    
    try {
      final params = LoginParams(username: email, password: password);
      final result = await _loginUseCase.call(params: params);
      
      if (result != null) {
        // 登录成功处理
        isLoggedIn = true;
      }
    } catch (e) {
      errorMessage = e.toString();
    } finally {
      isLoading = false;
    }
  }
}

表单验证实现

// 表单验证Store
class FormErrorStore = _FormErrorStore with _$FormErrorStore;

abstract class _FormErrorStore with Store {
  @observable
  String email = '';

  @observable
  String password = '';

  @computed
  bool get canLogin => 
      email.isEmpty == false && 
      password.isEmpty == false &&
      _isEmailValid(email);

  bool _isEmailValid(String email) {
    return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(email);
  }
}

UI组件中使用Store

// 登录页面
class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final UserStore _userStore = getIt<UserStore>();
  final FormErrorStore _formStore = getIt<FormErrorStore>();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Observer(
        builder: (_) => _userStore.isLoading 
            ? ProgressIndicatorWidget()
            : _buildLoginForm(),
      ),
    );
  }
  
  Widget _buildLoginForm() {
    return Column(
      children: [
        TextFieldWidget(
          hint: 'Email',
          onChanged: (value) => _formStore.setEmail(value),
          errorText: _formStore.emailError,
        ),
        TextFieldWidget(
          hint: 'Password',
          isObscure: true,
          onChanged: (value) => _formStore.setPassword(value),
          errorText: _formStore.passwordError,
        ),
        RoundedButtonWidget(
          buttonText: 'Sign In',
          onPressed: _formStore.canLogin ? _userStore.login : null,
        ),
      ],
    );
  }
}

步骤5:主题切换与国际化实现

主题配置

// lib/constants/app_theme.dart
class AppThemeData {
  static ThemeData lightThemeData = themeData(lightColorScheme);
  static ThemeData darkThemeData = themeData(darkColorScheme);

  static ThemeData themeData(ColorScheme colorScheme) {
    return ThemeData(
      colorScheme: colorScheme,
      textTheme: GoogleFonts.montserratTextTheme(),
      appBarTheme: AppBarTheme(
        backgroundColor: colorScheme.background,
        elevation: 0,
      ),
    );
  }
  
  static const ColorScheme lightColorScheme = ColorScheme(
    primary: Color(0xFFd21e1d), // 红色主色调
    background: Color(0xFFE6EBEB),
    // ...其他颜色定义
  );
  
  static const ColorScheme darkColorScheme = ColorScheme(
    primary: Color(0xFFFF8383), // 亮红色主色调
    background: Color(0xFF241E30),
    // ...其他颜色定义
  );
}

主题切换实现

// 主题Store
class ThemeStore = _ThemeStore with _$ThemeStore;

abstract class _ThemeStore with Store {
  @observable
  bool _darkMode = false;

  @computed
  bool get darkMode => _darkMode;

  @action
  void changeBrightnessToDark(bool value) {
    _darkMode = value;
    // 保存主题偏好
    _saveThemePreference(value);
  }
  
  Future<void> _saveThemePreference(bool isDarkMode) async {
    await _sharedPreferencesHelper.setDarkMode(isDarkMode);
  }
}

多语言支持

项目通过assets/lang目录下的JSON文件实现国际化:

// assets/lang/en.json
{
  "login_btn_sign_in": "Sign In",
  "login_et_user_email": "Email",
  "login_et_user_password": "Password"
}

// assets/lang/zh.json
{
  "login_btn_sign_in": "登录",
  "login_et_user_email": "邮箱",
  "login_et_user_password": "密码"
}

使用方式:

AppLocalizations.of(context).translate('login_btn_sign_in')

步骤6:网络请求与本地存储

Dio网络请求封装

// lib/core/network/dio/dio_client.dart
class DioClient {
  final Dio _dio;

  DioClient(this._dio) {
    _dio.options.baseUrl = NetworkConstants.baseUrl;
    _dio.options.connectTimeout = Duration(milliseconds: 5000);
    _dio.interceptors.add(LoggingInterceptor());
    _dio.interceptors.add(AuthInterceptor());
  }

  Future<T> get<T>(String path, {
    Map<String, dynamic>? queryParameters,
    Options? options,
  }) async {
    try {
      final response = await _dio.get(
        path,
        queryParameters: queryParameters,
        options: options,
      );
      return response.data;
    } catch (e) {
      throw NetworkExceptions.getDioException(e);
    }
  }
  
  // ...post/put/delete等方法
}

本地数据持久化

使用Sembast实现本地数据库存储:

// lib/data/local/datasources/post/post_datasource.dart
class PostDataSource {
  final Database _database;
  final StoreRef _postStore = intMapStoreFactory.store('posts');

  PostDataSource(this._database);

  Future<int> insert(Post post) async {
    return await _postStore.add(_database, post.toJson());
  }

  Future<List<Post>> getAllSortedByFilter({List<Filter>? filters}) async {
    final finder = Finder(
      filters: filters,
      sortOrders: [SortOrder(DBConstants.FIELD_ID)],
    );
    
    final recordSnapshots = await _postStore.find(_database, finder: finder);
    return recordSnapshots.map((snapshot) {
      final post = Post.fromJson(snapshot.value);
      return post;
    }).toList();
  }
}

步骤7:性能优化与最佳实践

代码生成技巧

使用build_runner自动生成MobX代码:

# 单次构建
flutter pub run build_runner build --delete-conflicting-outputs

# 监听文件变化自动构建
flutter pub run build_runner watch

生成的文件会以.g.dart为后缀,例如login_store.g.dart,包含状态管理的样板代码。

隐藏生成文件

在IDE中隐藏生成文件,提高代码可读性:

Android Studio:
Preferences > Editor > File Types 添加忽略:
*.inject.summary;*.inject.dart;*.g.dart;

VS Code:
settings.json 中添加:

"files.exclude": {
  "**/*.inject.summary": true,
  "**/*.inject.dart": true,
  "**/*.g.dart": true
}

性能优化建议

  1. 状态管理优化

    • 拆分大型Store为多个小型Store
    • 使用Observer包裹最小UI范围
  2. 网络优化

    • 实现请求缓存策略
    • 添加重试机制处理网络波动
  3. UI优化

    • 使用const构造函数创建静态Widget
    • 避免在build方法中创建对象

项目实战:登录功能完整实现

下面通过登录功能展示完整的业务流程实现:

1. 定义实体类

// domain/entity/user/user.dart
class User {
  final int id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
    );
  }
}

2. 实现UseCase

// domain/usecase/user/login_usecase.dart
class LoginUseCase extends UseCase<User?, LoginParams> {
  final AuthRepository _authRepository;

  LoginUseCase(this._authRepository);

  @override
  Future<User?> call({required LoginParams params}) {
    return _authRepository.login(params.username, params.password);
  }
}

class LoginParams {
  final String username;
  final String password;

  LoginParams({required this.username, required this.password});
}

3. 实现Repository

// data/repository/auth/auth_repository_impl.dart
class AuthRepositoryImpl extends AuthRepository {
  final AuthApi _authApi;
  final AuthDataSource _authDataSource;

  AuthRepositoryImpl(this._authApi, this._authDataSource);

  @override
  Future<User?> login(String username, String password) async {
    try {
      // 远程登录
      final user = await _authApi.login(username, password);
      // 本地缓存
      await _authDataSource.saveUser(user);
      return user;
    } catch (e) {
      // 处理异常
      throw NetworkExceptions.getExceptionMessage(e);
    }
  }
}

4. UI实现

// presentation/login/login.dart
class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final UserStore _userStore = getIt<UserStore>();
  final FormErrorStore _formStore = getIt<FormErrorStore>();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: Padding(
          padding: EdgeInsets.all(24),
          child: Column(
            children: [
              AppIconWidget(image: 'assets/icons/ic_appicon.png'),
              SizedBox(height: 24),
              _buildEmailField(),
              _buildPasswordField(),
              _buildLoginButton(),
            ],
          ),
        ),
      ),
    );
  }
  
  Widget _buildLoginButton() {
    return RoundedButtonWidget(
      buttonText: AppLocalizations.of(context).translate('login_btn_sign_in'),
      onPressed: () {
        if (_formStore.canLogin) {
          _userStore.login(
            _emailController.text,
            _passwordController.text,
          );
        }
      },
    );
  }
}

总结与进阶方向

通过本文7个步骤,你已掌握基于Flutter Boilerplate构建企业级应用的核心技能。下一步进阶方向

  1. 单元测试实现:使用mockito模拟依赖,编写Store和UseCase测试
  2. CI/CD配置:配置GitHub Actions实现自动构建与测试
  3. 性能监控:集成Firebase Performance或自定义监控工具
  4. 功能扩展:实现推送通知、离线支持等高级功能

项目完整代码:git clone https://gitcode.com/gh_mirrors/fl/flutter_boilerplate_project.git

如果觉得本文对你有帮助,请点赞+收藏,关注作者获取更多Flutter实战教程!
(下期待续:Flutter Boilerplate项目的单元测试与持续集成)

【免费下载链接】flutter_boilerplate_project A boilerplate project created in flutter using MobX and Provider. 【免费下载链接】flutter_boilerplate_project 项目地址: https://gitcode.com/gh_mirrors/fl/flutter_boilerplate_project

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐