# 技术规格书|Live Photo 制作与动态壁纸引导 App(V0.2-Tech) - 适用平台:iPhone / iPad(iOS / iPadOS) - 日期:2025-12-13(Asia/Manila) - 用途:用于 AI 编码 / 架构落地 / 研发验收 ## 1. 范围与目标 本技术规格书覆盖:媒体导入、编辑、Live Photo 合成与写入、校验、壁纸引导、缓存与日志、埋点。 - **目标**:在不使用私有 API 的前提下,生成系统相册可识别的 Live Photo 资产,并通过引导帮助用户设置锁屏动态壁纸。 - **非目标**:不直接替用户设置系统壁纸;不做云端上传/存储(默认本地)。 ## 2. 总体架构 ### 2.1 模块分层 | 层级 | 模块 | 职责 | 关键技术 | |---|---|---|---| | UI | Home/Editor/Processing/Result/Guide | 页面展示、交互、状态驱动 | SwiftUI(推荐)/UIKit | | Domain | Workflows | 导入-编辑-生成-保存-引导的业务编排 | async/await, Combine(可选) | | Service | MediaImport / Builder / AlbumWriter / Validation | 导入、合成、写相册、校验 | PhotosUI, AVFoundation, Photos, ImageIO | | Infra | CacheManager / Logger / Analytics | 缓存、日志、埋点、错误封装 | FileManager, OSLog, 自研/第三方 | ### 2.2 目录结构建议(Xcode) - App/(入口、DI、AppState) - Features/Home, Features/Editor, Features/Processing, Features/Result, Features/Guide - Domain/Models(WorkItem、ExportParams、Capability) - Domain/UseCases(ImportVideo、BuildLivePhoto、SaveToAlbum、Validate、GenerateGuideSteps) - Services/MediaImport, Services/LivePhotoBuilder, Services/AlbumWriter, Services/Validation - Infra/Cache, Infra/Logging, Infra/Analytics, Infra/Errors - Resources/(引导图、FAQ 文案、模板配置 JSON) ## 3. 核心数据模型 ### 3.1 WorkItem(作品) | 字段 | 类型 | 说明 | |---|---|---| | id | UUID | 作品唯一标识 | | createdAt | Date | 创建时间 | | sourceVideo | SourceRef | 来源引用:PHAsset localIdentifier 或 fileURL | | coverImage | SourceRef? | 可选封面图引用 | | exportParams | ExportParams | 比例/裁剪/关键帧等参数 | | status | enum | idle/editing/processing/success/failed | | resultAssetId | String? | 写入相册后的 asset.localIdentifier | | cacheDir | URL | 中间文件目录 | | error | AppError? | 失败信息(含可行动建议) | ### 3.2 ExportParams(导出参数) | 字段 | 类型 | 说明/规则 | |---|---|---| | aspectRatio | Preset/CGFloat | 模板:iPhoneLock、Full、4:3… | | cropTransform | scale + offset | 编辑页输出的裁剪参数 | | trimStart | Double | 秒;默认0 | | trimEnd | Double | 秒;默认3;限制1.5~5 | | keyFrameTime | Double | 秒;在trim区间内 | | audioPolicy | enum | keep/remove;默认keep | | codecPolicy | enum | passthrough / fallbackH264 | | hdrPolicy | enum | keep / toneMapToSDR(建议) | | maxDimension | Int | 上限,例如 1920 或自适应 | ## 4. 状态机与工作流 ### 4.1 作品状态机(建议) - Idle(未开始) - → Importing(导入中)→ Editing(编辑中) - → Processing(生成中:Normalize → BuildPhoto → BuildVideo → Pairing → Validate) - → Success(成功:可保存/已保存) - → Failed(失败:含可重试点与建议) 处理阶段建议暴露为枚举(用于进度与日志): - normalize(归一化:裁剪/转码策略确定) - extractKeyFrame(取关键帧/封面图) - writePhotoMetadata(写图片侧元数据) - writeVideoMetadata(重封装并写视频侧元数据) - saveToAlbum(写入相册) - validate(校验 Live Photo 是否可识别) ### 4.2 并发与取消 - 生成任务使用 Task(Swift Concurrency)实现,可被用户取消;取消时清理未写入相册的中间文件。 - 对 AVAssetReader/Writer 的写入任务采用串行队列/actor 封装,避免资源竞争。 - 避免主线程阻塞:任何转码/重封装/写文件都在后台队列或 Task 中执行。 ## 5. Live Photo 合成实现规范 ### 5.1 输入约束与预处理(Normalize) - 时长:将 trim 区间限制在 1.5~5s(默认 3s)。 - 分辨率:按 maxDimension 缩放;优先保证主体清晰而不是极限画质。 - 帧率:高帧率(>30fps)可降至 30fps,以提升兼容性与体积。 - HDR:若检测到 HDR/Dolby Vision,优先提示并建议转 SDR(tone mapping),避免部分系统/场景识别异常。 ### 5.2 绑定标识(Identifier) - 每次生成一个 assetIdentifier(UUID string)。 - 图片与视频必须共享同一 identifier;否则系统不会将其识别为 Live Photo 对。 ### 5.3 图片侧(Photo)输出规范 - 优先输出 HEIC(更现代且在较新系统上更稳定);必要时支持 JPEG 作为降级。 - 写入 Apple MakerNote/相关字段以携带 identifier(实现时以可验证的字段集合为准)。 - 封面图来源优先级:用户选封面照片 > 从视频 keyFrameTime 抽帧。 ### 5.4 视频侧(Paired Video)输出规范 - 容器:MOV。 - 写入 QuickTime metadata:content identifier(与照片一致)。 - 写入 timed metadata track:still-image-time(标记关键照片时刻)。 - 尽量 re-mux(不重编码)提升速度;若写入失败或素材不兼容,再降级到转码流程。 ### 5.5 写入相册规范 - 使用 PHAssetCreationRequest 同时 addResource:.photo 与 .pairedVideo。 - 在 performChanges 回调中记录成功/失败;成功后写入 resultAssetId;失败需返回可行动错误。 ### 5.6 校验(Validation) - 策略 A:保存后用 resultAssetId 取回 PHAsset,尝试请求 Live Photo(或检查其资源类型/子资源)。 - 策略 B:若无法直接取 Live Photo 对象,则至少验证:相册中显示 Live 标识(人工/自动化截图对比可作为 QA 手段)。 - 校验失败要区分:合成失败 vs 写相册失败 vs 系统未识别。 ## 6. 错误码与可行动建议(Error Taxonomy) | 错误码 | 阶段 | 用户可见文案(标题) | 常见原因 | 建议动作(App 提示) | |---|---|---|---|---| | LPB-001 | Import | 无法读取视频 | 权限不足/资源损坏 | 检查相册权限;换一个视频 | | LPB-101 | Normalize | 素材参数不兼容 | HDR/超高分辨率/奇怪编码 | 开启“兼容模式”;降低分辨率/转 SDR | | LPB-201 | Photo | 封面生成失败 | 抽帧失败/内存不足 | 缩短时长;降低分辨率;重试 | | LPB-301 | Video | 视频处理失败 | 重封装/转码失败 | 切换到 H.264 兼容导出;关闭音频 | | LPB-401 | Album | 保存到相册失败 | 无写入权限/相册忙 | 允许“添加到相册”;稍后重试 | | LPB-501 | Validate | 系统未识别为实况 | 元数据不完整/系统限制 | 重新生成;尝试更短视频;升级系统(如需壁纸动效) | | LPB-901 | Unknown | 发生未知错误 | 不可预期异常 | 反馈日志;重启 App;重试 | ## 7. 缓存、日志与诊断 ### 7.1 缓存目录结构 - `Caches/LivePhotoBuilder/{workId}/source.mov`(可选) - `Caches/LivePhotoBuilder/{workId}/normalized.mov`(归一化输出) - `Caches/LivePhotoBuilder/{workId}/photo.heic`(封面图) - `Caches/LivePhotoBuilder/{workId}/paired.mov`(写入元数据后的成品视频) - `Caches/LivePhotoBuilder/{workId}/builder.log`(阶段日志,供反馈) ### 7.2 清理策略 - 成功:保留 photo/paired 的短期缓存(例如 24h)以支持“再次保存/分享”;随后自动清理。 - 失败:保留日志与关键中间文件(例如 24h),方便用户一键反馈;随后清理。 - 用户手动“清理缓存”:立即删除所有 workId 目录,但不影响系统相册成品。 ## 8. 安全与隐私 - 默认全程本地处理,不上传用户素材。 - 日志默认不包含媒体内容本身;仅记录参数与错误码;用户反馈前需二次确认。 - 权限请求延迟到使用时,并提供用途说明与拒绝后的替代路径。 ## 9. AI 编码提示(可直接复制给 AI) - 按模块创建 Swift Package 或 App 内分组;对 LivePhotoBuilder 使用 `actor` 管理状态与文件路径。 - UseCase 层提供 async 函数:`importVideo()`, `buildLivePhoto()`, `saveToAlbum()`, `validate()`. - UI 层采用单一 source of truth:`WorkItemViewState`;所有副作用通过 UseCase 注入。 - 为每个阶段输出结构化日志与 `progress (0~1)` + `stage enum`。