接入友盟统计与 U-APM,并优化宣传页打卡点标签交互。

友盟 SDK 改为隐私同意后再初始化;宣传页标签新增滑块位移动画,超过 5 个时选中项自动滚动居中。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-03 09:23:15 +08:00
parent c7f557f361
commit 00c3cd0a93
134 changed files with 6555 additions and 590 deletions

View File

@ -24,6 +24,7 @@ App 模块负责应用入口、根视图切换、全局状态注入、主导航
- `SessionBootstrapper`:冷启动时读取本地 token 和账号快照,并向服务端校验登录态。
- `AccountContextLoader`:统一同步用户资料、角色权限、景区和门店。
- `AppServiceEnvironment.swift`:为无 UI 状态的服务定义 SwiftUI `EnvironmentKey`,供 View 通过 `@Environment(\.xxxAPI)` 读取。
- `UMengSDKBootstrap`:友盟统计与 U-APM 的隐私合规初始化入口,只在用户同意隐私政策且 AppKey 非空后初始化。
## 依赖注入:为何 API 走 Environment 而非单例
@ -81,31 +82,42 @@ SwiftUI 的 `Environment` 在本项目中是**依赖注入DI通道**,不
> 完整启动接口清单、数据依赖与 Splash 优化方案见 [启动流程分析与优化方案](../../docs/startup-analysis.md)。
1. `suixinkanApp` 创建 `RootView`
1. `suixinkanApp` 处理 UI Test 冷启动状态清理并创建 `RootView`
2. `RootView` 初始化共享依赖,并把它们注入 Environment。
3. iOS 系统 Launch Screen 展示品牌页白底、Logo、文案
4. `RootView` 挂载后在 bootstrap 完成前以 `SplashView` 覆盖根视图,避免空白或登录页闪屏。
5. `APIClient` 绑定 `AppSession.token` 作为默认 token provider。
6. `SessionBootstrapper.restore` 尝试从 UserDefaults 读取正式 token
7. 无 token 时保持 `loggedOut`,展示 `LoginView`
8. token 时进入 `restoring`,先恢复本地账号快照
9. 阻塞请求 `rolePermissions` 成功后立即 `markLoggedIn` 并展示 `MainTabsView`
10. `userInfo``scenicListAll``storeAll` 在后台补充刷新,不阻塞首屏
11. `ScenicSpotContext` 按当前景区懒加载景点/打卡点
12. 明确 token 失效时清空 token 和账号快照,回到登录页
13. 普通网络失败时保留本地登录态,使用账号快照进入主界面
14. 冷启动 bootstrap 不使用 Lottie 全局 Loading`.restoring` 期间展示 `SplashView`
15. `LoginView` 首屏出现后调用 `/api/app/config` 加载远程配置(如 `enable_register`),失败静默
6. 如果本地已记录用户同意隐私政策,则初始化高德与友盟 SDK否则不触发第三方 SDK 初始化
7. `SessionBootstrapper.restore` 尝试从 UserDefaults 读取正式 token
8. token 时保持 `loggedOut`,展示 `LoginView`
9. 有 token 时进入 `restoring`,先恢复本地账号快照
10. 阻塞请求 `rolePermissions` 成功后立即 `markLoggedIn` 并展示 `MainTabsView`
11. `userInfo``scenicListAll``storeAll` 在后台补充刷新,不阻塞首屏
12. `ScenicSpotContext` 按当前景区懒加载景点/打卡点
13. 明确 token 失效时清空 token 和账号快照,回到登录页
14. 普通网络失败时保留本地登录态,使用账号快照进入主界面
15. 冷启动 bootstrap 不使用 Lottie 全局 Loading`.restoring` 期间展示 `SplashView`
16. `LoginView` 首屏出现后调用 `/api/app/config` 加载远程配置(如 `enable_register`),失败静默。
## 初始化分层
| 阶段 | 职责 | 主要对象 |
|------|------|----------|
| App 入口 | UI Test 状态清理、后续可扩展 SDK 初始化 | `suixinkanApp``AppUITestLaunchState` |
| App 入口 | UI Test 状态清理 | `suixinkanApp``AppUITestLaunchState` |
| 冷启动恢复 | Launch Screen + Splash 覆盖 bootstrap | `SplashView``SessionBootstrapper``AccountContextLoader` |
| 首屏出现后 | 页面级远程配置 | `LoginView``AppConfigAPI` |
| 登录后 | 推送、景点列表、排队 WebSocket | `PushNotificationManager``ScenicSpotContext` |
## 第三方 SDK 隐私门禁
高德与友盟 SDK 均由 `RootView` 在隐私政策已同意后初始化,不再由 `suixinkanApp.init()` 直接触发。隐私同意状态保存在 `AppPreferencesStore`
- 首次冷启动未同意时,不初始化高德、友盟统计或 U-APM。
- 登录页校验确认已同意后,`AuthSessionCoordinator.savePrivacyAgreementAccepted(true)` 会先持久化状态,再触发第三方 SDK 初始化。
- 后续冷启动读取到已同意状态时,会自动初始化第三方 SDK。
- 退出登录只清空 token 和账号快照,保留隐私同意状态。
友盟配置集中在 `UMengConfig``appKey` 为空时 `UMengSDKBootstrap` 不会调用友盟 SDK便于在未配置真实 AppKey 前保持构建可用。U-APM 首版采用最小合规采集范围开启崩溃、卡顿和启动分析关闭网络分析、内存、OOM 与日志回捞。
## UI Test 启动约定
- `AppUITestLaunchState` 在收到 `-suixinkan-ui-tests` 时跳过推送注册和排队 WebSocket避免系统弹窗干扰自动化。