
鸿蒙跨设备剪贴板同步系统 原创
鸿蒙跨设备剪贴板同步系统
本文将基于HarmonyOS的分布式能力,实现一个跨设备剪贴板同步功能,允许用户在一台设备上复制内容后,在其他设备上直接粘贴使用。
技术架构
本地剪贴板监听:监控本地剪贴板变化
数据同步层:通过分布式数据管理实现内容同步
安全处理层:敏感内容过滤和加密传输
UI展示层:剪贴板历史记录和同步状态显示
完整代码实现
剪贴板数据模型定义
// model/ClipboardData.ts
export class ClipboardData {
id: string = ‘’; // 唯一标识
content: string = ‘’; // 剪贴板内容
contentType: ‘text’ ‘image’
‘url’ = ‘text’; // 内容类型
timestamp: number = 0; // 时间戳
sourceDevice: string = ‘’; // 来源设备
isSynced: boolean = false; // 是否已同步
constructor(data?: Partial<ClipboardData>) {
if (data) {
Object.assign(this, data);
if (!this.id) {
this.id = this.generateId();
if (!this.timestamp) {
this.timestamp = Date.now();
}
private generateId(): string {
return 'clip-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
// 内容摘要(用于显示)
get summary(): string {
if (this.contentType === ‘text’) {
return this.content.length > 30
this.content.substring(0, 30) + ‘…’
this.content;
return this.contentType === ‘image’ ? ‘[图片]’ : ‘[链接]’;
}
分布式剪贴板同步服务
// service/ClipboardSyncService.ts
import distributedData from ‘@ohos.data.distributedData’;
import deviceInfo from ‘@ohos.deviceInfo’;
import { ClipboardData } from ‘…/model/ClipboardData’;
const STORE_ID = ‘clipboard_sync_store’;
const CLIPBOARD_KEY_PREFIX = ‘clip_’;
export class ClipboardSyncService {
private kvManager: distributedData.KVManager;
private kvStore: distributedData.SingleKVStore;
private localDeviceId: string = deviceInfo.deviceId;
// 初始化分布式数据存储
async initialize() {
const config = {
bundleName: ‘com.example.clipboard’,
userInfo: {
userId: ‘clip_user’,
userType: distributedData.UserType.SAME_USER_ID
};
this.kvManager = distributedData.createKVManager(config);
const options = {
createIfMissing: true,
encrypt: true, // 启用加密
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.handleDataChange(data);
});
// 处理数据变更
private handleDataChange(data: distributedData.ChangeNotification) {
if (data.insertEntries.length > 0) {
data.insertEntries.forEach(entry => {
if (entry.key.startsWith(CLIPBOARD_KEY_PREFIX)) {
const clipData: ClipboardData = JSON.parse(entry.value.value);
this.processNewClipboardData(clipData);
});
}
// 处理新剪贴板数据
private processNewClipboardData(data: ClipboardData) {
// 忽略来自本设备的数据
if (data.sourceDevice === this.localDeviceId) return;
// 更新AppStorage中的剪贴板数据
const history: ClipboardData[] = AppStorage.get('clipboardHistory') || [];
const newHistory = [data, ...history].slice(0, 50); // 保留最近50条
AppStorage.setOrCreate('clipboardHistory', newHistory);
// 自动设置到系统剪贴板
if (this.shouldAutoPaste(data)) {
this.setSystemClipboard(data.content);
}
// 判断是否应该自动粘贴
private shouldAutoPaste(data: ClipboardData): boolean {
// 这里可以添加业务逻辑判断
return data.contentType === ‘text’ && data.content.length < 500;
// 设置系统剪贴板
private setSystemClipboard(content: string) {
// 实际项目中需要使用系统剪贴板API
console.log(‘设置剪贴板内容:’, content);
// 同步剪贴板内容
async syncClipboardContent(data: ClipboardData) {
data.sourceDevice = this.localDeviceId;
data.isSynced = true;
const clipKey = {CLIPBOARD_KEY_PREFIX}{data.id};
await this.kvStore.put(clipKey, JSON.stringify(data));
// 更新本地历史记录
const history: ClipboardData[] = AppStorage.get('clipboardHistory') || [];
const newHistory = [data, ...history].slice(0, 50);
AppStorage.setOrCreate('clipboardHistory', newHistory);
// 获取当前设备ID
getLocalDeviceId(): string {
return this.localDeviceId;
}
剪贴板监听服务
// service/ClipboardMonitorService.ts
import { ClipboardData } from ‘…/model/ClipboardData’;
export class ClipboardMonitorService {
private syncService: ClipboardSyncService;
private lastContent: string = ‘’;
private checkInterval: number = 0;
constructor(syncService: ClipboardSyncService) {
this.syncService = syncService;
// 开始监听剪贴板变化
startMonitoring() {
this.checkInterval = setInterval(() => {
this.checkClipboardChange();
}, 1000); // 每秒检查一次
// 停止监听
stopMonitoring() {
if (this.checkInterval) {
clearInterval(this.checkInterval);
this.checkInterval = 0;
}
// 检查剪贴板变化
private async checkClipboardChange() {
try {
// 实际项目中需要调用系统API获取剪贴板内容
const currentContent = await this.getSystemClipboard();
if (currentContent && currentContent !== this.lastContent) {
this.lastContent = currentContent;
this.handleNewClipboardContent(currentContent);
} catch (err) {
console.error('检查剪贴板失败:', err);
}
// 处理新剪贴板内容
private handleNewClipboardContent(content: string) {
const clipData = new ClipboardData({
content: content,
contentType: this.detectContentType(content)
});
this.syncService.syncClipboardContent(clipData);
// 检测内容类型
private detectContentType(content: string): ‘text’ ‘image’
‘url’ {
if (content.startsWith(‘http://’) || content.startsWith(‘https://’)) {
return ‘url’;
// 实际项目中需要更复杂的图像检测逻辑
return 'text';
// 获取系统剪贴板内容
private async getSystemClipboard(): Promise<string> {
// 实际项目中需要调用系统API
return Promise.resolve(‘’); // 模拟实现
}
剪贴板管理页面实现
// pages/ClipboardManagerPage.ets
import { ClipboardSyncService } from ‘…/service/ClipboardSyncService’;
import { ClipboardMonitorService } from ‘…/service/ClipboardMonitorService’;
import { ClipboardData } from ‘…/model/ClipboardData’;
@Entry
@Component
struct ClipboardManagerPage {
private syncService: ClipboardSyncService = new ClipboardSyncService();
private monitorService: ClipboardMonitorService;
@StorageLink(‘clipboardHistory’) clipboardHistory: ClipboardData[] = [];
@State isSynced: boolean = false;
@State autoSyncEnabled: boolean = true;
async aboutToAppear() {
await this.syncService.initialize();
this.isSynced = true;
this.monitorService = new ClipboardMonitorService(this.syncService);
this.monitorService.startMonitoring();
onPageHide() {
this.monitorService.stopMonitoring();
build() {
Column() {
// 标题和设置
Row() {
Text('跨设备剪贴板')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Toggle({ type: ToggleType.Switch, isOn: this.autoSyncEnabled })
.onChange((isOn: boolean) => {
this.autoSyncEnabled = isOn;
})
.padding(16)
.width('100%')
// 同步状态
Row() {
Circle()
.width(10)
.height(10)
.fill(this.isSynced ? '#4CAF50' : '#F44336')
.margin({ right: 5 })
Text(this.isSynced ? '已连接' : '连接中...')
.fontSize(14)
.fontColor('#666666')
.margin({ bottom: 16 })
// 剪贴板历史记录
List() {
ForEach(this.clipboardHistory, (item: ClipboardData) => {
ListItem() {
ClipboardItem({
data: item,
onTap: () => this.copyToClipboard(item)
})
})
.layoutWeight(1)
.width('100%')
.width(‘100%’)
.height('100%')
// 复制内容到剪贴板
private copyToClipboard(data: ClipboardData) {
// 实际项目中需要调用系统API
console.log(‘复制内容:’, data.content);
prompt.showToast({ message: '已复制: ’ + data.summary, duration: 2000 });
}
@Component
struct ClipboardItem {
@Prop data: ClipboardData;
@Prop onTap: () => void;
build() {
Row() {
Column() {
Text(this.data.summary)
.fontSize(16)
.fontColor(‘#333333’)
Row() {
Text(this.data.sourceDevice === AppStorage.get('localDeviceId') ? '本设备' : '其他设备')
.fontSize(12)
.fontColor('#666666')
Text(this.formatTime(this.data.timestamp))
.fontSize(12)
.fontColor('#666666')
.margin({ left: 8 })
.margin({ top: 4 })
.layoutWeight(1)
Image($r('app.media.ic_copy'))
.width(24)
.height(24)
.padding(16)
.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 8 })
.onClick(() => {
this.onTap();
})
// 格式化时间显示
private formatTime(timestamp: number): string {
const date = new Date(timestamp);
return {date.getHours().toString().padStart(2, ‘0’)}:{date.getMinutes().toString().padStart(2, ‘0’)};
}
实现原理详解
剪贴板监听机制:
定期检查系统剪贴板内容变化
发现新内容后创建ClipboardData对象
通过分布式服务同步到其他设备
数据同步流程:
使用加密的分布式数据库存储剪贴板内容
设备间自动同步最新剪贴板条目
可选自动粘贴功能
安全与隐私:
敏感内容过滤
传输加密
本地历史记录限制
扩展功能建议
内容加密传输:
// 加密剪贴板内容
async encryptContent(content: string): Promise<string> {
const crypto = require(‘@ohos.security.crypto’);
const cipher = await crypto.createCipher(‘AES-GCM’);
const encrypted = await cipher.encrypt(content);
return encrypted;
敏感内容检测:
// 检测敏感内容
function containsSensitiveInfo(content: string): boolean {
const patterns = [/\bpassword\b/i, /\bcredit\b/i, /\bcard\b/i];
return patterns.some(pattern => pattern.test(content));
设备白名单控制:
// 设备白名单检查
function isAllowedDevice(deviceId: string): boolean {
const allowedDevices = AppStorage.get(‘allowedDevices’) || [];
return allowedDevices.includes(deviceId);
总结
本文展示了如何利用HarmonyOS的分布式能力构建一个跨设备剪贴板同步系统。通过监听本地剪贴板变化并将内容同步到分布式数据库,实现了在多设备间无缝共享剪贴板内容的功能。
该方案不仅支持文本内容,还可以扩展支持图片、链接等多种类型。通过合理的安全控制措施,可以在提供便利的同时保护用户隐私和数据安全。这种架构可以广泛应用于多设备协同工作场景,大幅提升工作效率。
