面向移动端 MVP 的轻量 Flutter 脚手架:单包、浅层 feature-first、 Riverpod MVVM-lite。示例业务包含五 Tab、购物车分页、主题切换、全屏登录流程 和隐私/许可证入口。
项目使用 FVM 管理 Flutter:
fvm flutter pub get
fvm flutter analyze
fvm flutter test
fvm flutter run --dart-define=API_URL=https://your-api.example.com
dart run build_runner builddebug 未注入 API_URL 时使用 https://wanandroid.com/ 演示分页。release
必须同时注入自有 HTTPS API 和隐私政策,否则启动时主动拒绝继续:
fvm flutter build appbundle \
--dart-define=API_URL=https://api.example.com \
--dart-define=PRIVACY_URL=https://example.com/privacyAndroid release 还必须配置正式签名和应用 ID,缺少任一项时 Gradle 会失败, 不会回退 debug key:
export ANDROID_APPLICATION_ID=com.example.app
export ANDROID_APP_NAME='Example App'
export ANDROID_KEYSTORE_PATH=/absolute/path/upload.jks
export ANDROID_KEYSTORE_PASSWORD='***'
export ANDROID_KEY_ALIAS=upload
export ANDROID_KEY_PASSWORD='***'iOS 发布前在 Xcode 设置自己的 PRODUCT_BUNDLE_IDENTIFIER、
DEVELOPMENT_TEAM、显示名称和正式图标;仓库不携带个人 Team ID。
release 若仍使用 com.lyf.flutterscaffold 会在启动门禁中被拒绝。
| 能力 | 方案 |
|---|---|
| 状态与依赖注入 | Riverpod 3 Notifier / Provider |
| 路由 | GoRouter 18 StatefulShellRoute.indexedStack |
| 网络 | Dio 5 + retry/token/脱敏日志拦截器 |
| 普通 KV | MMKV,仅用于主题等非敏感偏好 |
| 鉴权凭证 | flutter_secure_storage(Keychain/Keystore) |
| 序列化 | json_serializable |
| 页面状态 | BaseWidget 五态 |
| 刷新分页 | easy_refresh |
| 全局反馈 | flutter_smart_dialog 薄封装 |
lib/
main.dart # 环境校验、错误钩子、存储与许可证初始化
app.dart # MaterialApp.router
router/app_router.dart # 页面装配,不向 feature 导出路径
core/
constants/env.dart # API_URL / PRIVACY_URL release 门禁
legal/ # 手工引入代码的许可证注册
log/log.dart # 不落盘的轻量日志门面
navigation/ # 路径常量、根 NavigatorKey
network/ # ApiClient、信封与三个拦截器
storage/ # MMKV 兜底、TokenStore 安全存储
theme/ # M3 主题与主题模式
widgets/ # 五态、反馈、刷新默认样式、WidgetX
features/
cart/ # model + repository + ViewModel + View
home|browse|message|mine/
login|settings/
依赖保持单向:router → features → core。路由路径位于
core/navigation/app_routes.dart,feature 不反向 import 路由装配文件;
业务 feature 之间不互相 import。
- View:Screen 和小型 Widget,只负责渲染、导航与 UI 回调映射。
- ViewModel:Riverpod
Notifier,持有不可变页面状态和并发规则。 - Model/Data:业务模型与 Repository 留在 feature 内,Repository 隔离协议。
- 静态展示页不强制创建空 ViewModel;不为 MVP 引入 UseCase/Mapper 多层仪式。
- 手写 Riverpod provider 默认常驻;页面/feature provider 显式使用
.autoDispose。全局连接池使用普通 provider,并在ref.onDispose释放资源;仅需临时保活 autoDispose provider 时才调用ref.keepAlive()。
购物车示例演示了首页加载、刷新、加载更多、跨页去重、到底、失败重试和 请求代际控制。刷新会废弃旧的在途加载更多结果,provider 销毁后异步响应不会 再写状态。
- release 只允许 HTTPS API,并要求配置隐私政策地址。
- Android 主 Manifest 包含联网权限,release 强制正式签名。
- access/refresh token 只走平台安全存储,不写 MMKV。
- 并发 401 只刷新一次;刷新成功写回安全存储,失败清空凭证。
- 网络日志递归脱敏、限制长度;release 不输出请求体和响应体。
- 日志不在设备持久化。接入 Sentry 等服务时仍需在
Log门面继续脱敏。
鉴权后端接入时覆盖 tokenRefreshCallbackProvider 和
tokenRefreshFailedCallbackProvider。刷新请求应使用独立 Dio,并通过
NetworkRequestExtras.isTokenRefresh/skipAuth 避免循环。
- 替换 bundle/application ID、应用名、图标、启动图和商店资料。
- 接入自己的鉴权刷新接口、登录态路由守卫及远端崩溃采集。
- 根据实际数据处理行为完成隐私政策、权限说明和应用商店隐私表单。
- 按业务增加本地化、无障碍、集成测试和发布 CI;不要把演示 API 当作生产 SLA。