- 添加 PRD、技术规范、交互规范文档 (V0.2) - 创建 Swift Package 和 Xcode 项目 - 实现 LivePhotoCore 基础模块 - 添加 HEIC MakerNote 元数据写入功能 - 创建项目结构文档和任务清单 - 添加 .gitignore 忽略规则
8.3 KiB
8.3 KiB
技术规格书|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。