# FunyMee 应用开发手册(完整版) 本文档是 **FunyMee 客户端** 的主开发手册:页面范围、启动与认证、`skin_config`、**`client_proxy_framework` 已封装 API**、分屏实施要点、合规与发布清单。 实现代理/V2 报文细节、字段别名全表时,需对照 [FunyMeeAI_client_guide.md](./FunyMeeAI_client_guide.md);从零搭工程、Adjust/Facebook 原生步骤可对照 [skin_app_development_guide.md](./skin_app_development_guide.md)。**按本手册顺序施工 + 上述两份文档作规格备查,即可闭环完整 App**(不含后端实现与商店审核商务材料)。 --- ## 目录 1. [资料闭环与本手册怎么用](#1-资料闭环与本手册怎么用) 2. [页面与画板映射](#2-页面与画板映射) 3. [目标工程结构(建议)](#3-目标工程结构建议) 4. [依赖与原生能力](#4-依赖与原生能力) 5. [启动、配置与认证](#5-启动配置与认证) 6. [请求与字段映射(框架行为)](#6-请求与字段映射框架行为) 7. [API 与数据实体总表](#7-api-与数据实体总表) 8. [分屏实施规格](#8-分屏实施规格) 9. [生图状态机与轮询](#9-生图状态机与轮询) 10. [历史 24 小时与倒计时](#10-历史-24-小时与倒计时) 11. [积分流水与支付记录](#11-积分流水与支付记录) 12. [内购(积分购买)](#12-内购积分购买) 13. [举报(反馈)](#13-举报反馈) 14. [注销账号](#14-注销账号) 15. [主题、字体与资源](#15-主题字体与资源) 16. [权限与合规](#16-权限与合规) 17. [调试、环境与联调](#17-调试环境与联调) 18. [测试与上线检查清单](#18-测试与上线检查清单) 19. [导航关系](#19-导航关系) 20. [外部文档索引](#20-外部文档索引) 21. [修订记录](#21-修订记录) --- ## 1. 资料闭环与本手册怎么用 | 层级 | 内容 | 文档/代码 | |------|------|-----------| | **产品/UI** | 视觉与交互 | `desgin/funymee_home.pen`、同目录 PNG 切图 | | **运行时配置** | BaseUrl、AES、代理键、归因、字段映射 | `assets/skin_config.json` | | **框架 API** | 已封装的 REST 调用与实体 | 本地依赖 `../client_proxy_framework`,见下文 API 表 | | **协议深度** | V2 包装、密文键名、错误码 | [FunyMeeAI_client_guide.md](./FunyMeeAI_client_guide.md) | | **工程/Android/iOS/SDK** | 换皮脚手架、清单、Gradle | [skin_app_development_guide.md](./skin_app_development_guide.md)、`client_proxy_framework/docs/sdk_integration_guide.md` | | **配置项语义** | 各 JSON 键说明 | [new_app_config_template.md](./new_app_config_template.md) | **推荐阅读顺序**:本手册 §1–9 → 开始写壳与首页 → 对照 client_guide 联调接口 → skin_guide 处理 SDK/权限遗漏。 --- ## 2. 页面与画板映射 来源:`desgin/funymee_home.pen` 根级 Frame(`children` 顶层)。 | 顺序 | 画板名称 | Pencil 根 id | 说明 | |------|----------|----------------|------| | 1 | FunyMee Home | `bi8Au` | 首页 | | 2 | 通用背景 · 黄→白渐变 | `suXxr` | 可复用渐变,非独立路由 | | 3 | My History 页面 | `WBRp4` | 历史;24h 提示与卡片时间见设计稿 | | 4 | Credit Record 页面 | `QR6Gq` | 积分流水 Tab | | 5 | Purchase Point 页面 | `ETbdo` | 购买积分 | | 6 | 生成图片 页面 | `EYsUi` | 选图/发起任务前 | | 7 | 生成图片 · 生成中 | `YoZaK` | 进行中 | | 8 | 生成图片 · 已完成 | `c7R7z` | 完成态 | | 9 | 生成图片 · 可下载 | `2SyyL` | 可下载 | | 10 | 生成图片 · 单图 | `0iJjl` | 单图结果变体 | | 11 | 个人中心 | `5J8Po` | 设置、积分入口、注销入口等 | | 12 | 注销账户 · 步骤1 | `SYt0O` | | | 13 | 注销账户 · 步骤2 | `yxwpg` | 二次确认 | | 14 | 通用 · 加载中 | `8rpyo` | 全屏 Loading 组件 | | 15 | 举报 | `Y9WlO` | **仅从生图完成后的结果页进入** | 补充切图(如 `desgin/订阅.png`)若单独成页,在本表追加一行并分配路由名。 --- ## 3. 目标工程结构(建议) 在现有 `lib/` 上扩展(与 [skin_app_development_guide.md](./skin_app_development_guide.md) 一致): ``` lib/ ├── main.dart ├── app.dart # MaterialApp + 路由入口 ├── core/ │ ├── auth/auth_service.dart # 已有 │ ├── user/user_state.dart # 已有;可改为 ChangeNotifier │ ├── theme/ # 色板、字体、圆角 │ ├── routing/ # 路由表、RoutePath 常量 │ └── widgets/ # 全屏 Loading、通用渐变背景等 └── features/ ├── home/ ├── generate/ # 选图 → 中 → 完成 → 下载 / 单图 ├── history/ # My History + Credit Record(Tab) ├── purchase/ ├── profile/ # 个人中心 + 注销两步 └── report/ # 举报(从结果页 push) ``` 验收:**每个画板至少对应一个 `Widget` 文件与一个路由路径常量**。 --- ## 4. 依赖与原生能力 当前 `pubspec.yaml` 已含:`client_proxy_framework`、`http`、`encrypt`、`crypto`、`logger`、`shared_preferences`、`android_id`、`device_info_plus`。 **按功能待增(在实现到对应章节时加入)**: | 能力 | 典型 package | 使用场景 | |------|----------------|----------| | 路由 | `go_router`(可选) | 深链、声明式路由 | | 选图/拍照 | `image_picker` | 生成页上传 | | 网络图 | `cached_network_image` | 历史缩略图、结果图 | | 保存相册 | `gal`、`image_gallery_saver` 或 `photo_manager` | 下载落盘 | | 时间/国际化 | `intl` | 创建时间格式化 | | UUID/路径 | `path`、`mime` | 上传文件名 | 框架侧已依赖 `in_app_purchase`(经 `client_proxy_framework` 传递);**确保 Android/iOS 内购能力与商店元数据在商店后台配置完成**。 --- ## 5. 启动、配置与认证 ### 5.1 `main.dart` 顺序(与现码一致) 1. `WidgetsFlutterBinding.ensureInitialized()` 2. `ClientBootstrap.initFromAsset('assets/skin_config.json')` - 内部:`SkinConfig.fromJson` → `ApiClient.init(skin)`,**此后方能发代理请求** 3. `ClientBootstrap.initAnalytics()`(Adjust / Facebook 配置来自 `skin_config.analytics`) 4. `AnalyticsService.initAttribution()`(若需与归因桥接) 5. `runApp(App(...))` 6. `AuthService.init()` → `FrameworkAuthService.init` + `start()`(设备 ID、`fast_login`、`common_info`) ### 5.2 `skin_config.json` 必用字段(顶层) | JSON 路径 | 用途 | |-----------|------| | `app.name` / `app.id` / `app.packageName` | 展示名、业务 appId、包名(请求映射) | | `backend.iosAppType` / `backend.androidAppType` | 接口 query `app`:`HIOS` / `HAndroid` 等 | | `api.preBaseUrl` / `api.prodBaseUrl` / `api.proxyPath` / `api.aesKey` | 环境与加解密 | | `api.alwaysUsePreBaseUrl` / `api.debugBaseUrlOverride` | 开发期切环境 | | `proxyKeys.*` / `v2.*` | 代理外框字段名与 V2 噪声 | | `fieldMapping` | 业务 JSON 键 ↔ V2 伪装键(巨大见文件;**查具体接口时打开 client_guide**) | | `analytics.adjust` / `analytics.facebook` | SDK 初始化 | | `adjustEvents.*` | 埋点 token,与 `AnalyticsService.track*` 对齐 | ### 5.3 业务侧 `app` 参数 凡 `UserApi` / `ImageApi` 等需要 `queryParams['app']` 处: - iOS:`ClientBootstrap.skin.backendAppTypeIOS`(或 `ApiClient.instance.config` 同等字段) - Android:`backendAppTypeAndroid` 与 `defaultTargetPlatform` 对齐,**不要用 appId 字符串顶替**。 ### 5.4 登录与鉴权 - **匿名设备登录**:`UserApi.fastLogin`(框架在 `FrameworkAuthService` 内调用;宿主实现 `AuthServiceCallbacks` 提供 `getDeviceId`、`computeSign`)。 - **Token**:成功后写入 `ApiClient`/代理层;之后 `ProxyClient` 自动带 `pkg` + `User_token`(除 fast_login)。 - **`common_info`**:拉取 `CommonInfoResponse`(积分、用户信息、`extConfig`、`t2IConfig`、`payCenterUrl`、`userToken` 等),在 `AppAuthCallbacks.onCommonInfoLoaded` 同步到 `UserState`。 - **业务请求前**:`await AuthService.loginComplete`(或框架提供的 `FrameworkAuthService.loginComplete`),避免空 token。 ### 5.5 `extConfig`(`skin_config` + common_info,框架内解析) 1. **`skin_config.json` → `extConfig`**(可选):配置 **wire 键名列表**(`keys` / `itemKeys`)及本地 **`defaults`**(与线上下发同键;`common_info` 成功后与服务器 **浅合并**,服务器覆盖同名顶层键)。见 `ExtConfigKeySchema`、`SkinExtConfigSection`,导出见 `package:client_proxy_framework/client_proxy_framework.dart`。 2. **`common_info.extConfig`**:线上 JSON 字符串;若与 `defaults` 合并后仍为空对象,则得到空的 `ExtConfigData`。 `AppConfig` 提供 `extConfigKeySchema`、`extConfigDefaults`;手写 `AppConfig` 时可覆盖;**换皮仅用 JSON 时在 `SkinConfig` 中已注入**。 | 导出 | 用途 | |------|------| | `ExtConfigRuntime.data` | `ValueNotifier`,监听后刷新首页 Tab / Grid | | `ExtConfigRuntime.commonInfoSucceeded` | `true` / `false` / `null`:是否成功拉到 common_info(**建议仅在为 `true` 时展示核心业务 UI**) | | `ExtConfigData` | `showVideoMenu`、`allowScreenshot`、`allowThirdPartyPayment`、`privacyUrl`、`agreementUrl`、`items` | | `ExtConfigItem` | 单项:`image`、`image_fix`、`img_need`、`cost`、`title`、`params` / `detail`;`taskExt` ⇒ `params ?? detail` | | `kExtConfigItemsCategoryId` | 固定 `-1`,作「静态 items Tab」分类 id | | `mergeHomeTabsWithExtConfigItems()` | `showVideoMenu == true` 时在 API Tab 列表 **末尾** 追加静态 Tab | | `ClientBootstrap.skin.extConfigKeySchema` 等 | `SkinConfig` 从 JSON `extConfig.keys` 注入;宿主可只改配置不换代码 | **默认 wire 键(可在 `skin_config.extConfig.keys` 中整体改写):** | 语义 | 默认候选键(首个存在则生效) | |------|------------------------------| | 展示顶部 Video Tab 栏 + items 固定最后一格 | `go_run`、`need_wait` | | 允许截屏 | `screen`;若无则看 `safe_area`(`true` ⇒ 不允许截屏) | | 允许第三方支付 | `san_fang`、`lucky` | | 隐私 / 协议 URL | `privacy`、`agreement` | | items 数组 | `items` | **`itemKeys` 默认(可省略 `imageFix`,仍解析 `image_fix`):** `image`、`image_fix`、`img_need`、`cost`、`title`、`params`、`detail`。 示例(与当前后端约定一致时可原样使用): ```json { "go_run": false, "screen": false, "san_fang": false, "privacy": "https://example.com/privacy", "agreement": "https://example.com/terms", "items": [ { "image": "https://cdn.example.com/a.png", "image_fix": "https://cdn.example.com/a.png", "img_need": 2, "cost": 1, "title": "BananaTask", "params": "animal_expression" } ] } ``` 首页逻辑建议(对齐 `app_client`):`await FrameworkAuthService.loginComplete` 后判断 `ExtConfigRuntime.commonInfoSucceeded.value == true` 再进入主页;`showVideoMenu == true` 时展示顶部 Tab,分类列表用 `mergeHomeTabsWithExtConfigItems` 把静态 Tab 放在最后,**该 Tab 的 Grid 数据源为 `ExtConfigRuntime.data.value?.items`**。第三方支付入口用 `allowThirdPartyPayment`;截屏策略用 `shouldPreventCapture` 或自行根据 `allowScreenshot` 调用宿主侧防护(框架不强制依赖 `screen_secure`)。 --- ## 6. 请求与字段映射(框架行为) - 宿主**只使用** `UserApi`、`ImageApi`、`PaymentApi`、`FeedbackApi` 等,**Body/Query 使用业务原始字段名**(如 `deviceId`、`taskId`)。 - `ProxyClient` 负责:按 `skin_config.fieldMapping` 做键名映射、V2 包装、AES、噪音字段等。 - 查阅某一字段的密文键名:在 [FunyMeeAI_client_guide.md](./FunyMeeAI_client_guide.md) 或 `skin_config.json` 的 `fieldMapping` 中搜索原始键。 --- ## 7. API 与数据实体总表 以下均定义于 `client_proxy_framework/lib/src/services/*.dart`,实体在 `entities/`。 ### 7.1 用户 | 方法 | Path | 说明 | |------|------|------| | `UserApi.fastLogin` | `POST /v1/user/fast_login` | 设备登录 | | `UserApi.referrer` | `POST /v1/user/referrer` | 归因上报 | | `UserApi.getCommonInfo` | `GET /v1/user/common_info` | 通用信息(首页配置、积分、扩展 JSON) | | `UserApi.getAppLanguage` | `GET /v1/config/app-language` | 语言配置 | | `UserApi.getAccount` | `GET /v1/user/account` | 账户信息 | | `UserApi.getCreditsPage` | `GET /v1/user/credits-page` | **积分分页流水**(`page/size/type`) | | `UserApi.getUserPayments` | `GET /v1/user/payments` | **支付/订单记录列表** | | `UserApi.getUnreadMessageCount` | `GET /v1/user/unread-message-count` | 未读消息 | | `UserApi.deleteAccount` | `GET /v1/user/delete` | **注销** | 核心实体:`FastLoginResponse`、`CommonInfoResponse`、`AccountResponse`、`CreditsPageInfoResponse`(含 `CreditRecordItem`)、`UserPaymentsListResponse`。 ### 7.2 图片 / 任务 | 方法 | Path | 说明 | |------|------|------| | `ImageApi.getCategoryList` | `GET /v1/image/img2video/categories` | 分类 | | `ImageApi.getImg2VideoTasks` | `GET /v1/image/img2video/tasks` | 图生视频任务模板列表 | | `ImageApi.getPromptRecommends` | `GET /v1/image/prompt/recomends` | 推荐提示词 | | `ImageApi.createTxt2Img` | `POST /v1/image/txt2img_create` | 文生图 | | `ImageApi.createImg2VideoPose` | `POST /v1/image/img2video_pose_task` | 图生视频姿态任务 | | `ImageApi.getProgress` | `GET /v1/image/progress` | **任务进度** | | `ImageApi.getImg2VideoPoseTemplates` | `GET /v1/image/img2Video_pose_template` | 姿态模板 | | `ImageApi.getUploadPresignedUrl` | `POST /v1/image/upload-presigned-url` | **用户图预签名上传** | | `ImageApi.createTask` | `POST /v1/image/create-task` | **主创建任务**(多参数,与后端协定) | | `ImageApi.getMyTasks` | `GET /v1/image/my-tasks` | **我的任务列表** | 核心实体:`CreateTaskResponse`、`ProgressResponse`(`status`、`progress`、`resultUrl`)、`MyTasksResponse` / `MyTaskItem`(`taskId`、`status`、`createTime`、`resultUrl` 等)、`UploadPresignedUrlResponse`。 **与 app_client 对齐(框架内、无 UI)** - **上传图 ↔ 任务 id 本地缓存**:创建任务成功后调用 `TaskUploadCoverStore.saveAfterCreateTaskResponse(response:, source:)`(或 `saveAfterCreateTaskBody` / `saveForTask`)。文件在应用 support 目录下 `gallery_upload_covers/`,默认 25h 过期清理,文件名与数字 `taskId` 一致(如 `123.jpg`)。 - **我的任务列表**:仍用 `ImageApi.getMyTasks`。`MyTasksResponse` 同时兼容列表键 `tasks` / `intensify`、`hasNext` / `manifest`;`MyTaskItem` / `CreateTaskResponse` 中任务 id 兼容 `taskId` / `tree` / `id`(解密后的 business 字段)。 - **与 app_client Gallery 相同的行模型**:`GalleryTaskItem` / `GalleryMediaItem` 及 `listingDisplayFromApi` 等见 `gallery_task_models.dart`;原始列表 Map 可用 `ImageTaskHistory.parseGalleryTasksFromData` 解析,本机封面路径用 `ImageTaskHistory.localCoverPathsForGalleryTasks`(或与 `MyTaskItem` 对应的 `localCoverPathsForMyTaskItems`)在刷新列表后合并。 **FunyMee 推荐直接调用的封装(框架已导出)** - **`compressImageForUpload` / `CompressImageForUploadOptions`**:上传前压图。 - **`ImagePresignedUploadCreateTaskFlow.run`**:压图(可关)→ `getUploadPresignedUrl` → HTTP PUT → `createTask` → 可选 `TaskUploadCoverStore`;`UploadPresignedUrlResponse` 支持 `putHeaders` 等与 PUT 合并;若后端只要 `imgUrl` 可设 `createTaskUseImgUrlOnly: true`。 - **`UserAccountRefresh.fetchAndNotify`**:`getAccount` + 回调,无 UI 状态。 - **`AdjustService.obtainReferrerForUpload`**:返回 `ReferrerForUpload`(`digest` + `source`),供 `UserApi.referrer` 等与参考产品一致。 - **`ensureDeviceMemoryProfileInitialized`**(默认通道 `client_proxy_framework/device_memory`,插件已接 Android `ActivityManager.totalMem`)、`deviceGridMaxConcurrentVideos` 等。 - **`VideoThumbnailCache.instance`**:远程视频缩略图 / 海报帧缓存。 ### 7.3 支付 | 方法 | Path | 说明 | |------|------|------| | `PaymentApi.getGooglePayActivities` | `GET /v1/payment/getGooglePayActivities` | Android 商品活动 | | `PaymentApi.getApplePayActivities` | `GET /v1/payment/getApplePayActivities` | iOS 商品活动 | | `PaymentApi.getPaymentMethods` | `POST /v1/payment/get-payment-methods` | 某活动支付方式 | | `PaymentApi.createPayment` | `POST /v1/payment/createPayment` | 创建订单 | | `PaymentApi.getPaymentDetailList` / `getOrderDetail` 等 | 见 `payment_api.dart` | 订单详情、列表 | 内购验证与 `PurchaseDetails` 流封装见 `PaymentService`(`client_proxy_framework`)。 ### 7.4 反馈(举报) | 方法 | Path | 说明 | |------|------|------| | `FeedbackApi.getUploadPresignedUrl` | `POST /v1/feedback/upload-presigned-url` | 截图/凭证上传 | | `FeedbackApi.submit` | `POST /v1/feedback/submit` | 提交(`fileUrls`、`contentType`、`content`) | 实体:`SubmitFeedbackResponse`、`FeedbackUploadPresignedUrlResponse`。 --- ## 8. 分屏实施规格 | 页面 | 主要 API / 数据源 | 关键实体与注意事项 | |------|-------------------|-------------------| | **FunyMee Home** | `getCommonInfo`(框架内已拉);Tab/静态列表用 **`ExtConfigRuntime` / `ExtConfigData`**;其它首页结构可解析 `t2IConfig` | 见 **§5.5**;静态 Tab id 使用 `kExtConfigItemsCategoryId` | | **生成图片** | `getUploadPresignedUrl` + HTTP PUT 到 `uploadUrl`;`createTask` 或 `createTxt2Img` / 业务指定路径 | 传 `userId`、`app`;参数以后台为准 | | **生成中** | `getProgress` 轮询 | `taskId` 来自创建响应;`status` / `progress` 与 client_guide 状态枚举对齐 | | **已完成 / 可下载 / 单图** | 同一任务不同 UI 态;数据来自 `ProgressResponse` 或 `MyTaskItem` | 下载前校验 `resultUrl`;**举报入口放此组页面** | | **My History** | `getMyTasks`(分页 `page` / `pageSize` / `cursor` 按后端) | 展示 `createTime`、`resultUrl`、状态;无远程封面时可合并 `TaskUploadCoverStore`;过期逻辑见 §10 | | **Credit Record** | `getCreditsPage` | `CreditRecordItem.createTime` 为整型时间戳(秒或毫秒需与后端确认) | | **Purchase Point** | `getGooglePayActivities` / `getApplePayActivities` → `getPaymentMethods` → `createPayment` + 平台 IAB | 对齐 `PaymentService` 与订单恢复 | | **个人中心** | `getAccount`;展示 `common_info` 冗余字段 | 跳转购买、注销;**无举报** | | **注销** | 两步 UI + `deleteAccount` | 成功后清除本地 token、回首页或登录流 | | **举报** | `FeedbackApi` 预签名上传 + `submit` | `contentType` 与后台枚举一致(见 client_guide) | | **全屏 Loading** | 无 API | 覆盖路由栈或全局 `Overlay` | --- ## 9. 生图状态机与轮询 推荐流程: 1. **创建**:`createTask`(或文生图等)→ 取 `taskId`;若有用户上传的本地待传文件,成功后调用 `TaskUploadCoverStore.saveAfterCreateTaskResponse` 与任务 id 关联(见 §7.2)。 2. **轮询**:循环 `ImageApi.getProgress(app:, taskId:, userId:)`,间隔 1–3s,带** backoff** 与**页面 dispose 取消**。 3. **状态映射**(字符串以**后端文档为准**,此处为占位): - `pending` / `processing` → 生成中页 - `success` / `completed` 且 `resultUrl` 有效 → 可下载 / 单图 - `failed` → 错误态 UI + 重试/客服 4. **离开 App 再进入**:用 `getMyTasks` 或持久化 `taskId` 恢复轮询。 详细状态码表:在 **client_guide** 搜索 `progress` / `task` / `status`。 --- ## 10. 历史 24 小时与倒计时 - 列表项展示 **创建时间**:优先 `MyTaskItem.createTime`(格式由后端决定,ISO8601 或时间戳用 `intl`/自建解析)。 - **「剩余可下载时间」**:若接口**未**直接返回过期时间戳,则采用产品规则: `deadline = createdAt + 24h`,剩余 = `deadline - DateTime.now()`;展示与 **My History** 画板一致(天/时/分)。 - 过期后:隐藏或置灰 Download,可选调用后台是否仍返回 `resultUrl` 以决定客户端行为。 --- ## 11. 积分流水与支付记录 - **积分流水(Credit Record 页)**:`UserApi.getCreditsPage(page:, size:, type:)`。 **`type` 含义必须与后台确认**(过滤消费/充值等);分页用 `total/current/pages`。 - **支付记录(若单独 Tab)**:`UserApi.getUserPayments(app:, userId:)`,实体 `UserPaymentsListResponse`。 --- ## 12. 内购(积分购买) ### 12.1 编排层(推荐,`package:client_proxy_framework/...` 已导出 `payment_flow.dart`) | 类型 | 作用 | |------|------| | `PaymentSettlementSink` | 宿主实现 `onPaymentSettled`:**仅此一处**拉 `common_info` / 更新 `UserState` / 埋点 | | `PaymentSettlement` / `PaymentFlowOutcomeType` | 成功 / 失败 / 取消 / 超时 等统一结果 | | `PaymentFlowCatalog.loadStoreActivities` | 按平台调 `getGooglePayActivities` / `getApplePayActivities` | | `PaymentApi.getPaymentMethods` | 仍直接调用;选完后走三方或内购 | | `ThirdPartyCheckoutCoordinator.createOrder` | 封装 `createPayment`,得到 `orderId` + `payUrl` | | `ThirdPartyCheckoutCoordinator.openPayUrlIfPresent` | 需传入宿主 `PaymentCheckoutUrlLauncher`(WebView / `launchUrl`) | | `ThirdPartyPaymentWatch` | 宿主在打开收银台后调用 `start(orderId:)`,`stop()` 停止;终态只触发一次 `sink` | | `NativeIapCoordinator.purchaseGooglePlay` | **仅 Android**:`createPayment` → 拉起购买 → `googlepay` → consume(含 `federation` 映射) | **宿主策略**:根据 `ExtConfigRuntime.data` 的 `allowThirdPartyPayment`(或自研规则)选择调用 `ThirdPartyCheckoutCoordinator` + `ThirdPartyPaymentWatch`,或 `NativeIapCoordinator.purchaseGooglePlay`;**不要在框架里写死分支**。 ### 12.2 底层 API(仍可直接用) 1. 拉商品活动:`PaymentApi.getGooglePayActivities` / `getApplePayActivities`。 2. 用户选档位 → `PaymentApi.getPaymentMethods(activityId: int)`。 3. `PaymentApi.createPayment`、`PaymentApi.googlepay`、`PaymentService` 补单等:**编排类内部已组合**,单独对接时仍以 client_guide 为准。 --- ## 13. 举报(反馈) 1. **入口**:仅从 **生图完成后的结果页**(已完成 / 可下载 / 单图)进入 `Y9WlO` 对应界面。 2. 可选图片:`FeedbackApi.getUploadPresignedUrl` → PUT 文件 → 得到 `fileUrl` 列表。 3. `FeedbackApi.submit(fileUrls:, content:, contentType:)`;`content` 可含任务 id、原因枚举等约定字段。 --- ## 14. 注销账号 1. UI:`SYt0O` → `yxwpg`。 2. 调用 `UserApi.deleteAccount(app:, userId:)`(GET);**确认是否需额外 body/query**。 3. 清理:`ApiClient` 侧 token、本地 `SharedPreferences`、再 `runApp` 或导航到首页。 --- ## 15. 主题、字体与资源 - 颜色/圆角:对齐 Pencil;主强调色与 Tab 下划线可参考 `#c99304`。 - 字体:`Inter` + `Bonheur Royale`(见历史卡片 Download 标签);在 `pubspec.yaml` 注册 `fonts:` 并放入 `assets/fonts/`。 - 首页背景:Pencil `bi8Au` 使用 `./首页.png`。请将设计导出为 **`assets/images/home_background.png`**(与代码中 `Image.asset` 一致);缺失时客户端使用深色渐变占位,非最终 1:1 效果。子页通用渐变见 `PencilTheme.yellowWhitePageGradient`(对齐 `suXxr` / `WBRp4`)。 --- ## 16. 权限与合规 - **相册/存储**:保存生成图、选图上传前申请权限(iOS `NSPhotoLibraryUsageDescription` 等)。 - **网络**:ATS / 明文规则按环境配置。 - **Adjust / Facebook**:按 skin_guide 填 `AndroidManifest.xml`、`Info.plist`。 - **隐私政策 URL**:若 `common_info` / `h5UrlConfig` 下发,在个人中心打开。 --- ## 17. 调试、环境与联调 - 切换预发布:`skin_config.api.alwaysUsePreBaseUrl: true` 或 `debugBaseUrlOverride`。 - 抓包:注意请求体为代理包装后的 JSON;**解密验证用 client_guide + 后端工具**。 - `Logger` / `AnalyticsService` 调试开关见 `skin_config.analytics.debugLogs`。 --- ## 18. 测试与上线检查清单 - [ ] 冷启动:无崩溃,`loginComplete` 后首屏可请求接口 - [ ] 生图全链路:创建 → 进度 → 结果 → 下载(或保存相册) - [ ] 历史分页与 24h 展示正确 - [ ] 积分流水 `type`、分页正确 - [ ] 内购:沙盒成功、积分刷新、Adjust 事件(若配置) - [ ] 举报:仅结果页可见、提交成功 - [ ] 注销:账号不可用、本地状态清空 - [ ] 弱网 / 后台恢复 / 任务恢复 --- ## 19. 导航关系 ```mermaid flowchart TB Home[FunyMee Home] GenFlow[生成图片→生成中] GenResult[生图完成: 已完成/可下载/单图] Hist[My History] Credit[Credit Record] Buy[Purchase Point] Profile[个人中心] Report[举报] Del1[注销 步骤1] Del2[注销 步骤2] Home --> GenFlow GenFlow --> GenResult GenResult --> Report Home --> Hist Home --> Profile Hist --- Credit Profile --> Buy Profile --> Del1 --> Del2 ``` --- ## 20. 外部文档索引 | 文档 | 用途 | |------|------| | [skin_app_development_guide.md](./skin_app_development_guide.md) | 换皮、Android/iOS、SDK、`AppAuthCallbacks` 模板 | | [FunyMeeAI_client_guide.md](./FunyMeeAI_client_guide.md) | 代理/V2/接口细节、错误码 | | [new_app_config_template.md](./new_app_config_template.md) | 配置模板说明 | | `assets/skin_config.json` | 本应用实际配置 | | `../client_proxy_framework/lib/src/services/*.dart` | API 源码与注释 | --- ## 21. 修订记录 | 日期 | 说明 | |------|------| | 2026-04-07 | 初版:页面清单与启动流程 | | 2026-04-07 | 举报入口:生图完成页 | | 2026-04-07 | **完整版**:API 总表、分屏规格、状态机、支付/举报/注销、`skin_config`、工程结构、测试清单;明确与 client_guide / skin_guide 的闭环关系 | | 2026-04-07 | 框架增加 `ExtConfigData` / `ExtConfigRuntime`:解析 `go_run`/`screen`/`san_fang` 与旧键名,common_info 成功后更新;手册 §5.5 | | 2026-04-07 | `skin_config.extConfig`:`keys`/`itemKeys`/`defaults`;`ExtConfigKeySchema`;与 common_info 浅合并 | | 2026-04-07 | 支付编排:`PaymentSettlementSink`、`ThirdPartyCheckoutCoordinator`、`ThirdPartyPaymentWatch`、`NativeIapCoordinator`;`CreatePaymentResponse.federation` |