
鸿蒙跨端用户偏好同步:主题设置多设备实时同步方案 原创
鸿蒙跨端用户偏好同步:主题设置多设备实时同步方案
本文将基于HarmonyOS 5的Preferences数据存储和分布式能力,实现一个跨设备的主题偏好设置系统,能够在不同设备间实时同步用户的主题选择(深色/浅色模式)。
技术架构
本地存储层:使用Preferences持久化存储主题设置
业务逻辑层:处理主题切换逻辑和跨设备同步
分布式同步层:通过分布式数据管理实现多设备同步
UI响应层:实时响应主题变化更新界面
完整代码实现
主题类型定义
// model/ThemeTypes.ts
export enum ThemeType {
LIGHT = ‘light’,
DARK = ‘dark’,
SYSTEM = ‘system’
export const THEME_KEY = ‘user_theme_preference’;
export const SYNC_THEME_KEY = ‘sync_theme_preference’;
本地主题管理服务
// service/LocalThemeService.ts
import { preferences } from ‘@ohos.data.preferences’;
import { THEME_KEY, ThemeType } from ‘…/model/ThemeTypes’;
const PREFERENCES_NAME = ‘user_settings’;
export class LocalThemeService {
private pref: preferences.Preferences;
// 初始化Preferences
async initPreferences() {
try {
this.pref = await preferences.getPreferences(globalThis.context, PREFERENCES_NAME);
catch (err) {
console.error('Failed to init preferences:', err);
}
// 获取当前主题
async getTheme(): Promise<ThemeType> {
try {
const theme = await this.pref.get(THEME_KEY, ThemeType.SYSTEM);
return theme as ThemeType;
catch (err) {
return ThemeType.SYSTEM;
}
// 设置主题
async setTheme(theme: ThemeType): Promise<void> {
try {
await this.pref.put(THEME_KEY, theme);
await this.pref.flush();
catch (err) {
console.error('Failed to save theme:', err);
}
分布式主题同步服务
// service/DistributedThemeService.ts
import distributedData from ‘@ohos.data.distributedData’;
import { SYNC_THEME_KEY, ThemeType } from ‘…/model/ThemeTypes’;
const STORE_ID = ‘theme_sync_store’;
export class DistributedThemeService {
private kvManager: distributedData.KVManager;
private kvStore: distributedData.SingleKVStore;
// 初始化分布式数据库
async initKVStore() {
const config = {
bundleName: ‘com.example.themeapp’,
userInfo: {
userId: ‘defaultUser’,
userType: distributedData.UserType.SAME_USER_ID
};
this.kvManager = distributedData.createKVManager(config);
const options = {
createIfMissing: true,
encrypt: false,
backup: false,
autoSync: true,
kvStoreType: distributedData.KVStoreType.SINGLE_VERSION
};
this.kvStore = await this.kvManager.getKVStore(STORE_ID, options);
// 订阅主题变更
this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => {
this.handleThemeChange(data);
});
// 处理主题变更
private handleThemeChange(data: distributedData.ChangeNotification) {
if (data.insertEntries.length > 0) {
const entry = data.insertEntries.find(e => e.key === SYNC_THEME_KEY);
if (entry) {
const newTheme = entry.value.value as ThemeType;
AppStorage.setOrCreate(‘currentTheme’, newTheme);
// 更新本地存储
const themeManager = new LocalThemeService();
themeManager.setTheme(newTheme);
themeManager.applyThemeToUI(newTheme);
}
// 同步主题到其他设备
async syncTheme(theme: ThemeType) {
try {
await this.kvStore.put(SYNC_THEME_KEY, theme);
catch (err) {
console.error('Failed to sync theme:', err);
}
主题设置页面实现
// pages/ThemeSettingPage.ets
import { ThemeType } from ‘…/model/ThemeTypes’;
import { LocalThemeService } from ‘…/service/LocalThemeService’;
import { DistributedThemeService } from ‘…/service/DistributedThemeService’;
@Entry
@Component
struct ThemeSettingPage {
private localThemeService: LocalThemeService = new LocalThemeService();
private distThemeService: DistributedThemeService = new DistributedThemeService();
@State currentTheme: ThemeType = ThemeType.SYSTEM;
@State isSyncing: boolean = false;
async aboutToAppear() {
await this.localThemeService.initPreferences();
await this.distThemeService.initKVStore();
this.currentTheme = await this.localThemeService.getTheme();
build() {
Column() {
Text('主题设置')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 30 })
// 主题选项
Column() {
ThemeOption({
theme: ThemeType.LIGHT,
current: this.currentTheme,
title: '浅色模式',
icon: $r('app.media.ic_light'),
onSelect: () => this.changeTheme(ThemeType.LIGHT)
})
Divider().margin(10)
ThemeOption({
theme: ThemeType.DARK,
current: this.currentTheme,
title: '深色模式',
icon: $r('app.media.ic_dark'),
onSelect: () => this.changeTheme(ThemeType.DARK)
})
Divider().margin(10)
ThemeOption({
theme: ThemeType.SYSTEM,
current: this.currentTheme,
title: '跟随系统',
icon: $r('app.media.ic_system'),
onSelect: () => this.changeTheme(ThemeType.SYSTEM)
})
.width(‘90%’)
.padding(20)
.backgroundColor($r('app.color.card_background'))
.borderRadius(12)
// 同步开关
Row() {
Text('跨设备同步主题设置')
.fontSize(16)
.layoutWeight(1)
Toggle({ type: ToggleType.Switch })
.onChange((isOn: boolean) => {
AppStorage.setOrCreate('syncThemeEnabled', isOn);
})
.width(‘90%’)
.margin({ top: 30 })
// 同步状态
if (this.isSyncing) {
Row() {
LoadingProgress()
.width(20)
.height(20)
.margin({ right: 8 })
Text('同步中...')
.fontSize(14)
.fontColor('#666666')
.margin({ top: 20 })
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.background'))
// 切换主题
private async changeTheme(theme: ThemeType) {
this.currentTheme = theme;
await this.localThemeService.setTheme(theme);
this.applyTheme(theme);
// 如果开启了同步,则同步到其他设备
if (AppStorage.get('syncThemeEnabled')) {
this.isSyncing = true;
await this.distThemeService.syncTheme(theme);
this.isSyncing = false;
}
// 应用主题到UI
private applyTheme(theme: ThemeType) {
const systemUI = getContext().resourceManager;
if (theme === ThemeType.SYSTEM) {
// 跟随系统主题
const isDarkMode = systemUI.getConfiguration().colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
theme = isDarkMode ? ThemeType.DARK : ThemeType.LIGHT;
// 更新全局主题变量
AppStorage.setOrCreate('currentTheme', theme);
// 实际应用中这里可以设置状态栏、导航栏等系统UI
if (theme === ThemeType.DARK) {
systemUI.setDarkMode(true);
else {
systemUI.setDarkMode(false);
}
@Component
struct ThemeOption {
@Prop theme: ThemeType;
@Prop current: ThemeType;
@Prop title: string;
@Prop icon: Resource;
@Prop onSelect: () => void;
build() {
Row() {
Image(this.icon)
.width(24)
.height(24)
.margin({ right: 15 })
Text(this.title)
.fontSize(18)
.layoutWeight(1)
if (this.theme === this.current) {
Image($r('app.media.ic_check'))
.width(20)
.height(20)
}
.width('100%')
.height(60)
.onClick(() => {
this.onSelect();
})
}
主题应用扩展
// 扩展CommonMethod支持主题样式
declare module ‘@ohos.arkui.base’ {
interface CommonMethod<T> {
themeStyles(theme: ThemeType): T;
}
CommonMethod.prototype.themeStyles = function<T>(this: CommonMethod<T>, theme: ThemeType): T {
const isDark = theme === ThemeType.DARK;
return this
.backgroundColor(isDark ? r(‘app.color.dark_background’) : r(‘app.color.light_background’))
.fontColor(isDark ? r(‘app.color.dark_text’) : r(‘app.color.light_text’));
};
// 在页面中使用
@Component
struct ThemedComponent {
@StorageLink(‘currentTheme’) currentTheme: ThemeType;
build() {
Column() {
Text(‘主题化组件’)
.themeStyles(this.currentTheme)
}
实现原理详解
数据存储与同步流程:
用户在一个设备上更改主题设置
设置首先保存到本地Preferences
如果开启了同步,通过分布式KVStore同步到其他设备
其他设备收到变更通知后更新本地Preferences和UI
主题应用机制:
使用AppStorage管理当前主题状态
通过自定义扩展方法统一应用主题样式
支持动态切换不重启应用
冲突解决策略:
最后修改的设备优先级最高
同步时携带时间戳解决冲突
本地变更优先于远程变更
扩展功能建议
主题同步历史记录:
// 记录主题变更历史
async recordThemeChange(theme: ThemeType, deviceId: string) {
const historyKey = ‘theme_change_history’;
const history = await this.pref.get(historyKey, []);
history.push({
theme,
deviceId,
timestamp: new Date().toISOString()
});
await this.pref.put(historyKey, history.slice(-10)); // 保留最近10条记录
多主题扩展支持:
// 支持自定义主题
enum CustomTheme {
BLUE = ‘blue’,
GREEN = ‘green’,
PINK = ‘pink’
// 动态加载主题资源
function getThemeResource(theme: string) {
switch (theme) {
case CustomTheme.BLUE:
return { bgColor: ‘#E3F2FD’, textColor: ‘#0D47A1’ };
// 其他主题…
}
同步冲突可视化:
// 显示同步冲突解决界面
function showConflictResolution(localTheme: ThemeType, remoteTheme: ThemeType) {
AlertDialog.show({
title: ‘主题冲突’,
message: 本地主题: {localTheme}\n远程主题: {remoteTheme},
buttons: [
text: ‘使用本地’, action: () => this.syncTheme(localTheme) },
text: ‘使用远程’, action: () => this.applyTheme(remoteTheme) }
});
总结
本文展示了如何利用HarmonyOS的Preferences和分布式能力实现跨设备的主题偏好同步系统。通过本地存储确保单设备体验的一致性,再通过分布式数据管理扩展到多设备场景,为用户提供无缝的跨设备主题体验。
这种模式不仅适用于主题设置,还可以扩展到字体大小、语言偏好、通知设置等各种用户偏好设置场景,是构建HarmonyOS全场景应用的重要模式之一。合理利用这些能力,可以显著提升用户体验和应用粘性。
