Refactor AppServices into assembly, feature facades, and lifecycle coordinator.
Extract dependency wiring and session lifecycle from the container and RootViewController, split NetworkBundle by domain, and add module-level feature services while keeping flat accessors for compatibility. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -13,7 +13,10 @@ App 模块负责应用入口、根视图切换、全局状态注入、主导航
|
||||
## 核心对象
|
||||
|
||||
- `AppDelegate` / `SceneDelegate`:UIKit 应用入口;`SceneDelegate` 挂载 `RootViewController` 并持有其强引用。
|
||||
- `AppServices`:全局依赖容器(Composition Root),等价于参考工程 SwiftUI `RootView` 中的 Environment 注入;内部按 Session / Context / Network / UI / Runtime 分组,对外仍保留扁平属性访问。
|
||||
- `AppServices`:全局依赖容器(Composition Root),等价于参考工程 SwiftUI `RootView` 中的 Environment 注入;自身只持有 Session / Context / Network / UI / Runtime 分组和导航器。
|
||||
- `AppServicesAssembly`:负责创建生产或测试依赖图,避免装配细节堆在容器本体中。
|
||||
- `AppFeatureServices`:按业务域提供模块级 Facade,避免页面散取全局 API、Context、Toast、Loading 和运行时依赖。
|
||||
- `AppSessionLifecycleCoordinator`:处理冷启动恢复、登录后景点刷新、登出清理和推送授权;`RootViewController` 只负责根控制器切换。
|
||||
- `RootViewController`:监听 `AppSession.phase`,未登录时在自身上展示登录/恢复页,登录后将 `MainTabBarController` 设为 window 根控制器,并挂载全局 Toast / Loading。
|
||||
- `AppSession`:保存认证阶段和正式 token,只负责登录态,不承载业务资料。
|
||||
- `AccountContext`:保存当前账号资料、景区作用域和门店作用域。
|
||||
@ -27,7 +30,19 @@ App 模块负责应用入口、根视图切换、全局状态注入、主导航
|
||||
|
||||
## AppServices 依赖约定
|
||||
|
||||
`AppServices.shared` 是唯一 Composition Root,集中创建 `APIClient`、各业务 API 与全局 Context,并绑定 token provider。
|
||||
`AppServices.shared` 是唯一 Composition Root,通过 `AppServicesAssembly` 集中创建 `APIClient`、各业务 API 与全局 Context,并绑定 token provider。
|
||||
|
||||
`AppServices` 本体保持轻量:只保存已装配的依赖分组、绑定跨分组关系和暴露 App 生命周期入口。兼容旧调用的扁平属性统一放在 `AppServices+Accessors.swift`,新增复杂业务不得继续塞进容器本体。
|
||||
|
||||
`NetworkBundle` 内部按业务域拆分为 Account / Commerce / Operation / Content 四组,所有 API 仍共享同一 `APIClient`。旧的 `services.ordersAPI`、`services.profileAPI` 等扁平访问器继续保留,仅作为兼容层。
|
||||
|
||||
新增页面优先通过模块 Facade 获取依赖:
|
||||
|
||||
- `ordersFeatureServices`:订单 API、景区/门店/角色、订单导航、Toast / Loading。
|
||||
- `profileFeatureServices`:登录、资料、账号上下文和退出登录清理。
|
||||
- `homeFeatureServices`:首页菜单、账号权限上下文和首页导航。
|
||||
- `assetsFeatureServices`:资产 API、OSS 上传、当前景区和云传记录仓库。
|
||||
- `queueFeatureServices`:排队 API、用户/景区/景点上下文和排队运行时。
|
||||
|
||||
### 何时通过 `init(services:)` 注入
|
||||
|
||||
@ -56,16 +71,17 @@ ViewModel **不持有** `AppServices`。View 从容器取出具体依赖,在 `
|
||||
|
||||
- `PushNotificationManager.shared`:`AppDelegate` 回调桥
|
||||
- `CloudTransferStore.shared`:跨页面云传任务状态
|
||||
- `ScenicQueueRuntime.shared`:跨页面排队轮询、后台任务和语音播报运行时
|
||||
- 第三方 SDK(如 `AMapServices`)
|
||||
|
||||
`AppSession`、`AccountContext`、各 `*API` 等**不应**拆成多个 `.shared`,须由 `AppServices` 统一创建,并在登出时由 `RootViewController` 统一 reset。
|
||||
`AppSession`、`AccountContext`、各 `*API`、`AppNavigator`、持久化 Store 等**不应**拆成多个 `.shared`,须由 `AppServices` 统一创建,并在登出时由 `AppSessionLifecycleCoordinator` 统一 reset。
|
||||
|
||||
## 启动流程
|
||||
|
||||
1. `AppDelegate` 创建 `RootViewController(services: .shared)`。
|
||||
2. `AppServices` 初始化共享依赖(`NetworkBundle` 内共享同一 `APIClient`)。
|
||||
2. `AppServices` 初始化共享依赖(`NetworkBundle` 子分组内共享同一 `APIClient`)。
|
||||
3. `APIClient` 绑定 `AppSession.token` 作为默认 token provider。
|
||||
4. `SessionBootstrapper.restore` 尝试从 Keychain 读取正式 token。
|
||||
4. `AppSessionLifecycleCoordinator` 调用 `SessionBootstrapper.restore` 尝试从 Keychain 读取正式 token。
|
||||
5. 无 token 时保持 `loggedOut`,展示 `LoginViewController`。
|
||||
6. 有 token 时进入 `restoring`,先恢复本地账号快照。
|
||||
7. `AccountContextLoader` 并行请求用户资料和角色权限,再补全景区与门店。
|
||||
|
||||
Reference in New Issue
Block a user