# TapTap 云存档接入指南
# 1. 简要说明
TapTap 云存档服务允许 Minigame 和 H5 游戏将玩家进度保存到云端,实现跨设备同步。
# 核心特性
- 无需安装 SDK:
tap是全局对象,直接使用。 - 双层存储:数据需先写入本地文件系统 (
tapfile://),再同步到云端。 - 主要限制:单个存档最大 10MB,每分钟最多上传 1 次。
# 接入流程
# 2. 主要接口说明
详细参数请参考 官方 API 文档
# 核心管理器
- CloudSaveManager:
const cloud = tap.getCloudSaveManager()- 管理云端存档。 - FileSystemManager:
const fs = tap.getFileSystemManager()- 管理本地文件。
# 常用 API
| 方法 | 描述 | 文档链接 |
|---|---|---|
| createArchive | 创建新存档(需先写入本地文件) | API 详情 |
| updateArchive | 更新已有存档(覆盖旧文件) | API 详情 |
| getArchiveList | 获取当前用户的所有存档列表 | API 详情 |
| getArchiveData | 下载云端存档到本地 | API 详情 |
| getArchiveCover | 下载存档封面图片到本地 | API 详情 |
| deleteArchive | 删除云端存档 | API 详情 |
| writeFile | 将数据写入本地文件系统 | API 详情 |
| readFile | 读取本地文件内容 | API 详情 |
# 3. 代码示例
以下是一个封装好的存档管理器类,处理了本地读写、封面处理和云端同步的完整流程。
/**
* 存档槽管理器 - 封装常用的云存档操作
*/
class SaveSlotManager {
constructor() {
this.cloudSaveManager = tap.getCloudSaveManager();
this.fs = tap.getFileSystemManager();
this.basePath = tap.env.USER_DATA_PATH; // 推荐存储路径: tapfile://usr
}
/**
* 保存到指定槽位
* @param {number} slotId - 槽位ID
* @param {Object} gameData - 游戏数据
* @param {string} [coverPath] - 封面图片路径(可选,需先保存到本地)
*/
async save(slotId, gameData, coverPath = null) {
const filePath = `${this.basePath}/slot_${slotId}.json`;
const saveData = { ...gameData, savedAt: Date.now() };
return new Promise((resolve, reject) => {
// 1. 写入本地文件
this.fs.writeFile({
filePath,
data: JSON.stringify(saveData),
encoding: 'utf8',
success: async () => {
try {
// 2. 检查是否存在该槽位
const slots = await this.getSlots();
const existing = slots.find(s => s.name === `slot_${slotId}`);
const options = {
archiveMetaData: {
name: `slot_${slotId}`, // 注意:存档名不能含空格/中文
summary: `Level ${gameData.level || 1} - ${new Date().toLocaleString()}`,
playtime: gameData.playTime || 0
},
archiveFilePath: filePath,
archiveCoverPath: coverPath, // 封面图片路径
success: resolve,
fail: reject
};
// 3. 更新或创建云端存档
if (existing) {
this.cloudSaveManager.updateArchive({ archiveUUID: existing.uuid, ...options });
} else {
this.cloudSaveManager.createArchive(options);
}
} catch (err) {
reject(err);
}
},
fail: reject
});
});
}
/**
* 从指定槽位加载
* @param {number} slotId - 槽位ID
*/
async load(slotId) {
const slots = await this.getSlots();
const slot = slots.find(s => s.name === `slot_${slotId}`);
if (!slot) throw new Error('存档不存在');
return new Promise((resolve, reject) => {
// 1. 下载存档
this.cloudSaveManager.getArchiveData({
archiveUUID: slot.uuid,
archiveFileId: slot.fileId,
targetFilePath: `${this.basePath}/slot_${slotId}_temp.json`,
success: (res) => {
// 2. 读取文件
this.fs.readFile({
filePath: res.filePath,
encoding: 'utf8',
success: (fileRes) => resolve(JSON.parse(fileRes.data)),
fail: reject
});
},
fail: reject
});
});
}
/**
* 下载并获取封面图片路径
* @param {number} slotId - 槽位ID
*/
async loadCover(slotId) {
const slots = await this.getSlots();
const slot = slots.find(s => s.name === `slot_${slotId}`);
if (!slot) return null;
return new Promise((resolve, reject) => {
this.cloudSaveManager.getArchiveCover({
archiveUUID: slot.uuid,
archiveFileId: slot.fileId,
targetFilePath: `${this.basePath}/slot_${slotId}_cover.png`,
success: (res) => resolve(res.filePath),
fail: reject
});
});
}
/**
* 获取所有存档列表
*/
getSlots() {
return new Promise((resolve, reject) => {
this.cloudSaveManager.getArchiveList({
success: (res) => resolve(res.saves),
fail: reject
});
});
}
}
// 使用示例
const saveManager = new SaveSlotManager();
// 保存(带封面)
// 假设已将截图保存到临时目录
const coverPath = `${tap.env.TEMP_DATA_PATH}/screenshot.png`;
saveManager.save(1, { level: 5, gold: 100 }, coverPath)
.then(() => console.log('保存成功'));
// 加载数据
saveManager.load(1).then(data => console.log('加载数据:', data));
// 加载封面
saveManager.loadCover(1).then(path => console.log('封面已下载至:', path));
# 4. QA
Q: 为什么提示 "tap is not defined"? A: 请确保代码在 TapTap 客户端或 Minigame 环境中运行,不要在普通浏览器或 Node.js 中测试。
Q: 存档名有什么限制?
A: 最大 60 字节,不能包含空格或中文字符,推荐使用 slot_1, auto_save 等格式。
Q: 如何处理上传频率限制(400001)? A: 云存档每分钟只能上传 1 次。建议在本地缓存数据,只在关键节点(如通关、手动保存)同步到云端。
Q: 存档文件和封面大小限制? A: 单个存档文件最大 10MB;封面图片最大 512KB,支持 PNG/JPG 格式。
Q: 如何处理多设备冲突?
A: 在加载时对比本地与云端存档的 modifiedTime 或自定义版本号,引导用户选择保留哪一份。
