从零搭建到长期维护:一套面向真实业务的 Flutter 基础框架

很多 Flutter 项目在启动阶段都会重复经历同一套流程:配置路由、封装 Dio、定义请求结果、编写页面基类,再补齐按钮、弹窗、输入框、主题和资源目录。

这些工作并不复杂,却会持续消耗时间。更重要的是,如果项目从一开始缺少统一边界,随着业务增长和人员协作,路由、网络请求、公共组件与业务代码很容易逐渐混在一起。

因此,一套有价值的 Flutter 基础框架,不应该只是几个 Demo 页面或简单脚手架,而应该是一份能够直接复制、快速启动,并支持长期维护的母版工程。

一、框架解决的核心问题

这套框架面向实际业务项目,重点沉淀以下通用能力:

  • 应用启动与入口配置

  • 页面基类与页面状态管理

  • 路由统一管理

  • 网络请求统一封装

  • H5 页面容器

  • 通用组件和工具类

  • 代码风格与目录职责约束

它更适合持续迭代的业务项目,而不是只用于展示效果的示例工程。其目标可以概括为四点:

  1. 减少新项目重复搭建基础设施的时间;

  2. 统一多人协作时的代码组织方式;

  3. 降低入口、路由和公共能力的修改成本;

  4. 避免项目扩大后框架层与业务层边界失控。

二、框架的核心优势

1. 复制模板即可进入业务开发

路由、网络层、页面基类、通用组件、开屏页和主题资源等能力已经提前整理。创建新项目时,可以直接复制模板,从配置层和业务层开始填充内容,而不必再次从零搭建基础结构。

2. 目录职责清晰,降低维护成本

框架提前明确了常见公共能力应该放在哪里:

  • 路由由 router/ 统一管理;

  • 网络能力集中在 net/

  • 页面基础抽象放在 base/

  • 跨模块组件放在 widgets/

  • 全局配置集中在 common/

  • 业务页面统一进入 pages/

清晰的边界可以让新成员更快理解项目,也能避免公共逻辑散落在各个业务页面中。

3. 启动入口集中配置

应用名称、项目标识、开屏页开关、开屏页路由和首页路由统一维护在:

lib/common/app_definition.dart

例如,项目是否启用开屏页、启动后进入哪个首页,都可以在统一位置调整,不必在多个文件中查找跳转逻辑。

4. 完整的页面基础抽象

框架保留了一组适合真实业务落地的页面基类:

  • BasePage

  • BasePageState

  • BasePageNormalState

  • BaseListPageState

  • BaseListNormalPageState

  • PageConfig

这些抽象用于统一处理页面标题栏、返回逻辑、状态栏、通用布局,以及 loadingfailnormal 等页面状态。列表页面还可以在统一结构中实现刷新和加载更多,避免每个页面重复编写相似逻辑。

5. 标准化网络请求层

网络层使用统一请求封装与适配器模式,主要包括:

  • DioNet

  • ApiBaseAdapter<T>

  • DataResult

  • ApiCode

  • TokenInterceptor

页面不直接耦合裸 Dio,请求结果通过统一结构返回,不同接口则可以按适配器拆分。这种设计为后续加入 Token、公共请求头、错误处理和日志等能力预留了清晰的扩展位置。

6. 可复用的 H5 容器

框架内置通用 Web 容器页、路由入参结构,以及可选的 H5 预加载服务,可用于承载:

  • 用户协议与隐私政策;

  • 活动页和 Web 落地页;

  • 后端动态下发页面;

  • 其他轻量混合业务页面。

这样可以避免不同业务模块反复实现 WebView 容器。

三、整体目录结构

lib/
  app.dart
  main.dart
  base/
  common/
  event/
  net/
  pages/
  provider/
  res/
  router/
  services/
  utils/
  widgets/

目录数量不是重点,重点是每一层都有明确职责。

main.dart:应用启动入口

负责启动 Flutter、执行最早期初始化,并运行根应用。该文件应尽量保持简洁,避免堆积业务逻辑。

app.dart:根应用配置

负责 Provider 注册、Theme 与 Router 挂载,以及全局 MaterialApp 的组织。

common/:全局配置与常量

当前重点包括:

  • app_definition.dart

  • constant.dart

主要用于维护应用名称、启动入口、项目常量和通用 Key。

base/:页面基础抽象

提供页面壳子、页面状态切换、列表页基础能力和 MVP 结构壳子,是整个框架的核心层之一。

router/:统一路由层

集中维护路由常量、路由分发、全局导航入口和路由监听,避免页面之间通过零散字符串互相跳转。

net/:网络请求层

统一请求入口、返回结构、接口常量、拦截器和适配器模式。页面只关心请求参数和业务结果,不需要重复处理底层通信细节。

res/:资源规范层

集中维护主题、字号、间距和颜色规则。框架只定义颜色文件的组织方式和命名约定,不预设具体业务颜色,使模板能够适配不同项目的视觉体系。

widgets/:通用组件层

可放置按钮、输入框、弹窗、底部弹窗、空态、加载框、AppBar 和 WebContainer 等跨业务模块复用的组件,但不应承载某个业务模块的专属 UI。

provider/:共享状态层

用于承载会话状态、配置状态、本地设置状态和通用列表状态。框架保留状态管理的扩展壳子,但不绑定具体登录模型和业务字段。

services/:基础服务层

用于存放相对独立的基础服务,例如 WebView 预加载能力。

utils/:轻量工具层

用于维护权限、Toast、正则和通用辅助函数。工具类应保持职责单一,避免最终演变成无边界的“大杂烩”。

pages/:业务页面层

模板只保留必要的占位入口页,不塞入大量业务页面。原因很简单:这是一套基础模板,提供的是稳定的工程壳子,而不是特定业务内容。

四、开屏页与首页入口设计

启动入口往往是新项目中改动最频繁的部分。有的项目需要开屏页,有的直接进入首页,还有的需要先判断登录状态或展示引导页。

为避免入口逻辑散落,框架通过 lib/common/app_definition.dart 集中维护:

  • AppIdentity.appName

  • AppLaunchConfig.enableSplashPage

  • AppLaunchConfig.splashPageRoute

  • AppLaunchConfig.homePageRoute

框架还提供默认占位开屏页:

lib/pages/splash/default_splash_page.dart

它并非正式业务开屏页,而是用于保证模板的启动链路完整,同时向接手者展示开屏页的替换方式。复制模板后,即使尚未编写业务页面,也能够获得完整、清晰的启动流程。

五、规范比目录本身更重要

基础框架不仅要提供文件,还要提供稳定的扩展方式。因此,项目通过 CODE_STYLE_GUIDE.md 约定代码风格与目录边界。

基础文件需要说明用途

每个基础文件都应说明它负责什么、应该如何使用。模板未来可能由不同成员维护,清晰注释可以显著降低理解成本。

目录之间必须有边界

并不是所有公共代码都应该进入 utils/,也不是所有 UI 代码都适合放进 widgets/。只有先明确职责,团队才能长期维持一致的项目结构。

公共层保持去业务化

框架层应尽量避免绑定:

  • 特定用户或商品模型;

  • 某个业务接口路径;

  • 某个项目专属流程;

  • 具体品牌的颜色与视觉规则。

只有保持通用,基础模板才具备跨项目复制的价值。

扩展时优先使用已有抽象

例如:

  • 普通页面优先复用 BasePageNormalState

  • 列表页面优先复用 BaseListNormalPageState

  • 接口适配优先复用 ApiBaseAdapter<T>

这能避免项目中出现多套功能相似、结构不同的平行实现。

六、适用场景

中小型、持续迭代的业务团队

当项目需要长期维护、人员可能发生轮换时,统一的页面、网络和目录规范可以降低交接成本。

经常创建多个项目的团队

如果团队频繁启动相似业务,不必每次重新配置基础设施。复制母版后,修改入口和项目配置即可进入业务开发。

有 Flutter 与 H5 混合需求的项目

对于经常承载协议、活动页、落地页或动态 Web 内容的应用,统一 WebContainer 和预加载能力会更实用。

重视长期维护的项目

如果目标不是完成短期 Demo,而是让项目能够持续扩展并被其他开发者接手,那么规范化基础框架通常比轻量脚手架更有价值。

七、边界与设计取舍

为了保证通用性,这套模板做了三项明确取舍。

不内置大量业务页面

业务页面越多,模板越重,也越容易携带特定项目的设计假设。模板只提供页面结构和必要占位入口。

不预定义业务颜色

不同项目的品牌和视觉风格差异很大,因此框架只保留集中式颜色文件、注释分区与命名规则,实际色值由具体项目定义。

不绑定具体登录模型

登录字段和流程通常存在较大差异。框架只保留会话、配置和本地设置等状态管理壳子,不预设具体业务模型。

八、后续演进方向

在保持“只扩展通用层、不侵入业务层”的前提下,框架还可以从以下方向继续完善。

1. 补充项目初始化指南

整理项目名、包名、应用显示名、开屏页、首页、主题和接口地址的修改步骤,让新成员能够更快完成初始化。

2. 提供脚本化改名能力

可以进一步实现项目名、包名和显示名的一键替换,减少复制模板后的机械操作。

3. 丰富通用基础组件

后续可以按真实项目需求逐步加入:

  • 通用 Tab 容器;

  • 通用筛选栏;

  • 通用分页请求工具;

  • 通用表单校验规则。

新增能力仍需遵循同一个原则:只沉淀跨项目可复用的基础设施,不把具体业务带入模板。

九、总结

一套 Flutter 基础框架的价值,不在于目录多、文件多,而在于它是否提前整理了真实业务中最容易重复、最容易混乱,也最值得统一的部分。

这套模板通过集中入口配置、页面状态抽象、统一路由、标准化网络层、H5 容器、通用组件和代码规范,提供了一份可直接复制并持续扩展的工程母版。

如果希望 Flutter 项目从第一天开始就拥有清晰边界,并在多人协作与长期迭代中保持稳定,那么先建立统一的基础框架,往往比直接从空工程堆叠业务代码更值得投入。