2026-08-18 13:43:52 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-17 15:29:55 +08:00
2026-08-18 13:43:52 +08:00
2026-08-17 15:29:55 +08:00

conti-retail-app

大陆马门店 App。Flutter + Melos 单仓多包。

架构约束全部来自相邻仓库 conti-docs/ 的 0114 号文档。本仓库对这些文档的 偏离,逐条记在 SCAFFOLD-NOTES.md——那份文件是回写文档的 依据,改动之前先看一眼。


怎么跑起来

三步。不要跳过第二步。

# 0. 工具链(一次性)
fvm use 3.44.9                       # 或者保证 PATH 上的 flutter 就是 3.44.9
dart pub global activate melos 8.2.2

# 1. 装依赖
melos bootstrap

# 2. 生成代码(riverpod 的 *.g.dart 不入库,不跑这步全仓库编译不过)
melos run gen

# 3. 跑起来
cd app
flutter run --flavor dev -t lib/main_dev.dart --dart-define-from-file=env/dev.json
  • 或者安装vscodeflutter插件并修改launch.json F5运行
{
  "version": "0.0.1",
  "configurations": [
    {
      "name": "Flutter Dev (Web)",
      "request": "launch",
      "type": "dart",
      "program": "app/lib/main_dev.dart",
      "flavor": "dev",
      "deviceId": "chrome",
      "toolArgs": [
        "--dart-define-from-file=env/dev.json"
      ]
    }
  ]
}

--flavor / -t / --dart-define-from-file 三个参数缺一不可

  • 少了 --dart-define-from-fileAppEnv.fromDartDefine 会在启动瞬间抛错。 这是故意的——带着空 baseUrl 跑起来,问题会在第一个请求 404 时才暴露。
  • 少了 -tFlutter 会去找 lib/main.dart,本仓库没有这个文件。

VS Code / Android Studio 用户建议把三条 flavor 配进 launch.json

环境与工具链版本

跑通时的实测版本,与 pubspec.lock 一致:

版本 备注
Flutter 3.44.9 .fvmrc 里锁着
Dart 3.12.2 Flutter 自带的那个,见下面的坑
Melos 8.2.2 配置内联在根 pubspec.yaml,没有 melos.yaml
flutter_riverpod 3.3.2
riverpod_annotation 4.0.3
riverpod_generator 4.0.4
build_runner 2.15.1
analyzer 12.1.0

riverpod 的版本被 flutter_test 卡着。 flutter_test pin 了 test_api 0.7.11,往上升 riverpod 会拉起不兼容的 analyzer,解析直接失败。 想升级先确认这条链路,不要只看 pub.dev 上的最新版。

坑:机器上有两个 Dart SDK

如果你的 PATH 上装了独立的 Dart SDKdart --version 不等于 3.12.2),那么

dart run build_runner build     # ← 会用错 SDK,报一堆看不懂的解析错误

要显式用 Flutter 自带的那个:

export FDART="$(dirname "$(which flutter)")/cache/dart-sdk/bin/dart"
$FDART run build_runner build
# fvm 用户:~/fvm/versions/stable/bin/cache/dart-sdk/bin/dart

melos run gen 内部走的是 dart run,所以同样受影响。最省事的做法是让 PATH 上只有 Flutter 自带的 Dart。

坑:melos 命令

pub cache 里只有 melos.batgit-bash 下直接敲 melos 可能找不到。用:

dart pub global run melos:melos <cmd>

常用命令

melos run gen         # 代码生成(riverpod
melos run gen:watch   # 开发期常驻
melos run gen:pigeon  # native_* 的 Pigeon 产物(产物入库)
melos run analyze     # flutter analyze --fatal-infos,含 riverpod_lint
melos run format      # dart format --set-exit-if-changed
melos run test        # flutter test --coverage

analyze--fatal-infos。不加等于没加 lint——绝大多数 riverpod_lint 规则 报的是 info 级。

riverpod_lintflutter analyze 直接执行(顶层 plugins: 映射),不再 需要 custom_lint,也没有 dart run custom_lint 这一步。文档 03/14 写的还是 旧方案,见 SCAFFOLD-NOTES §B。

包结构与依赖规则

app/                    壳工程。唯一知道所有包的地方:环境注入、启动编排、路由聚合
packages/
  core_foundation/      AppEnv / AppException 体系 / ApiCode        ← 叶子包,谁都能依赖
  core_logging/         AppLogger / CrashReporter / 脱敏
  core_analytics/       Analytics 接口 + 事件常量表
  core_storage/         PrefsKV)。Drift 暂缓,见 SCAFFOLD-NOTES
  core_auth/            AppSession 四态 / TokenStorage / SessionNotifier
  core_network/         dio + 4 个拦截器 + ApiClient
  core_router/          goRouterProvider / menuRouteMap / go_router re-export
  core_ui/              主题 / AsyncValueView / ErrorPresenter
  core_webview/         UrlGuard / JSBridge / WebViewSession
  feature_auth/         登录、选店
  feature_home/         工作台
  native_scan/          Pigeon 扫码接口(原生实现待补)

依赖规则(01):

  • feature_* → core_* / native_*feature 之间禁止互相依赖——两个 feature 要共享东西,说明那个东西属于某个 core_*。
  • core_* → core_* 只允许三条边:core_network → core_authcore_router → core_authcore_webview → core_auth。外加所有包都可以依赖 叶子包 core_foundation
  • native_* 只依赖 Flutter SDK 和 Pigeon 产物,一个 core_ 都不依赖*。
  • feature 的 pubspec 里不出现 go_router:路由类型由 core_router re-export。

这些规则靠 --fatal-infos 守,不是靠编译器(实测结论)

直觉上会以为「没在 pubspec 里声明就 import 不到」。在 Pub Workspace 里这是错的 所有成员包共用根目录一份 .dart_tool/package_config.json,任何成员都能解析到 任何其他成员。实测在 feature_home 里 import feature_auth 而不声明依赖:

flutter test     → All tests passed!        ← 编译通过,跑得起来
flutter analyze  → info: depend_on_referenced_packages

只有一条 info。所以:

melos run analyze--fatal-infos 是这套包边界唯一的强制点。 谁把它从 CI 里拿掉,或者在某个包里 ignore 掉 depend_on_referenced_packages,边界当天就失效,而且没有任何别的信号。

想自己复现:在 feature_home/lib/src/ 下扔一个 import feature_auth 的文件, flutter test 是绿的,flutter analyze --fatal-infos 是红的。

那些 throw UnimplementedError('必须在 bootstrap 里 override')

依赖规则会挡住一些合理的调用(比如 core_auth 想发 HTTP、core_webview 想 换票)。这些地方一律用依赖反转解决:包内声明 abstract interface + 一个会抛错 的 provider,实现落在 app/lib/bootstrap.dart 里 override 进去。

新增一个这样的端口时,必须同时在 bootstrap 里接上——它是运行期才炸的, 编译器帮不了你。

待办 / 阻塞项

  • iOS flavor 未配置Scheme 和 Build Configuration 只能在 Xcode 里建, 步骤见 app/ios/FLAVORS.md。目前没有 Mac 构建机。
  • native_scan 没有原生实现Pigeon 接口和 Dart 侧齐了,Kotlin/Swift 侧是 模板。现在调 startScan 会抛 MissingPluginException,属预期。
  • 神策 SDK 未采购analyticsProviderNoopAnalytics。接入时注意必须在 用户同意隐私政策之后再初始化。
  • env/*.json 里全是占位域名SENTRY_DSN 全空,待运维确认。
  • CI 镜像名未定.gitlab-ci.yml 里标了 TODO(ops)。
S
Description
No description provided
Readme
369 KiB
Languages
Dart 87.7%
Swift 6.5%
Kotlin 5.3%
Ruby 0.5%