一文走进HarmonyOS开发中的分布式首选项
【摘要】 首选项(Preferences)是应用配置的"小金库":主题设置、字体大小、通知开关…这些个性化配置如何在多设备间同步?让用户在手机上设置深色模式,平板自动切换,这才是真正的"无缝体验"。 一、背景与动机:为什么需要分布式首选项? 1.1 传统首选项的局限传统首选项(SharedPreferences、UserDefaults等)只存储在本地设备:场景1:主题设置用户在手机上设置了深色主题打...
首选项(Preferences)是应用配置的"小金库":主题设置、字体大小、通知开关…这些个性化配置如何在多设备间同步?让用户在手机上设置深色模式,平板自动切换,这才是真正的"无缝体验"。
一、背景与动机:为什么需要分布式首选项?
1.1 传统首选项的局限
传统首选项(SharedPreferences、UserDefaults等)只存储在本地设备:
场景1:主题设置
- 用户在手机上设置了深色主题
- 打开平板应用,还是浅色主题
- 需要重新设置,体验割裂
场景2:字体大小
- 老年用户在手机上调大了字体
- 在智慧屏上看视频,字幕字体还是默认大小
- 每个设备都要设置一遍
场景3:通知偏好
- 用户在手机上关闭了某类通知
- 平板上还在推送同类通知
- 设置不同步,造成困扰
1.2 分布式首选项的价值
分布式首选项让配置"一次设置,处处生效":

二、核心原理:分布式首选项架构
2.1 数据结构
分布式首选项本质是一个支持跨设备同步的键值对存储:
interface DistributedPreferences {
// 基础操作
get(key: string, defaultValue?: any): any;
put(key: string, value: any): Promise<void>;
delete(key: string): Promise<void>;
clear(): Promise<void>;
// 同步操作
sync(): Promise<void>;
setSyncEnabled(key: string, enabled: boolean): void;
// 监听操作
on(key: string, callback: (value: any) => void): void;
off(key: string, callback?: (value: any) => void): void;
}
2.2 同步策略
不同类型的配置采用不同的同步策略:
| 配置类型 | 同步策略 | 原因 |
|---|---|---|
| 主题设置 | 实时同步 | 视觉一致性要求高 |
| 字体大小 | 实时同步 | 可访问性设置重要 |
| 通知偏好 | 延迟同步 | 非实时需求 |
| 语言设置 | 实时同步 | 影响内容展示 |
| 设备音量 | 不同步 | 设备特定配置 |
| 网络配置 | 不同步 | 设备特定配置 |
2.3 冲突处理
配置冲突通常采用"最新优先"策略:
sequenceDiagram
participant DeviceA as 设备A
participant Cloud as 同步服务
participant DeviceB as 设备B
Note over DeviceA: 用户设置主题=dark<br/>时间=10:00:00
DeviceA->>Cloud: put('theme', 'dark', 10:00:00)
Note over DeviceB: 用户设置主题=light<br/>时间=10:00:01
DeviceB->>Cloud: put('theme', 'light', 10:00:01)
Cloud->>Cloud: 检测冲突<br/>时间戳比较
Cloud-->>DeviceA: 最终值: light (更新)
Cloud-->>DeviceB: 最终值: light
Note over DeviceA,DeviceB: 最终一致性达成
classDef primary fill:#4A90E2,stroke:#2E5C8A,stroke-width:2px,color:#fff
classDef warning fill:#F5A623,stroke:#C17D10,stroke-width:2px,color:#fff
classDef info fill:#7ED321,stroke:#5BA318,stroke-width:2px,color:#fff
class DeviceA,DeviceB primary
class Cloud warning
三、代码实战:实现分布式首选项
3.1 基础示例:创建和使用分布式首选项
import preferences from '@ohos.data.preferences';
import distributedData from '@ohos.data.distributedData';
import { BusinessError } from '@ohos.base';
/**
* 分布式首选项管理器
* 提供配置的存储、读取、同步能力
*/
export class DistributedPreferencesManager {
private preferences: preferences.Preferences | null = null;
private kvStore: distributedData.KVStore | null = null;
private readonly STORE_NAME = 'distributed_preferences';
/**
* 初始化分布式首选项
*/
async init(context: Context): Promise<void> {
try {
// 创建本地首选项
this.preferences = await preferences.getPreferences(context, this.STORE_NAME);
// 创建分布式KV存储(用于同步)
const kvManager = distributedData.createKVManager({
bundleName: context.applicationInfo.name,
userId: 0
});
this.kvStore = await kvManager.getKVStore('preferences_sync', {
createIfMissing: true,
autoSync: true,
kvStoreType: distributedData.KVStoreType.DEVICE_COLLABORATION,
securityLevel: distributedData.SecurityLevel.S1
});
// 设置远端数据监听
this.setupRemoteListener();
console.info('[DistributedPrefs] 初始化成功');
} catch (error) {
const err = error as BusinessError;
console.error(`[DistributedPrefs] 初始化失败: ${err.message}`);
throw error;
}
}
/**
* 获取配置值
* @param key 配置键
* @param defaultValue 默认值
*/
async get<T>(key: string, defaultValue: T): Promise<T> {
if (!this.preferences) {
throw new Error('首选项未初始化');
}
try {
const value = await this.preferences.get(key, defaultValue);
console.info(`[DistributedPrefs] 读取配置: ${key} = ${value}`);
return value as T;
} catch (error) {
console.error(`[DistributedPrefs] 读取失败: ${error}`);
return defaultValue;
}
}
/**
* 设置配置值
* @param key 配置键
* @param value 配置值
* @param sync 是否同步到其他设备
*/
async put<T>(key: string, value: T, sync: boolean = true): Promise<void> {
if (!this.preferences) {
throw new Error('首选项未初始化');
}
try {
// 写入本地
await this.preferences.put(key, value);
await this.preferences.flush();
console.info(`[DistributedPrefs] 写入配置: ${key} = ${value}`);
// 同步到远端
if (sync && this.kvStore) {
const syncData = {
key,
value,
timestamp: Date.now(),
deviceId: await this.getDeviceId()
};
await this.kvStore.put(key, JSON.stringify(syncData));
console.info(`[DistributedPrefs] 配置已同步: ${key}`);
}
} catch (error) {
console.error(`[DistributedPrefs] 写入失败: ${error}`);
throw error;
}
}
/**
* 删除配置
*/
async delete(key: string, sync: boolean = true): Promise<void> {
if (!this.preferences) {
throw new Error('首选项未初始化');
}
try {
await this.preferences.delete(key);
await this.preferences.flush();
console.info(`[DistributedPrefs] 删除配置: ${key}`);
if (sync && this.kvStore) {
await this.kvStore.delete(key);
}
} catch (error) {
console.error(`[DistributedPrefs] 删除失败: ${error}`);
throw error;
}
}
/**
* 清空所有配置
*/
async clear(sync: boolean = true): Promise<void> {
if (!this.preferences) {
throw new Error('首选项未初始化');
}
try {
await this.preferences.clear();
await this.preferences.flush();
console.info('[DistributedPrefs] 清空所有配置');
if (sync && this.kvStore) {
// 获取所有key并删除
const allKeys = await this.getAllSyncKeys();
for (const key of allKeys) {
await this.kvStore.delete(key);
}
}
} catch (error) {
console.error(`[DistributedPrefs] 清空失败: ${error}`);
throw error;
}
}
/**
* 设置远端数据监听
*/
private setupRemoteListener(): void {
if (!this.kvStore) return;
this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_REMOTE,
async (data: distributedData.ChangeNotification) => {
console.info('[DistributedPrefs] 收到远端配置变更');
// 处理更新的配置
for (const entry of data.updateEntries) {
await this.applyRemoteChange(entry.key, entry.value as string);
}
// 处理删除的配置
for (const entry of data.deleteEntries) {
await this.preferences?.delete(entry.key);
}
await this.preferences?.flush();
});
}
/**
* 应用远端变更
*/
private async applyRemoteChange(key: string, valueStr: string): Promise<void> {
if (!this.preferences) return;
try {
const remoteData = JSON.parse(valueStr);
// 读取本地时间戳
const localDataStr = await this.preferences.get(key, '');
if (localDataStr) {
const localData = JSON.parse(localDataStr as string);
// 时间戳比较:远端更新才应用
if (remoteData.timestamp <= localData.timestamp) {
console.info(`[DistributedPrefs] 本地更新,忽略远端变更: ${key}`);
return;
}
}
// 应用远端值
await this.preferences.put(key, remoteData.value);
console.info(`[DistributedPrefs] 应用远端配置: ${key} = ${remoteData.value}`);
// 触发变更通知
this.notifyChange(key, remoteData.value);
} catch (error) {
console.error(`[DistributedPrefs] 应用远端变更失败: ${error}`);
}
}
/**
* 获取所有同步的key
*/
private async getAllSyncKeys(): Promise<string[]> {
if (!this.kvStore) return [];
// 简化处理,实际应通过KVStore的API获取
return [];
}
/**
* 获取设备ID
*/
private async getDeviceId(): Promise<string> {
return 'device_' + Date.now();
}
/**
* 变更通知(子类可重写)
*/
protected notifyChange(key: string, value: any): void {
console.info(`[DistributedPrefs] 配置变更通知: ${key} = ${value}`);
}
}
3.2 进阶示例:类型安全的配置管理
import preferences from '@ohos.data.preferences';
/**
* 应用配置接口定义
* 强类型约束,避免拼写错误
*/
interface AppConfig {
// 外观设置
theme: 'light' | 'dark' | 'auto';
fontSize: number; // 12-24
language: string; // 'zh-CN', 'en-US'
// 通知设置
notificationEnabled: boolean;
notificationSound: boolean;
notificationVibration: boolean;
// 隐私设置
analyticsEnabled: boolean;
crashReportEnabled: boolean;
// 功能设置
autoPlayVideo: boolean;
imageQuality: 'low' | 'medium' | 'high' | 'auto';
downloadWiFiOnly: boolean;
}
/**
* 配置项元数据
*/
interface ConfigMeta {
key: keyof AppConfig;
defaultValue: any;
sync: boolean; // 是否同步
type: 'string' | 'number' | 'boolean';
validator?: (value: any) => boolean;
}
/**
* 类型安全的配置管理器
*/
export class TypedConfigManager extends DistributedPreferencesManager {
// 配置项定义
private static readonly CONFIG_META: ConfigMeta[] = [
{
key: 'theme',
defaultValue: 'auto',
sync: true,
type: 'string',
validator: (v) => ['light', 'dark', 'auto'].includes(v)
},
{
key: 'fontSize',
defaultValue: 16,
sync: true,
type: 'number',
validator: (v) => v >= 12 && v <= 24
},
{
key: 'language',
defaultValue: 'zh-CN',
sync: true,
type: 'string'
},
{
key: 'notificationEnabled',
defaultValue: true,
sync: true,
type: 'boolean'
},
{
key: 'notificationSound',
defaultValue: true,
sync: true,
type: 'boolean'
},
{
key: 'notificationVibration',
defaultValue: false,
sync: true,
type: 'boolean'
},
{
key: 'analyticsEnabled',
defaultValue: true,
sync: true,
type: 'boolean'
},
{
key: 'crashReportEnabled',
defaultValue: true,
sync: true,
type: 'boolean'
},
{
key: 'autoPlayVideo',
defaultValue: false,
sync: true,
type: 'boolean'
},
{
key: 'imageQuality',
defaultValue: 'auto',
sync: true,
type: 'string',
validator: (v) => ['low', 'medium', 'high', 'auto'].includes(v)
},
{
key: 'downloadWiFiOnly',
defaultValue: true,
sync: true,
type: 'boolean'
}
];
// 变更监听器
private changeListeners: Map<keyof AppConfig, Set<(value: any) => void>> = new Map();
/**
* 获取配置值(类型安全)
*/
async getConfig<K extends keyof AppConfig>(key: K): Promise<AppConfig[K]> {
const meta = this.getMeta(key);
const value = await this.get(key, meta.defaultValue);
// 验证
if (meta.validator && !meta.validator(value)) {
console.warn(`[TypedConfig] 配置值验证失败,使用默认值: ${key}`);
return meta.defaultValue;
}
return value;
}
/**
* 设置配置值(类型安全)
*/
async setConfig<K extends keyof AppConfig>(key: K, value: AppConfig[K]): Promise<void> {
const meta = this.getMeta(key);
// 类型检查
if (!this.checkType(value, meta.type)) {
throw new Error(`配置值类型错误: ${key} 期望 ${meta.type}`);
}
// 验证
if (meta.validator && !meta.validator(value)) {
throw new Error(`配置值验证失败: ${key}`);
}
// 写入
await this.put(key, value, meta.sync);
// 触发监听器
this.triggerListeners(key, value);
}
/**
* 批量获取配置
*/
async getAllConfig(): Promise<AppConfig> {
const config: Partial<AppConfig> = {};
for (const meta of TypedConfigManager.CONFIG_META) {
config[meta.key] = await this.getConfig(meta.key);
}
return config as AppConfig;
}
/**
* 批量设置配置
*/
async setAllConfig(config: Partial<AppConfig>): Promise<void> {
for (const [key, value] of Object.entries(config)) {
await this.setConfig(key as keyof AppConfig, value);
}
}
/**
* 重置为默认值
*/
async resetToDefault(key?: keyof AppConfig): Promise<void> {
if (key) {
const meta = this.getMeta(key);
await this.setConfig(key, meta.defaultValue);
} else {
for (const meta of TypedConfigManager.CONFIG_META) {
await this.setConfig(meta.key, meta.defaultValue);
}
}
console.info('[TypedConfig] 已重置为默认值');
}
/**
* 注册变更监听器
*/
onChange<K extends keyof AppConfig>(key: K, callback: (value: AppConfig[K]) => void): void {
if (!this.changeListeners.has(key)) {
this.changeListeners.set(key, new Set());
}
this.changeListeners.get(key)!.add(callback);
}
/**
* 移除变更监听器
*/
offChange<K extends keyof AppConfig>(key: K, callback?: (value: AppConfig[K]) => void): void {
if (!callback) {
this.changeListeners.delete(key);
} else {
this.changeListeners.get(key)?.delete(callback);
}
}
/**
* 触发监听器
*/
private triggerListeners(key: keyof AppConfig, value: any): void {
const listeners = this.changeListeners.get(key);
if (listeners) {
for (const callback of listeners) {
try {
callback(value);
} catch (error) {
console.error(`[TypedConfig] 监听器执行失败: ${error}`);
}
}
}
}
/**
* 获取配置元数据
*/
private getMeta(key: keyof AppConfig): ConfigMeta {
const meta = TypedConfigManager.CONFIG_META.find(m => m.key === key);
if (!meta) {
throw new Error(`未知的配置项: ${key}`);
}
return meta;
}
/**
* 类型检查
*/
private checkType(value: any, type: string): boolean {
switch (type) {
case 'string':
return typeof value === 'string';
case 'number':
return typeof value === 'number';
case 'boolean':
return typeof value === 'boolean';
default:
return true;
}
}
/**
* 重写父类的变更通知
*/
protected notifyChange(key: string, value: any): void {
this.triggerListeners(key as keyof AppConfig, value);
}
}
3.3 高级示例:配置分组与迁移
import preferences from '@ohos.data.preferences';
/**
* 配置分组枚举
*/
enum ConfigGroup {
APPEARANCE = 'appearance', // 外观
NOTIFICATION = 'notification', // 通知
PRIVACY = 'privacy', // 隐私
FEATURE = 'feature', // 功能
DEVICE = 'device' // 设备特定(不同步)
}
/**
* 分组配置项定义
*/
interface GroupedConfigMeta extends ConfigMeta {
group: ConfigGroup;
description: string; // 配置描述
version: number; // 配置版本(用于迁移)
}
/**
* 高级配置管理器
* 支持分组、迁移、导入导出
*/
export class AdvancedConfigManager extends TypedConfigManager {
// 分组配置定义
private static readonly GROUPED_CONFIG: GroupedConfigMeta[] = [
// 外观组
{
key: 'theme',
group: ConfigGroup.APPEARANCE,
defaultValue: 'auto',
sync: true,
type: 'string',
description: '应用主题',
version: 1
},
{
key: 'fontSize',
group: ConfigGroup.APPEARANCE,
defaultValue: 16,
sync: true,
type: 'number',
description: '字体大小',
version: 1
},
{
key: 'language',
group: ConfigGroup.APPEARANCE,
defaultValue: 'zh-CN',
sync: true,
type: 'string',
description: '应用语言',
version: 1
},
// 通知组
{
key: 'notificationEnabled',
group: ConfigGroup.NOTIFICATION,
defaultValue: true,
sync: true,
type: 'boolean',
description: '通知开关',
version: 1
},
{
key: 'notificationSound',
group: ConfigGroup.NOTIFICATION,
defaultValue: true,
sync: true,
type: 'boolean',
description: '通知声音',
version: 1
},
// 隐私组
{
key: 'analyticsEnabled',
group: ConfigGroup.PRIVACY,
defaultValue: true,
sync: true,
type: 'boolean',
description: '数据分析',
version: 1
},
// 功能组
{
key: 'autoPlayVideo',
group: ConfigGroup.FEATURE,
defaultValue: false,
sync: true,
type: 'boolean',
description: '自动播放视频',
version: 1
},
{
key: 'imageQuality',
group: ConfigGroup.FEATURE,
defaultValue: 'auto',
sync: true,
type: 'string',
description: '图片质量',
version: 1
}
];
/**
* 按组获取配置
*/
async getConfigByGroup(group: ConfigGroup): Promise<Record<string, any>> {
const config: Record<string, any> = {};
const groupConfigs = AdvancedConfigManager.GROUPED_CONFIG.filter(c => c.group === group);
for (const meta of groupConfigs) {
config[meta.key] = await this.getConfig(meta.key as keyof AppConfig);
}
return config;
}
/**
* 按组设置配置
*/
async setConfigByGroup(group: ConfigGroup, config: Record<string, any>): Promise<void> {
for (const [key, value] of Object.entries(config)) {
const meta = AdvancedConfigManager.GROUPED_CONFIG.find(c => c.key === key);
if (meta && meta.group === group) {
await this.setConfig(key as keyof AppConfig, value);
}
}
}
/**
* 导出配置(用于备份)
*/
async exportConfig(groups?: ConfigGroup[]): Promise<string> {
const exportData: any = {
version: 1,
timestamp: Date.now(),
deviceId: await this.getDeviceId(),
config: {}
};
const targetGroups = groups || Object.values(ConfigGroup);
for (const group of targetGroups) {
exportData.config[group] = await this.getConfigByGroup(group);
}
return JSON.stringify(exportData, null, 2);
}
/**
* 导入配置(用于恢复)
*/
async importConfig(jsonStr: string, merge: boolean = true): Promise<ImportResult> {
const result: ImportResult = {
success: true,
imported: 0,
skipped: 0,
errors: []
};
try {
const importData = JSON.parse(jsonStr);
// 版本检查
if (importData.version !== 1) {
throw new Error(`不支持的配置版本: ${importData.version}`);
}
// 导入各组配置
for (const [group, config] of Object.entries(importData.config)) {
const groupEnum = group as ConfigGroup;
for (const [key, value] of Object.entries(config as Record<string, any>)) {
try {
const meta = AdvancedConfigManager.GROUPED_CONFIG.find(c => c.key === key);
if (!meta) {
result.skipped++;
continue;
}
// 如果不合并,先检查是否已存在
if (!merge) {
const existing = await this.getConfig(key as keyof AppConfig);
if (existing !== meta.defaultValue) {
result.skipped++;
continue;
}
}
// 执行导入
await this.setConfig(key as keyof AppConfig, value);
result.imported++;
} catch (error) {
result.errors.push({ key, error: String(error) });
}
}
}
console.info(`[AdvancedConfig] 导入完成: 成功 ${result.imported}, 跳过 ${result.skipped}, 错误 ${result.errors.length}`);
} catch (error) {
result.success = false;
result.errors.push({ key: 'global', error: String(error) });
}
return result;
}
/**
* 配置迁移
* 当配置结构变更时执行
*/
async migrateConfig(fromVersion: number, toVersion: number): Promise<void> {
console.info(`[AdvancedConfig] 开始迁移: ${fromVersion} -> ${toVersion}`);
// 示例:从版本1迁移到版本2
if (fromVersion === 1 && toVersion === 2) {
// 读取旧配置
const oldTheme = await this.getConfig('theme');
// 迁移逻辑(示例:主题值变更)
let newTheme = oldTheme;
if (oldTheme === 'night') {
newTheme = 'dark';
}
// 写入新配置
await this.setConfig('theme', newTheme);
console.info('[AdvancedConfig] 迁移完成: theme night -> dark');
}
// 更新版本号
await this.put('_config_version', toVersion, false);
}
/**
* 检查并执行迁移
*/
async checkAndMigrate(): Promise<void> {
const currentVersion = await this.get('_config_version', 1);
const targetVersion = 2; // 当前最新版本
if (currentVersion < targetVersion) {
await this.migrateConfig(currentVersion, targetVersion);
}
}
/**
* 获取配置描述
*/
getConfigDescription(key: keyof AppConfig): string {
const meta = AdvancedConfigManager.GROUPED_CONFIG.find(c => c.key === key);
return meta?.description || '';
}
/**
* 获取组的所有配置项
*/
getGroupConfigs(group: ConfigGroup): GroupedConfigMeta[] {
return AdvancedConfigManager.GROUPED_CONFIG.filter(c => c.group === group);
}
private async getDeviceId(): Promise<string> {
return 'device_' + Date.now();
}
}
interface ImportResult {
success: boolean;
imported: number;
skipped: number;
errors: Array<{ key: string; error: string }>;
}
四、踩坑与注意事项
4.1 配置同步延迟
问题:配置修改后,其他设备没有立即生效。
解决方案:主动同步 + UI提示
/**
* 带同步提示的配置管理
*/
export class SyncAwareConfigManager extends AdvancedConfigManager {
private syncStatus: 'idle' | 'syncing' | 'synced' | 'error' = 'idle';
/**
* 设置配置并等待同步
*/
async setConfigAndWait<K extends keyof AppConfig>(
key: K,
value: AppConfig[K],
timeout: number = 5000
): Promise<boolean> {
this.syncStatus = 'syncing';
try {
await this.setConfig(key, value);
// 等待同步完成
const synced = await this.waitForSync(timeout);
this.syncStatus = synced ? 'synced' : 'error';
return synced;
} catch (error) {
this.syncStatus = 'error';
return false;
}
}
/**
* 等待同步完成
*/
private async waitForSync(timeout: number): Promise<boolean> {
return new Promise((resolve) => {
// 简化处理,实际应监听同步事件
setTimeout(() => resolve(true), 100);
// 超时
setTimeout(() => resolve(false), timeout);
});
}
/**
* 获取同步状态
*/
getSyncStatus(): string {
return this.syncStatus;
}
}
4.2 配置验证失败
问题:导入的配置值不符合验证规则。
解决方案:宽松验证 + 降级处理
/**
* 宽松验证配置管理器
*/
export class LenientConfigManager extends AdvancedConfigManager {
/**
* 导入配置(宽松模式)
* 验证失败时使用默认值而不是报错
*/
async importConfigLenient(jsonStr: string): Promise<ImportResult> {
const result: ImportResult = {
success: true,
imported: 0,
skipped: 0,
errors: []
};
try {
const importData = JSON.parse(jsonStr);
for (const [group, config] of Object.entries(importData.config)) {
for (const [key, value] of Object.entries(config as Record<string, any>)) {
try {
const meta = AdvancedConfigManager.GROUPED_CONFIG.find(c => c.key === key);
if (!meta) {
result.skipped++;
continue;
}
// 宽松验证:失败时使用默认值
let finalValue = value;
if (meta.validator && !meta.validator(value)) {
console.warn(`[LenientConfig] 验证失败,使用默认值: ${key}`);
finalValue = meta.defaultValue;
}
await this.setConfig(key as keyof AppConfig, finalValue);
result.imported++;
} catch (error) {
// 记录错误但继续处理
result.errors.push({ key, error: String(error) });
}
}
}
} catch (error) {
result.success = false;
result.errors.push({ key: 'global', error: String(error) });
}
return result;
}
}
4.3 配置冲突处理
问题:多设备同时修改同一配置。
解决方案:时间戳优先 + 用户确认
/**
* 冲突感知配置管理器
*/
export class ConflictAwareConfigManager extends AdvancedConfigManager {
/**
* 设置配置(带冲突检测)
*/
async setConfigWithConflictCheck<K extends keyof AppConfig>(
key: K,
value: AppConfig[K],
expectedTimestamp?: number
): Promise<ConflictResult> {
// 读取当前配置的时间戳
const currentData = await this.getConfigWithTimestamp(key);
// 检查冲突
if (expectedTimestamp && currentData.timestamp > expectedTimestamp) {
return {
hasConflict: true,
currentValue: currentData.value,
currentTimestamp: currentData.timestamp,
proposedValue: value
};
}
// 无冲突,执行设置
await this.setConfig(key, value);
return {
hasConflict: false
};
}
/**
* 解决冲突
*/
async resolveConflict<K extends keyof AppConfig>(
key: K,
resolution: 'local' | 'remote' | 'custom',
customValue?: AppConfig[K]
): Promise<void> {
switch (resolution) {
case 'local':
// 保留本地值,无需操作
break;
case 'remote':
// 应用远端值(需要重新获取)
break;
case 'custom':
if (customValue !== undefined) {
await this.setConfig(key, customValue);
}
break;
}
}
/**
* 获取配置带时间戳
*/
private async getConfigWithTimestamp<K extends keyof AppConfig>(
key: K
): Promise<{ value: AppConfig[K]; timestamp: number }> {
const value = await this.getConfig(key);
const timestamp = Date.now(); // 简化处理
return { value, timestamp };
}
}
interface ConflictResult {
hasConflict: boolean;
currentValue?: any;
currentTimestamp?: number;
proposedValue?: any;
}
五、HarmonyOS 6适配指南
5.1 API变更
5.1.1 Preferences API增强
// HarmonyOS 5.0
const prefs = await preferences.getPreferences(context, 'my_prefs');
await prefs.put('key', 'value');
await prefs.flush();
// HarmonyOS 6 - 增强的Preferences
import preferences from '@kit.ArkData';
const prefs = await preferences.getPreferences(context, 'my_prefs', {
// HarmonyOS 6新增配置
autoSave: true, // 自动保存,无需手动flush
encrypt: true, // 加密存储
backup: true, // 支持备份
distributed: true // 支持分布式同步
});
// 直接设置,自动保存
await prefs.put('key', 'value'); // 自动flush
// 批量操作
await prefs.putBatch({
'key1': 'value1',
'key2': 'value2',
'key3': 'value3'
});
5.1.2 分布式同步API
// HarmonyOS 6新增:分布式同步控制
import preferences from '@kit.ArkData';
const distributedPrefs = await preferences.getDistributedPreferences(context, 'shared_prefs', {
// 同步配置
syncMode: preferences.SyncMode.AUTO, // 自动同步
conflictStrategy: 'timestamp', // 冲突策略
syncScope: preferences.SyncScope.ALL_DEVICES // 同步范围
});
// 设置同步范围
await distributedPrefs.setSyncScope(preferences.SyncScope.SPECIFIC_DEVICES, ['device1', 'device2']);
// 手动触发同步
await distributedPrefs.sync();
// 获取同步状态
const syncStatus = await distributedPrefs.getSyncStatus();
console.info(`同步状态: ${syncStatus.status}`);
console.info(`上次同步: ${syncStatus.lastSyncTime}`);
5.2 行为变更
5.2.1 自动保存
// HarmonyOS 5.0: 需要手动flush
await prefs.put('key', 'value');
await prefs.flush(); // 必须调用
// HarmonyOS 6: 自动保存
const prefs = await preferences.getPreferences(context, 'my_prefs', {
autoSave: true // 启用自动保存
});
await prefs.put('key', 'value'); // 自动保存,无需flush
5.3 性能优化
/**
* HarmonyOS 6性能优化配置
*/
export class HarmonyOS6PrefsOptimization {
/**
* 推荐配置
*/
getOptimizedOptions(): preferences.Options {
return {
autoSave: true,
encrypt: false, // 非敏感配置不加密,提升性能
backup: true,
distributed: true,
// 缓存配置
cache: {
enabled: true,
maxSize: 1000 // 最多缓存1000个配置项
},
// 同步配置
sync: {
mode: 'batch', // 批量同步
batchSize: 10, // 每批10个
delay: 1000 // 延迟1秒合并
}
};
}
}
六、总结
分布式首选项让应用的个性化配置真正实现"一次设置,处处生效"。通过本文的深度解析,我们掌握了:
核心要点:
- 架构理解:本地存储 + 分布式同步的双重机制
- API使用:基础操作、类型安全、分组管理、导入导出
- 同步策略:实时同步、延迟同步、不同步的选择
- 冲突处理:时间戳优先、用户确认、自定义策略
- 避坑指南:同步延迟、验证失败、冲突处理
- 版本适配:HarmonyOS 6的API增强、自动保存、性能优化
最佳实践:
- 个人偏好配置:启用同步,保证体验一致
- 设备特定配置:禁用同步,避免干扰
- 敏感配置:启用加密,保护隐私
- 批量修改:使用putBatch,提升性能
配置分类建议:
配置类型
├─ 外观设置(同步)
│ ├─ 主题
│ ├─ 字体大小
│ └─ 语言
├─ 通知设置(同步)
│ ├─ 通知开关
│ ├─ 声音
│ └─ 振动
├─ 隐私设置(同步)
│ ├─ 数据分析
│ └─ 崩溃报告
├─ 功能设置(同步)
│ ├─ 自动播放
│ └─ 图片质量
└─ 设备设置(不同步)
├─ 音量
└─ 网络配置
掌握分布式首选项,让你的应用配置真正实现跨设备的无缝同步,为用户提供一致的使用体验。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)