Files
conti-retail-app/README.md
T

191 lines
7.2 KiB
Markdown
Raw Normal View History

2026-08-17 15:29:55 +08:00
# conti-retail-app
大陆马门店 App。Flutter + Melos 单仓多包。
架构约束全部来自相邻仓库 `conti-docs/` 的 01–14 号文档。**本仓库对这些文档的
偏离,逐条记在 [SCAFFOLD-NOTES.md](SCAFFOLD-NOTES.md)**——那份文件是回写文档的
依据,改动之前先看一眼。
---
## 怎么跑起来
三步。不要跳过第二步。
```bash
# 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
```
2026-08-18 13:43:52 +08:00
- 或者安装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"
]
}
]
}
```
2026-08-17 15:29:55 +08:00
`--flavor` / `-t` / `--dart-define-from-file` **三个参数缺一不可**
- 少了 `--dart-define-from-file``AppEnv.fromDartDefine` 会在启动瞬间抛错。
这是故意的——带着空 baseUrl 跑起来,问题会在第一个请求 404 时才暴露。
- 少了 `-t`Flutter 会去找 `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 SDK`dart --version` 不等于 3.12.2),那么
```bash
dart run build_runner build # ← 会用错 SDK,报一堆看不懂的解析错误
```
要显式用 Flutter 自带的那个:
```bash
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.bat`git-bash 下直接敲 `melos` 可能找不到。用:
```bash
dart pub global run melos:melos <cmd>
```
## 常用命令
```bash
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_lint``flutter 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_auth`
`core_router → core_auth``core_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`](app/ios/FLAVORS.md)。目前没有 Mac 构建机。
- **native_scan 没有原生实现**Pigeon 接口和 Dart 侧齐了,Kotlin/Swift 侧是
模板。现在调 `startScan` 会抛 `MissingPluginException`,属预期。
- **神策 SDK 未采购**`analyticsProvider``NoopAnalytics`。接入时注意必须在
用户同意隐私政策之后再初始化。
- **env/*.json 里全是占位域名**`SENTRY_DSN` 全空,待运维确认。
- **CI 镜像名未定**`.gitlab-ci.yml` 里标了 TODO(ops)。