client_framework/docs/video_home_data_flow.md
2026-04-16 17:00:55 +08:00

8.2 KiB
Raw Blame History

视频首页数据获取流程(以首款换皮应用 FunyMee 为参考)

本文描述框架侧在典型换皮应用(首款为 FunyMee)中,从冷启动到「视频首页」可展示分类与模板列表的数据链路与调用顺序。FunyMee 宿主 UI 不在本仓库内;流程以 client_proxy_framework 中的 FrameworkAuthServiceExtConfigRuntimeVideoHomeRuntimeImageApi 为准,与代码注释中引用的线网接口(如 GET /v1/image/img2video/tasks)一致。


1. 前提与配置

  1. ClientBootstrap.initFromAsset:加载 skin_config.json,构建 SkinConfigApiClient.init使后续请求走统一代理、AES 与 V2 包装(见 lib/src/bootstrap/client_bootstrap.dart)。
  2. FrameworkAuthService.init + start:宿主实现 AuthServiceCallbacks(设备 ID、签名等由框架编排登录与 common_info(见 lib/src/services/auth_service.dart)。
  3. skin_config.json 中与首页相关的片段:
    • extConfigkeys.showVideoMenu 映射到线网布尔(示例中为 go_run / need_wait 等,见 lib/src/config/skin_config.example.jsonitemstaskItemMapping 决定 common_info 下发的运营位卡片如何解析为与任务列表同形的 ExtConfigItem
    • videoHomeimagesTabLabelimagesTabFirst 控制「Images」虚拟 Tab 的文案及与接口分类的排序(见 lib/src/config/skin_config.dart)。
  4. fieldMappingFunyMee 等换皮下线网字段与逻辑字段不一致时,响应体会先经映射再进入实体解析(注释示例见 lib/src/services/image_api.dart)。

2. 总览时序

sequenceDiagram
  participant Host as 宿主 main / UI
  participant Boot as ClientBootstrap
  participant Auth as FrameworkAuthService
  participant User as UserApi / ProxyClient
  participant Ext as ExtConfigRuntime
  participant VH as VideoHomeRuntime
  participant Img as ImageApi

  Host->>Boot: initFromAsset(skin_config)
  Host->>Auth: init(callbacks); start()
  Auth->>User: POST /v1/user/fast_login
  User-->>Auth: userToken, userId
  Auth->>User: GET /v1/user/common_info
  User-->>Auth: extConfig 等
  Auth->>Ext: applyCommonInfoSuccess
  Auth->>VH: hydrateAfterCommonInfo (异步)
  VH->>Img: GET /v1/image/img2video/categories
  Img-->>VH: 分类列表
  VH->>VH: 合并 Tabs接口分类 + ext items → Images
  VH->>Img: GET /v1/image/img2video/tasks?categoryId=…
  Img-->>VH: 当前分类模板列表

3. 分阶段说明

3.1 启动与快速登录

  • 延迟与重试策略由 FrameworkAuthService.start 控制(默认启动延迟、登录重试等)。
  • UserApi.fastLoginPOST /v1/user/fast_login。请求头pkg不带 User_token(见 UserApi 文档注释)。
  • 成功后框架将返回的 userToken 写入 ApiClient.instance.setUserToken,此后代理请求自动附带 pkgUser_token(见 ProxyClient 行为与 UserApi 说明)。

3.2 归因上报(与首页数据并行准备)

  • 在拉取 common_info 之前,若存在 Adjust / Play 等 referrer会依次调用 UserApi.referrerPOST /v1/user/referrer)上报,不阻塞后续 common_info 的成功与否结论,但属于同一 _reportReferrersAndLoadCommonInfo 流程(见 auth_service.dart)。

3.3 通用信息与 extConfig

  • UserApi.getCommonInfoGET /v1/user/common_infoquery 含 appiOS/Android 后端渠道,与 skin_config.backend 一致)、pkguserIddeviceId 等(见 user_api.dart)。
  • 成功时调用 ExtConfigRuntime.applyCommonInfoSuccess
    • extConfig 与本地 extConfig.defaults 浅合并;
    • extConfigKeySchema 解析为 ExtConfigData(含 showVideoMenuitems 等)(见 ext_config_runtime.dartext_config_models.dart)。
  • ExtConfigRuntime.commonInfoSucceeded:宿主可用「登录完成且 common_info 成功」再展示主业务界面(见 ext_config_runtime.dart 注释建议)。

3.4 视频首页运行时水合hydrate

common_info 成功后,FrameworkAuthServicefire-and-forget 调用 VideoHomeRuntime.hydrateAfterCommonInfo(不阻塞 loginComplete 的完成)(见 auth_service.dart)。

hydrateAfterCommonInfo 的进入条件与行为(见 video_home_runtime.dart

条件 行为
userId 为空,或 ExtConfigData.showVideoMenu != true VideoHomeRuntime.reset,不拉分类、无 images Tab
否则 snapshot.loading = true,再请求分类列表

水合步骤概要:

  1. ImageApi.getCategoryListGET /v1/image/img2video/categories,得到服务端分类(CategoryItem,含 id / name)。
  2. ExtConfigRuntime.data 读取 items,过滤 ExtConfigItem.isUsableOnHome,非空则存在 Images 虚拟 Tab文案为 AppConfig.videoHomeImagesTabLabel(来自 skin_config.videoHome.imagesTabLabel)。
  3. Tab 顺序:由 videoHomeImagesTabFirst 决定是先 Images 还是先接口分类。
  4. 默认选中 Tab:默认选中第一个服务端分类(非 Images若仅有 Images Tab 则下标为 0并发水合与用户提前切换时有保护逻辑video_home_runtime.dart 内注释)。
  5. 水合结束后调用 VideoHomeRuntime.ensureTabItems(selectedTabIndex),为当前 Tab 拉取模板数据(见下节)。

若分类接口失败且没有任何 Tab 可构建,snapshot.error 会携带失败信息。

3.5 按 Tab 拉取模板列表

  • Images Tab:数据直接来自 ExtConfigData.items(已在水合前解析),不再请求 img2video/tasks
  • 服务端分类 Tab:首次选中该 Tab 时,VideoHomeRuntime.ensureTabItems 调用 ImageApi.getImg2VideoTasks(categoryId: id)GET /v1/image/img2video/tasks?categoryId=...(与 FunyMee 文档一致)。结果通过 ExtConfigItem.fromTaskItem 写入 VideoHomeSnapshot.networkItemsByCategoryId,并按分类 id 缓存,避免重复请求。

4. 宿主 UI 对接要点

  • 监听状态VideoHomeRuntime.snapshotVideoHomeRuntime.selectedTabIndexValueNotifier,可用 ValueListenableBuilder 或类似方式驱动顶栏 Tab 与内容区。
  • 切换 Tab:切换 selectedTabIndex 后应调用 VideoHomeRuntime.ensureTabItems(newIndex)(框架水合末尾已对初始 Tab 调用一次),以按需加载该分类下的模板列表。
  • 登录 / common_info 失败ExtConfigRuntime.commonInfoSucceeded == falseuserId 为空时,不会进入视频首页水合;宿主应展示错误态或重试入口。

5. 相关 HTTP 接口汇总

顺序 方法 路径 用途
1 POST /v1/user/fast_login 设备登录,取得 token
2 POST /v1/user/referrer 可选,归因上报
3 GET /v1/user/common_info 开关与 extConfig(含首页运营位 items
4 GET /v1/image/img2video/categories 视频首页顶栏服务端分类
5 GET /v1/image/img2video/tasks 某分类下模板列表querycategoryId

所有经 ProxyClient 的业务请求均走 skin_config 中的 proxyPathbody 为加密后的代理载荷;响应经解密与 fieldMapping 还原为逻辑字段后再解析实体。


6. 代码索引(便于跳转)

模块 路径
启动换皮配置 lib/src/bootstrap/client_bootstrap.dart
登录与 common_info 编排 lib/src/services/auth_service.dart
用户接口 lib/src/services/user_api.dart
图/视频分类与任务列表 lib/src/services/image_api.dart
extConfig 运行时 lib/src/config/ext_config_runtime.dart
视频首页 Tab 与缓存 lib/src/config/video_home_runtime.dart
extConfig / items 解析 lib/src/config/ext_config_models.dart
JSON 配置示例 lib/src/config/skin_config.example.json

7. 与《创建新换皮应用》的关系

从零搭建宿主工程、资产路径与 main 初始化顺序,仍以 create_new_skin_app.md 为准;本文仅补充 「视频首页」在框架内的数据流,与 FunyMee 首推路线一致。