介绍
鸿蒙(HarmonyOS)的分布式键值型数据库(DistributedKVStore) 是实现 同应用跨设备 轻量数据同步的核心方案,专为 键值(Key-Value) 结构数据设计,具备“自动同步、低延迟、最终一致性”的特性,无需开发者手动处理设备通信,是跨设备数据同步的首选方案。
应用场景
- 应用配置
- 用户偏好
- 收藏列表
- 状态信息
特点
| 特性 | 说明 |
|---|---|
| 自动跨设备同步 | 开启autoSync后,数据写入本地即自动同步到同一账号下的信任设备,无需手动触发 |
| 增量同步 | 仅同步变更的键值对,而非全量数据,降低传输开销 |
| 数据一致性保障 | 内置 CRDT(无冲突复制数据类型),解决多设备并发写入冲突(默认最后写入胜出) |
| 轻量化 | 适配轻量数据(单条≤4MB,总存储≤1GB),API极简,开发成本低 |
| 多设备权限管控 | 基于华为账号+信任设备列表,仅同步到已配对的设备,保障数据安全 |
| 离线同步 | 设备离线时写入的数据,联网后自动补同步到其他设备 |
约束限制
设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB
单版本数据库,针对每条记录,
Key的长度≤1 KB,Value的长度<4 MB。键值型数据库不支持应用程序自定义冲突解决策略。
每个应用程序最多支持同时打开16个键值型分布式数据库。
单个数据库最多支持注册8个订阅数据变化的回调。
开发步骤
此处以单版本键值型数据库跨设备数据同步的开发为例。以下是具体的开发流程和开发步骤。
概念
1. 关键概念
KVManager:键值数据库管理器,用于创建/打开 KV 存储实例,是操作入口;
SingleKVStore:单版本键值存储(推荐跨设备同步场景),支持多设备数据同步;
DeviceID:鸿蒙设备唯一标识,用于指定同步目标设备(可选);
同步策略:系统默认“最后写入胜出(LWW)”,也支持自定义冲突解决。
2. 前置条件
设备:所有设备需升级到鸿蒙 2.0+,登录同一华为账号,开启“超级终端”和“多设备数据同步”开关;
权限:需申请分布式数据同步相关权限(必选);
数据限制:单条 KV 数据
≤4MB,总存储≤1GB,超出需改用分布式文件系统。
配置权限
HarmonyOS NEXT鸿蒙开发:同应用跨设备数据同步-申请权限
代码
步骤1:导入模块
import { distributedKVStore } from '@kit.ArkData';
步骤2:初始化KV管理器与存储实例
建议在 Ability 的 onCreate 生命周期中初始化,保证全局唯一实例:
import distributedKVStore from '@ohos.data.distributedKVStore';
import common from '@ohos.app.ability.common';
// 全局KV存储实例
let kvStore: distributedKVStore.SingleKVStore | null = null;
// 初始化分布式KV存储
async function initDistributedKVStore(context: common.UIAbilityContext) {
try {
// 1. 创建KV管理器配置
const kvManagerConfig = {
context: context, // 应用上下文
bundleName: context.applicationInfo.bundleName // 应用包名(自动获取,避免硬编码)
};
// 2. 创建KV管理器
const kvManager = distributedKVStore.createKVManager(kvManagerConfig);
// 3. 配置KV存储参数(核心:开启自动同步)
const kvStoreOptions = {
createIfMissing: true, // 存储不存在则创建
encrypt: false, // 敏感数据建议开启加密(需配置加密密钥)
backup: true, // 支持云备份(可选)
autoSync: true, // 开启跨设备自动同步(核心)
kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION, // 单版本(同步场景必选)
securityLevel: distributedKVStore.SecurityLevel.S1 // 安全级别(S1为普通级)
};
// 4. 打开KV存储(storeId需唯一,建议按业务划分)
kvStore = await kvManager.getKVStore('app_sync_kv_store', kvStoreOptions);
console.log('分布式KV存储初始化成功');
} catch (err) {
console.error(`KV存储初始化失败:${JSON.stringify(err)}`);
}
}
// 在Ability中调用初始化(以EntryAbility为例)
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
initDistributedKVStore(this.context);
}
}
步骤3:核心操作(写入/读取/同步/监听)
1. 写入数据(自动同步到其他设备)
写入后系统自动触发增量同步,支持 string/number/boolean/Uint8Array 类型值:
/**
* 写入键值数据(自动跨设备同步)
* @param key 键(字符串,建议按业务命名:如"config/theme")
* @param value 值(支持string/number/boolean/Uint8Array)
*/
async function putSyncData(key: string, value: string | number | boolean) {
if (!kvStore) {
console.error('KV存储未初始化');
return;
}
try {
await kvStore.put(key, value);
console.log(`数据写入成功:${key}=${value}`);
} catch (err) {
console.error(`数据写入失败:${JSON.stringify(err)}`);
}
}
// 调用示例:同步应用主题配置
putSyncData('config/app_theme', 'dark');
// 同步用户登录状态
putSyncData('user/login_status', true);
2. 读取同步数据(本地/跨设备同步过来的数据)
支持读取单个键、批量读取、读取所有键值对:
/**
* 读取单个键的同步数据
* @param key 键
* @returns 对应值(无则返回空)
*/
async function getSyncData(key: string): Promise<any> {
if (!kvStore) {
console.error('KV存储未初始化');
return null;
}
try {
const value = await kvStore.get(key);
console.log(`读取数据成功:${key}=${value}`);
return value;
} catch (err) {
console.error(`读取数据失败:${err}`);
return null;
}
}
// 调用示例:获取同步后的主题配置
getSyncData('config/app_theme').then((theme) => {
if (theme) {
// 更新UI主题
console.log('当前同步主题:', theme);
}
});
// 批量读取(按前缀匹配)
async function getSyncDataByPrefix(prefix: string) {
if (!kvStore) return [];
const result = await kvStore.getEntriesByPrefix(prefix);
return result.entries; // 返回[{key: 'xxx', value: 'xxx'}, ...]
}
// 示例:读取所有配置类数据
getSyncDataByPrefix('config/');
3. 监听数据变更(跨设备同步触发)
监听本地/远端设备的数变更,实时更新业务逻辑:
/**
* 监听跨设备数据变更
*/
function listenSyncDataChange() {
if (!kvStore) {
console.error('KV存储未初始化');
return;
}
// 注册数据变更监听
kvStore.on('dataChange', (data: distributedKVStore.DataChangeNotification) => {
console.log('数据变更触发:', JSON.stringify(data));
// data.type:变更类型(PUT/DELETE)
// data.keys:变更的键列表
// data.deviceId:触发变更的设备ID(本地为"",远端为设备唯一标识)
// 远端设备同步数据过来,重新读取并更新UI
if (data.deviceId !== '') {
data.keys.forEach(async (key) => {
const value = await getSyncData(key);
console.log(`远端设备同步数据:${key}=${value}`);
// 业务逻辑:更新页面、刷新状态等
});
}
});
}
// 启动监听(建议在Ability onCreate中调用)
listenSyncDataChange();
4. 手动触发同步(可选,补充自动同步)
若关闭了autoSync,可手动触发指定设备/所有设备同步:
/**
* 手动触发同步(指定设备/所有设备)
* @param deviceIds 设备ID列表(空数组则同步到所有信任设备)
*/
async function syncDataManually(deviceIds: string[] = []) {
if (!kvStore) return;
try {
await kvStore.sync(deviceIds, distributedKVStore.SyncMode.PUSH_PULL);
// SyncMode:PUSH(本地推到远端)、PULL(远端拉到本地)、PUSH_PULL(双向同步)
console.log('手动同步触发成功');
} catch (err) {
console.error(`手动同步失败:${err}`);
}
}
// 示例1:同步到所有信任设备
syncDataManually();
// 示例2:同步到指定设备(需先获取DeviceID)
syncDataManually(['12345678-xxxx-xxxx-xxxx-xxxxxxxxxxxx']);
5. 删除数据(同步删除其他设备数据)
async function deleteSyncData(key: string) {
if (!kvStore) return;
try {
await kvStore.delete(key);
console.log(`数据删除成功:${key}`);
// 删除后,其他设备的该键值也会同步删除
} catch (err) {
console.error(`数据删除失败:${err}`);
}
}
步骤4:获取分布式设备列表(可选)
如需指定同步目标设备,可先获取同一账号下的在线设备:
import distributedDeviceManager from '@ohos.distributedDeviceManager';
/**
* 获取同一账号下的信任设备列表
*/
async function getTrustDeviceList(context: common.UIAbilityContext) {
try {
const dm = distributedDeviceManager.createDistributedDeviceManager(context);
const deviceList = dm.getTrustedDeviceListSync();
// deviceList结构:[{deviceId: 'xxx', deviceName: '手机', deviceType: 'phone'}, ...]
console.log('信任设备列表:', deviceList);
return deviceList;
} catch (err) {
console.error(`获取设备列表失败:${err}`);
return [];
}
}
四、进阶优化:冲突解决与安全
1. 自定义数据冲突解决
系统默认“最后写入胜出(LWW)”,若需更精细的冲突处理(如合并多设备编辑的列表),可通过监听变更事件手动处理:
kvStore.on('dataChange', async (data) => {
// 仅处理远端设备的变更
if (data.deviceId === '') return;
// 示例:合并多设备的收藏列表
if (data.keys.includes('user/collect_list')) {
const localList = await getSyncData('user/collect_list') || [];
const remoteList = await getSyncData('user/collect_list'); // 同步后的远端列表
// 去重合并
const mergedList = [...new Set([...localList, ...remoteList])];
// 重新写入(覆盖冲突)
await putSyncData('user/collect_list', mergedList);
}
});
2. 敏感数据加密
同步密码、token等敏感数据时,开启KV存储加密:
const kvStoreOptions = {
// 其他配置不变
encrypt: true, // 开启加密
cipherKey: 'your_32_byte_key_1234567890123456' // 32字节加密密钥(需自定义)
};
3. 低功耗优化
非实时同步场景(如每日配置同步),可关闭autoSync,改为用户触发/定时同步:
// 初始化时关闭自动同步
const kvStoreOptions = {
autoSync: false,
// 其他配置不变
};
// 定时同步(如每天23点)
import timer from '@ohos.timer';
timer.setTimeout(() => {
syncDataManually();
}, 23 * 60 * 60 * 1000);
五、常见问题与避坑
1. 数据同步失败?
- 检查设备是否登录同一华为账号、开启“多设备数据同步”;
- 检查权限是否申请成功(尤其是
DISTRIBUTED_DATASYNC); - 确认设备已配对(超级终端可发现),且网络正常(Wi-Fi/蓝牙开启);
- 单条数据不超过4MB,超出会同步失败。
2. 多设备并发写入导致数据覆盖?
- 优先依赖系统CRDT一致性策略;
- 对关键数据添加版本号(如
config/theme_v=1),通过版本号判断合并逻辑; - 避免高频次并发写入(如每秒多次写入)。
3. 离线数据无法同步?
- 鸿蒙会缓存离线数据,联网后自动同步,无需手动处理;
- 若需确认同步状态,可监听
syncFinish事件(API 10+支持)。
六、总结
DistributedKVStore 是鸿蒙同应用跨设备轻量数据同步的最优解,核心优势是“系统级自动同步”——开发者无需关注设备通信、组网等底层逻辑,仅需几行API即可实现配置、状态等轻量数据的跨设备同步。
实际开发中,需根据业务场景选择:
- 轻量数据(≤4MB):直接用 DistributedKVStore,开启
autoSync; - 大文件(图片/视频):搭配分布式文件系统(DistributedFileSystem);
- 复杂业务数据:结合手动同步+自定义冲突解决。
核心避坑点:权限配置、设备账号配对、数据大小限制,做好这三点,即可稳定实现跨设备键值数据同步。
