第103篇 | HarmonyOS 结营复盘:从相机 Demo 到多端智能记忆应用
第103篇 | HarmonyOS 结营复盘:从相机 Demo 到多端智能记忆应用
第 103 篇是这个阶段的收束。项目从一个相机 Demo 出发,逐步接入地图、相册、保险箱、AI、视频、系统分享、近场分享、华为账号和端云同步。真正值得保留的不是功能数量,而是每一步都能回到用户路径和工程边界。
结营复盘要回答三个问题:这个项目解决了什么用户问题,哪些能力已经形成闭环,哪些能力仍需要真机和线上环境继续验证。
版本与环境
本文复测口径为 DevEco Studio 6.1 Release、HarmonyOS SDK 6.1.0(23)、Stage 模型 ArkTS 页面。涉及相机、地图、AI 在线能力、华为账号、系统分享或多端同步时,以真机结果为准;预览器只能用来检查页面结构和文案层级,不能替代权限、设备能力和系统弹窗验证。
对应源码位置
entry/src/main/module.json5entry/src/main/ets/pages/Index.etsentry/src/main/ets/services/GallerySyncService.etsentry/src/main/ets/services/VolcengineArkService.ets
本篇目标
- 从产品路线而不是 API 清单复盘项目。
- 确认多设备、隐私、AI、端云同步四条主线各自的边界。
- 把还需要真机复验的点列清楚。
- 为后续发布、开源和社区答疑留下路线图。
先确认项目不是手机单形态 Demo
module.json5 里声明了 phone、tablet、2in1,说明项目从配置层就考虑了多设备入口。结营复盘时要把这个前提讲清楚:多端不是最后加一张平板截图,而是从窗口模式、导航宽度、内容约束开始设计。
如果后续要继续扩展 PC 或折叠屏,第一件事仍然是检查配置、窗口指标和页面布局是否一起更新。

项目从配置层声明 phone、tablet、2in1 和窗口模式
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"metadata": [
{
"name": "client_id",
"value": "6917602606633938955"
}
],
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:foreground",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"supportWindowMode": [
"fullscreen",
"split",
"floating"
],
端云同步把单机记忆变成可恢复资产
GallerySyncService 把身份、快照、记录和视频放进同一套同步模型里。它不是简单上传数组,而是要处理 ownerKey、schemaVersion、cloudReady、localMirror 和 cloudFoundation。
这条主线说明项目已经从本地相机走向可恢复资产,但也意味着账号切换、冲突合并和云端失败都必须被认真验收。

端云同步让相册记录和视频记录从单机状态变成可恢复资产
export type GallerySyncMode = 'localMirror' | 'cloudFoundation';
export interface HuaweiCredentialSeed {
unionID?: string;
openID?: string;
idToken?: string;
authorizationCode?: string;
displayName?: string;
nickName?: string;
email?: string;
}
export interface GalleryAccountIdentity {
userKey: string;
displayName: string;
source: 'huawei';
loginAt: number;
tokenHint: string;
}
export interface GallerySyncSnapshot {
schemaVersion: number;
ownerKey: string;
mode: GallerySyncMode;
updatedAt: number;
records: Array<GalleryMoment>;
videos: Array<GalleryVideoRecord>;
}
export interface GallerySyncRuntimeState {
mode: GallerySyncMode;
statusText: string;
syncedAt: number;
photoCount: number;
videoCount: number;
cloudReady: boolean;
}
export interface GallerySyncResult {
records: Array<GalleryMoment>;
videos: Array<GalleryVideoRecord>;
state: GallerySyncRuntimeState;
}
interface GalleryCloudSnapshot {
records: Array<GalleryMoment>;
videos: Array<GalleryVideoRecord>;
}
interface GalleryAssetSize {
width: number;
height: number;
}
export class GallerySyncService {
private static readonly STORE_NAME: string = 'super_image_gallery_sync';
private static readonly IDENTITY_KEY: string = 'gallery_sync_identity';
private static readonly STATE_KEY: string = 'gallery_sync_state';
AI 能力必须保留离线兜底
VolcengineArkService 接入图像理解、文案生成、视频生成和图片生成,但这些能力都依赖网络、Key 和服务端模型。结营复盘里不能只写“已接入 AI”,还要写清离线图解、本地提示词和失败恢复。
AI 是增强能力,不应该成为相册、地图和保险箱主链路的单点故障。

AI 输出需要解析、校验和本地兜底,不能破坏原始记录
private static parseInsight(rawText: string, record: GalleryMoment): VolcengineImageInsight {
const jsonBlock = VolcengineArkService.extractJsonBlock(rawText);
if (jsonBlock.length > 0) {
try {
const parsed = JSON.parse(jsonBlock) as ArkInsightPayload;
if (parsed.aiCaption && parsed.videoPrompt) {
return {
aiCaption: parsed.aiCaption.trim(),
videoPrompt: parsed.videoPrompt.trim(),
rawText: rawText
};
}
} catch (error) {
console.error(`Failed to parse Ark insight JSON: ${JSON.stringify(error)}`);
}
}
const fallbackText = VolcengineArkService.sanitizeProductText(rawText);
return {
aiCaption: fallbackText.length > 0
? fallbackText.slice(0, 80)
: VolcengineArkService.buildFallbackCaption(record),
videoPrompt: `以 ${record.place} 的照片为主场景,沿用原图人物、物体、光影和空间结构做 6 秒回忆短片,轻微运镜,不新增无关物体。`,
rawText: rawText
};
}
private static extractJsonBlock(rawText: string): string {
const firstBrace = rawText.indexOf('{');
const lastBrace = rawText.lastIndexOf('}');
最终路线图要能被真机复验
结营复盘最后要落到一张验收路线图:拍照、相册、地图、AI、视频、保险箱、分享、端云同步。每个节点都要有成功态、失败态和下一步动作。
这张路线图也是 6.14 文章发布后的社区答疑依据。有人问“支持什么设备”“失败怎么办”“隐私怎么处理”,都能回到这张表和对应源码入口。

结营复盘把项目从相机 Demo 收束为可复验的智能记忆应用
if (this.cloudSyncBusy) {
return;
}
this.cloudSyncBusy = true;
this.cloudSyncStatusText = this.cloudSyncIdentity ? '正在同步照片...' : '请先使用华为账号一键登录';
try {
const ready = await this.ensureHuaweiIdentityForCloudSync();
if (!ready || !this.cloudSyncIdentity) {
if (this.cloudSyncStatusText.indexOf('华为账号') < 0) {
this.cloudSyncStatusText = '请先使用华为账号一键登录';
}
return;
}
this.cloudSyncStatusText = reason === 'login' ? '正在恢复照片...' : '正在同步照片...';
const result = await GallerySyncService.mergeSnapshot(
this.getAbilityContext(),
this.cloudSyncIdentity,
this.galleryRecords,
this.videoManagerRecords
);
await GalleryRecordService.saveRecords(this.getAbilityContext(), result.records);
await GalleryVideoService.saveRecords(this.getAbilityContext(), result.videos);
const savedRecords = await GalleryRecordService.loadRecords(this.getAbilityContext());
const savedVideos = await GalleryVideoService.loadRecords(this.getAbilityContext());
await this.applyGalleryRecords(savedRecords);
this.videoManagerRecords = savedVideos;
this.updateCloudSyncState(result.state);
} catch (error) {
const err = error as BusinessError;
this.cloudSyncStatusText = this.buildCloudSyncFriendlyMessage(err);
console.error(`Failed to sync gallery cloud data: ${JSON.stringify(error)}`);
} finally {
this.cloudSyncBusy = false;
}
}
真机验收步骤
| 验收点 | 操作 | 预期结果 |
|---|---|---|
| 多端入口 | 检查 module.json5 和窗口模式 | phone、tablet、2in1 入口清楚 |
| 隐私边界 | 未解锁保险箱时点击私密详情 | 不渲染私密图片和导出按钮 |
| AI 兜底 | 清空 Key 或断网后使用图解功能 | 保留本地文案,不破坏原始记录 |
| 端云同步 | 登录华为账号后同步,再切换账号 | 状态文案清楚,冲突可恢复 |
复现边界
端云同步、华为账号、近场分享、DLP 防窥、在线 AI 都需要真机、账号或网络环境配合。结营复盘只说明工程链路和验收方法,不把外部服务可用性写成绝对承诺。
后续继续发布时,仍要以 CSDN 后台数据质量分和社区同步状态为最终验收,不以本地文章估算作为结果。
社区同步摘要
社区同步摘要可以写:本文复盘双镜记忆相机如何从相机 Demo 延展到多设备、隐私保护、AI 增强和端云同步,并给出每条能力的真机验收边界。
今日练习
- 把项目路线图压缩成一张“成功态/失败态/源码入口”表。
- 找出仍依赖真机或在线环境的能力,分别写出降级文案。
- 准备一段 120 秒结营讲解稿,按用户路径而不是 API 顺序介绍。
更多推荐


所有评论(0)