# 应用启动与数据加载流程 对应代码:`lib/main.dart`、`lib/core/auth/auth_service.dart`、`lib/core/referrer/referrer_service.dart`、`lib/app.dart`、`lib/features/home/home_screen.dart`。 ## 总览(时序) ```mermaid sequenceDiagram participant Main as main() participant Ref as ReferrerService participant Adj as Adjust SDK participant Auth as AuthService.init participant API as 后端 API participant UI as App / HomeScreen Main->>Adj: initSdk + attributionCallback Main->>Ref: await init() 竞速归因并缓存 digest Main->>Auth: init() 不 await,后台执行 Main->>UI: runApp Auth->>Auth: delay 2s Auth->>Ref: getReferrer() 读缓存 Auth->>API: fast_login(digest=crest) Auth->>API: referrer(android_adjust) Auth->>API: referrer(gg) Auth->>API: common_info Auth->>UI: loginComplete / isLoginComplete UI->>API: HomeScreen._loadCategories 等 loginComplete 后 ``` ## 1. `main()` 中顺序(在 `runApp` 之前) | 步骤 | 说明 | |------|------| | `WidgetsFlutterBinding.ensureInitialized()` | Flutter 绑定 | | `_initAdjust()` | `Adjust.initSdk`,注册 `attributionCallback`(回调里会 `ReferrerService.receiveAttributionFromCallback`) | | `_initFacebookAppEvents()` | Facebook `activateApp` | | **`await ReferrerService.init()`** | 与 `getAttributionWithTimeout`、归因回调**竞速**,得到用于 **fast_login** 的 `crest`(Adjust Base64 优先,否则 Android Play Install Referrer),并写入内存缓存 | | `SystemChrome.setSystemUIOverlayStyle` | 状态栏样式 | | **`AuthService.init()`** | **不 await**,与 UI 首帧并行执行快速登录链路 | | `runApp(const App())` | 构建根组件 | | Android | `GooglePlayPurchaseService.startPendingPurchaseListener()` | | `AuthService.loginComplete.then(...)` | 登录 Future 完成后跑谷歌支付补单 `runOrderRecovery` | ## 2. `AuthService.init()`(后台异步) 1. **固定等待 2 秒**(缓解冷启动网络未就绪)。 2. 取 **deviceId**、**sign**(MD5(deviceId) 大写)。 3. **`ReferrerService.getReferrer()`**:通常直接命中 `init()` 阶段缓存,作为 **fast_login** 的 `digest`。 4. **`POST /v1/user/fast_login`**:最多重试 3 次;成功则设置 **token**、**userId**、积分与资料字段、首次安装时 Adjust register 等。 5. **`_reportBothReferrersAndRefreshCommonInfo`**(需已登录 uid) - 分别计算 **Adjust 专用 digest**、**Play Install Referrer(gg)**(`getAdjustReferrerDigest` / `getGgReferrerDigest`)。 - **顺序**调用两次 **`POST /v1/user/referrer`**:`accolade=android_adjust`、`accolade=gg`;**无论业务成功失败,均等待响应返回**后继续。 - 两次都结束后 **`GET /v1/user/common_info`** **一次**。 - 在 **`_saveCommonInfoToState`** 中解析 `surge` → **extConfig**(`need_wait`、`items`、`safe_area`、`lucky` 等)。 - 若 **`need_wait` 或 `items`** 相对应用前快照发生**结构性变化**,则 **`UserState.requestHomeFullReload()`**(首页完整重走分类 + 任务加载)。 6. **`finally`**:`loginComplete` 完成、`isLoginComplete = true`,去掉全屏登录等待遮罩。 ## 3. 首屏 UI 与首页数据 - **`App`**:`FutureBuilder` 监听 `AuthService.loginComplete`,未完成时叠一层半透明 + `CircularProgressIndicator`。 - **`HomeScreen`**:`initState` 里 **`_loadCategories()`** 会先 **`await AuthService.loginComplete`**,再请求分类接口;根据当前 **`UserState.needShowVideoMenu`** 决定是否追加 **pets** 分类;选中非 pets 时再拉视频任务列表。 - 监听 **`UserState.needShowVideoMenu` / `extConfigItems` / `isLoginComplete`** → `setState` 刷新展示。 - 监听 **`UserState.homeReloadNonce`** → 再次 **`_loadCategories()`**,用于 **need_wait 等变化**后重新走「加载分类 → 加载任务」。 ## 4. 与主页文档的关系 主页如何根据 **extConfig** 渲染分类栏与列表,见 [home.md](home.md) 与 [extConfig.md](extConfig.md)。