鸿蒙开发之:多端协同与流转
鸿蒙操作系统的核心特性之一就是分布式能力,它通过分布式软总线技术,让多个设备能够像使用一个设备一样协同工作。多端协同允许应用在不同设备间无缝流转,数据在多设备间同步共享。分布式基础:设备发现、连接和管理应用流转:跨设备无缝接续应用体验数据同步:分布式数据存储和实时同步硬件共享:摄像头、文件等硬件能力共享安全机制:多端协同的安全认证和加密实战应用:多端协同阅读、待办等完整应用。
本文字数:约3500字 | 预计阅读时间:14分钟
前置知识:建议先学习本系列前七篇,特别是服务卡片开发
实战价值:掌握多端协同技术,打造全场景智慧体验
系列导航:本文是《鸿蒙开发系列》第8篇,下篇将讲解性能优化与调试技巧
一、多端协同概述:鸿蒙的分布式能力
鸿蒙操作系统的核心特性之一就是分布式能力,它通过分布式软总线技术,让多个设备能够像使用一个设备一样协同工作。多端协同允许应用在不同设备间无缝流转,数据在多设备间同步共享。
1.1 多端协同的核心特性
-
设备虚拟化:多个设备虚拟为一个超级终端
-
能力互助:设备间共享硬件和软件能力
-
数据流转:应用和数据在设备间无缝迁移
-
分布式安全:端到端的安全保障
1.2 典型应用场景
| 场景 | 描述 | 示例 |
|---|---|---|
| 应用接续 | 应用从一个设备迁移到另一个设备 | 手机上看的视频流转到平板上继续观看 |
| 跨屏协同 | 多个设备屏幕协同显示 | 手机作为平板的手写板或控制器 |
| 硬件共享 | 共享其他设备的硬件能力 | 使用平板的摄像头进行视频通话 |
| 数据同步 | 数据在多设备间实时同步 | 笔记、日历、联系人实时同步 |
二、分布式软总线基础
2.1 设备发现与连接
typescript
// ets/utils/DistributedDeviceManager.ts
import deviceManager from '@ohos.distributedDeviceManager';
class DistributedDeviceManager {
private deviceList: Array<deviceManager.DeviceBasicInfo> = [];
private discoverCallback: ((devices: Array<deviceManager.DeviceBasicInfo>) => void) | null = null;
// 初始化设备管理
async initialize() {
try {
// 创建设备管理器
const deviceManager = await deviceManager.createDeviceManager('com.example.app');
console.log('设备管理器创建成功');
// 注册设备状态监听
deviceManager.on('deviceStateChange', (data) => {
this.handleDeviceStateChange(data);
});
return true;
} catch (error) {
console.error('设备管理器初始化失败:', error);
return false;
}
}
// 开始发现设备
startDiscovery() {
try {
deviceManager.startDeviceDiscovery({
mode: deviceManager.DiscoveryMode.ACTIVE,
medium: deviceManager.ExchangeMedium.AUTO,
freq: deviceManager.ExchangeFreq.HIGH
});
deviceManager.on('deviceFound', (data) => {
this.handleDeviceFound(data);
});
console.log('开始设备发现');
} catch (error) {
console.error('设备发现失败:', error);
}
}
// 停止发现设备
stopDiscovery() {
try {
deviceManager.stopDeviceDiscovery();
console.log('停止设备发现');
} catch (error) {
console.error('停止设备发现失败:', error);
}
}
// 处理设备发现
private handleDeviceFound(data: deviceManager.DeviceBasicInfo) {
// 检查是否已存在
const exists = this.deviceList.some(device => device.deviceId === data.deviceId);
if (!exists) {
this.deviceList.push(data);
console.log('发现新设备:', data.deviceName);
// 通知监听者
if (this.discoverCallback) {
this.discoverCallback(this.deviceList);
}
}
}
// 处理设备状态变化
private handleDeviceStateChange(data: { deviceId: string, deviceState: number }) {
const device = this.deviceList.find(d => d.deviceId === data.deviceId);
if (device) {
if (data.deviceState === deviceManager.DeviceState.OFFLINE) {
// 设备离线
this.deviceList = this.deviceList.filter(d => d.deviceId !== data.deviceId);
console.log('设备离线:', device.deviceName);
} else if (data.deviceState === deviceManager.DeviceState.ONLINE) {
console.log('设备在线:', device.deviceName);
}
// 通知监听者
if (this.discoverCallback) {
this.discoverCallback(this.deviceList);
}
}
}
// 设置设备发现回调
setDiscoverCallback(callback: (devices: Array<deviceManager.DeviceBasicInfo>) => void) {
this.discoverCallback = callback;
}
// 获取设备列表
getDevices(): Array<deviceManager.DeviceBasicInfo> {
return [...this.deviceList];
}
// 连接设备
async connectDevice(deviceId: string): Promise<boolean> {
try {
await deviceManager.authenticateDevice(deviceId, {
authType: deviceManager.AuthType.PIN,
token: '123456' // 实际使用时需要更安全的认证方式
});
console.log('设备连接成功:', deviceId);
return true;
} catch (error) {
console.error('设备连接失败:', error);
return false;
}
}
}
export default new DistributedDeviceManager();
2.2 设备信息获取
typescript
// ets/utils/DeviceInfoUtil.ts
import deviceInfo from '@ohos.deviceInfo';
class DeviceInfoUtil {
// 获取设备基本信息
static getDeviceInfo() {
return {
deviceId: deviceInfo.deviceId,
deviceType: deviceInfo.deviceType,
deviceName: deviceInfo.deviceName,
manufacturer: deviceInfo.manufacturer,
brand: deviceInfo.brand,
marketName: deviceInfo.marketName,
productSeries: deviceInfo.productSeries,
productModel: deviceInfo.productModel,
softwareModel: deviceInfo.softwareModel,
hardwareModel: deviceInfo.hardwareModel,
hardwareProfile: deviceInfo.hardwareProfile,
bootloaderVersion: deviceInfo.bootloaderVersion,
abiList: deviceInfo.abiList,
securityPatchTag: deviceInfo.securityPatchTag,
displayVersion: deviceInfo.displayVersion,
incrementalVersion: deviceInfo.incrementalVersion,
osReleaseType: deviceInfo.osReleaseType,
osFullName: deviceInfo.osFullName,
majorVersion: deviceInfo.majorVersion,
seniorVersion: deviceInfo.seniorVersion,
featureVersion: deviceInfo.featureVersion,
buildVersion: deviceInfo.buildVersion,
sdkApiVersion: deviceInfo.sdkApiVersion,
firstApiVersion: deviceInfo.firstApiVersion
};
}
// 获取设备能力信息
static getDeviceCapabilities() {
return {
// 屏幕信息
screen: {
width: window.innerWidth,
height: window.innerHeight,
density: window.devicePixelRatio
},
// 设备类型
type: this.getDeviceType(),
// 支持的功能
capabilities: {
camera: this.hasCapability('camera'),
microphone: this.hasCapability('microphone'),
gps: this.hasCapability('gps'),
nfc: this.hasCapability('nfc'),
bluetooth: this.hasCapability('bluetooth'),
wifi: this.hasCapability('wifi')
}
};
}
// 判断设备类型
private static getDeviceType(): string {
const deviceType = deviceInfo.deviceType;
switch (deviceType) {
case 'phone': return '手机';
case 'tablet': return '平板';
case 'tv': return '电视';
case 'wearable': return '穿戴设备';
case 'car': return '车机';
default: return '未知设备';
}
}
// 检查设备能力
private static hasCapability(capability: string): boolean {
// 这里根据设备类型和能力进行判断
const deviceType = deviceInfo.deviceType;
switch (capability) {
case 'camera':
return deviceType !== 'wearable'; // 穿戴设备可能没有摄像头
case 'microphone':
return deviceType !== 'wearable';
case 'gps':
return deviceType === 'phone' || deviceType === 'tablet';
default:
return true;
}
}
}
export default DeviceInfoUtil;
三、应用流转:跨设备无缝体验
3.1 流转能力配置
json
// module.json5
{
"module": {
"name": "entry",
"type": "entry",
"continuable": true, // 启用流转能力
"abilities": [
{
"name": "MainAbility",
"srcEntry": "./ets/entryability/MainAbility.ts",
"description": "$string:mainability_description",
"icon": "$media:icon",
"label": "$string:entry_MainAbility",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"actions": [
"action.system.home"
],
"entities": [
"entity.system.home"
]
}
],
"continuationFilter": {
"deviceTypes": ["phone", "tablet", "tv"], // 支持的设备类型
"abilityTypes": ["page"],
"bundleName": "com.example.multideviceapp",
"supportDimensions": ["1*2", "2*2", "2*4", "4*4"]
}
}
]
}
}
3.2 流转管理器
typescript
// ets/utils/ContinuationManager.ts
import continuation from '@ohos.continuation.continuationManager';
class ContinuationManager {
private continuationToken: number = 0;
private deviceList: Array<any> = [];
// 注册流转能力
async registerContinuation() {
try {
this.continuationToken = await continuation.registerContinuation({
deviceType: ['phone', 'tablet', 'tv'],
abilityType: ['page'],
bundleName: 'com.example.multideviceapp'
});
console.log('流转能力注册成功, token:', this.continuationToken);
return true;
} catch (error) {
console.error('流转能力注册失败:', error);
return false;
}
}
// 显示设备选择器
async showDevicePicker(): Promise<string | null> {
try {
const extraParams = {
title: '选择流转设备',
deviceType: ['phone', 'tablet'],
filter: 'online'
};
const result = await continuation.startDeviceSelection(this.continuationToken, extraParams);
if (result && result.length > 0) {
return result[0]; // 返回选择的设备ID
}
return null;
} catch (error) {
console.error('设备选择失败:', error);
return null;
}
}
// 更新流转状态
updateContinuationState(state: continuation.ContinuationState) {
try {
continuation.updateContinuationState(this.continuationToken, state);
} catch (error) {
console.error('更新流转状态失败:', error);
}
}
// 取消流转
unregisterContinuation() {
if (this.continuationToken > 0) {
try {
continuation.unregisterContinuation(this.continuationToken);
console.log('流转能力取消注册');
} catch (error) {
console.error('取消流转注册失败:', error);
}
}
}
// 获取流转数据
saveContinuationData(): any {
// 保存需要流转的数据
return {
timestamp: Date.now(),
pageData: this.getCurrentPageData(),
userState: this.getUserState()
};
}
// 恢复流转数据
restoreContinuationData(data: any) {
// 恢复流转的数据
if (data && data.pageData) {
this.restorePageData(data.pageData);
}
}
private getCurrentPageData(): any {
// 获取当前页面数据
return {
pageIndex: 0,
scrollPosition: 0,
formData: {}
};
}
private getUserState(): any {
// 获取用户状态
return {
userId: 'user123',
preferences: {}
};
}
private restorePageData(data: any) {
// 恢复页面数据
console.log('恢复页面数据:', data);
}
}
export default new ContinuationManager();
3.3 流转页面实现
typescript
// ets/pages/MainPage.ets
@Entry
@Component
struct MainPage {
@State currentVideo: { id: string, title: string, url: string, progress: number } = {
id: 'video001',
title: '鸿蒙开发教程',
url: 'https://example.com/video.mp4',
progress: 0.35
};
@State connectedDevices: Array<{id: string, name: string, type: string}> = [];
@State isPlaying: boolean = false;
private continuationManager = ContinuationManager;
aboutToAppear() {
// 注册流转能力
this.continuationManager.registerContinuation();
// 监听设备连接
DistributedDeviceManager.setDiscoverCallback((devices) => {
this.connectedDevices = devices.map(device => ({
id: device.deviceId,
name: device.deviceName,
type: this.getDeviceTypeName(device.deviceType)
}));
});
}
aboutToDisappear() {
// 取消流转注册
this.continuationManager.unregisterContinuation();
}
build() {
Column({ space: 20 }) {
// 视频播放器
Column({ space: 12 }) {
Text(this.currentVideo.title)
.fontSize(20)
.fontWeight(FontWeight.Bold)
// 视频播放区域
Column()
.width('100%')
.height(200)
.backgroundColor('#000000')
.justifyContent(FlexAlign.Center) {
Row() {
if (this.isPlaying) {
Image($r('app.media.pause'))
.width(48)
.height(48)
.onClick(() => {
this.isPlaying = false;
})
} else {
Image($r('app.media.play'))
.width(48)
.height(48)
.onClick(() => {
this.isPlaying = true;
})
}
}
}
// 进度条
Column() {
Row()
.width(`${this.currentVideo.progress * 100}%`)
.height(4)
.backgroundColor('#007DFF')
}
.width('100%')
.height(4)
.backgroundColor('#EEEEEE')
// 播放时间
Row() {
Text('12:30')
.fontSize(12)
.fontColor('#666666')
Blank()
Text('35:45')
.fontSize(12)
.fontColor('#666666')
}
.width('100%')
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(16)
.shadow({ radius: 8, color: '#00000010' })
// 流转控制
Column({ space: 12 }) {
Text('流转到其他设备')
.fontSize(16)
.fontWeight(FontWeight.Medium)
if (this.connectedDevices.length === 0) {
Text('未发现可用设备')
.fontSize(14)
.fontColor('#999999')
} else {
Column({ space: 8 }) {
ForEach(this.connectedDevices, (device) => {
Row({ space: 12 }) {
Image(this.getDeviceIcon(device.type))
.width(24)
.height(24)
Column({ space: 4 }) {
Text(device.name)
.fontSize(14)
.fontColor('#333333')
Text(device.type)
.fontSize(12)
.fontColor('#666666')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Button('流转')
.width(80)
.height(32)
.fontSize(12)
.onClick(() => {
this.transferToDevice(device.id);
})
}
.padding(12)
.backgroundColor('#F8F8F8')
.borderRadius(12)
})
}
}
Button('发现更多设备')
.width('100%')
.height(40)
.fontSize(14)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.onClick(() => {
this.discoverDevices();
})
}
.padding(20)
.backgroundColor(Color.White)
.borderRadius(16)
.shadow({ radius: 8, color: '#00000010' })
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
}
// 流转到指定设备
async transferToDevice(deviceId: string) {
// 保存当前状态
const continuationData = {
video: this.currentVideo,
isPlaying: this.isPlaying,
progress: this.currentVideo.progress,
timestamp: Date.now()
};
// 开始流转
const selectedDeviceId = await this.continuationManager.showDevicePicker();
if (selectedDeviceId) {
console.log('开始流转到设备:', selectedDeviceId);
// 更新流转状态
this.continuationManager.updateContinuationState('started');
// 这里实际会触发系统流转流程
// 流转成功后,应用会在目标设备上恢复
}
}
// 发现设备
discoverDevices() {
DistributedDeviceManager.startDiscovery();
}
// 获取设备图标
getDeviceIcon(type: string): Resource {
switch (type) {
case '手机': return $r('app.media.phone');
case '平板': return $r('app.media.tablet');
case '电视': return $r('app.media.tv');
case '穿戴设备': return $r('app.media.watch');
default: return $r('app.media.device');
}
}
// 获取设备类型名称
getDeviceTypeName(deviceType: number): string {
switch (deviceType) {
case 0: return '手机';
case 1: return '平板';
case 3: return '电视';
case 4: return '穿戴设备';
case 5: return '车机';
default: return '未知设备';
}
}
}
四、分布式数据管理
4.1 分布式数据存储
typescript
// ets/utils/DistributedDataManager.ts
import distributedData from '@ohos.data.distributedData';
class DistributedDataManager {
private kvManager: distributedData.KVManager | null = null;
private kvStore: distributedData.KVStore | null = null;
private storeId: string = 'multidevice_data_store';
// 初始化分布式KV存储
async initialize() {
try {
// 创建KVManager配置
const config: distributedData.KVManagerConfig = {
bundleName: 'com.example.multideviceapp',
userInfo: {
userId: 'globalUser',
userType: distributedData.UserType.SAME_USER_ID
},
context: getContext(this)
};
// 创建KVManager
this.kvManager = distributedData.createKVManager(config);
// 创建KVStore配置
const options: distributedData.Options = {
createIfMissing: true,
encrypt: true,
backup: false,
autoSync: true,
kvStoreType: distributedData.KVStoreType.DEVICE_COLLABORATION,
securityLevel: distributedData.SecurityLevel.S2
};
// 创建KVStore
this.kvStore = await this.kvManager.getKVStore(this.storeId, options);
console.log('分布式数据存储初始化成功');
return true;
} catch (error) {
console.error('分布式数据存储初始化失败:', error);
return false;
}
}
// 保存数据
async save(key: string, value: any): Promise<boolean> {
if (!this.kvStore) return false;
try {
await this.kvStore.put(key, JSON.stringify(value));
return true;
} catch (error) {
console.error('保存数据失败:', error);
return false;
}
}
// 获取数据
async get<T = any>(key: string): Promise<T | null> {
if (!this.kvStore) return null;
try {
const value = await this.kvStore.get(key);
if (value) {
return JSON.parse(value.toString()) as T;
}
return null;
} catch (error) {
console.error('获取数据失败:', error);
return null;
}
}
// 删除数据
async delete(key: string): Promise<boolean> {
if (!this.kvStore) return false;
try {
await this.kvStore.delete(key);
return true;
} catch (error) {
console.error('删除数据失败:', error);
return false;
}
}
// 同步数据到其他设备
async sync(deviceIds?: Array<string>): Promise<boolean> {
if (!this.kvStore) return false;
try {
const mode = distributedData.SyncMode.PULL_ONLY;
const delay = 0; // 立即同步
if (deviceIds && deviceIds.length > 0) {
// 同步到指定设备
await this.kvStore.sync(deviceIds, mode, delay);
} else {
// 同步到所有设备
await this.kvStore.sync(mode, delay);
}
return true;
} catch (error) {
console.error('数据同步失败:', error);
return false;
}
}
// 监听数据变化
onDataChange(callback: (data: { key: string, value: any, deviceId: string }) => void) {
if (!this.kvStore) return;
this.kvStore.on('dataChange', (data) => {
const changeData = data as distributedData.ChangeNotification;
changeData.insertEntries.forEach(entry => {
try {
const value = JSON.parse(entry.value.toString());
callback({
key: entry.key,
value: value,
deviceId: changeData.deviceId
});
} catch (error) {
console.error('解析变更数据失败:', error);
}
});
});
}
}
export default new DistributedDataManager();
4.2 分布式数据同步示例
typescript
// ets/pages/CollaborationPage.ets
@Entry
@Component
struct CollaborationPage {
@State todoList: Array<{ id: string, text: string, completed: boolean, device: string }> = [];
@State newTodoText: string = '';
@State connectedDevices: Array<string> = [];
private distributedDataManager = DistributedDataManager;
private deviceId: string = '';
async aboutToAppear() {
// 初始化分布式数据
await this.distributedDataManager.initialize();
// 获取设备ID
this.deviceId = DeviceInfoUtil.getDeviceInfo().deviceId;
// 监听数据变化
this.distributedDataManager.onDataChange((data) => {
this.handleDataChange(data);
});
// 加载数据
await this.loadTodoList();
}
async loadTodoList() {
const savedList = await this.distributedDataManager.get<Array<any>>('todo_list');
if (savedList) {
this.todoList = savedList;
}
}
handleDataChange(data: { key: string, value: any, deviceId: string }) {
if (data.key === 'todo_list') {
this.todoList = data.value;
console.log(`数据从设备 ${data.deviceId} 同步`);
}
}
async addTodo() {
if (!this.newTodoText.trim()) return;
const newTodo = {
id: Date.now().toString(),
text: this.newTodoText,
completed: false,
device: this.deviceId,
timestamp: Date.now()
};
this.todoList = [...this.todoList, newTodo];
this.newTodoText = '';
// 保存到分布式存储
await this.distributedDataManager.save('todo_list', this.todoList);
// 同步到其他设备
await this.distributedDataManager.sync();
}
async toggleTodo(id: string) {
this.todoList = this.todoList.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
);
// 保存并同步
await this.distributedDataManager.save('todo_list', this.todoList);
await this.distributedDataManager.sync();
}
async deleteTodo(id: string) {
this.todoList = this.todoList.filter(todo => todo.id !== id);
// 保存并同步
await this.distributedDataManager.save('todo_list', this.todoList);
await this.distributedDataManager.sync();
}
build() {
Column({ space: 20 }) {
Text('协同待办')
.fontSize(24)
.fontWeight(FontWeight.Bold)
// 添加待办
Row({ space: 12 }) {
TextInput({ placeholder: '添加新待办...' })
.width('70%')
.height(48)
.value(this.newTodoText)
.onChange((value: string) => {
this.newTodoText = value;
})
Button('添加')
.width('30%')
.height(48)
.fontSize(14)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.onClick(() => {
this.addTodo();
})
}
.width('100%')
// 待办列表
List({ space: 12 }) {
ForEach(this.todoList, (todo) => {
ListItem() {
Row({ space: 12 }) {
// 完成状态
Column()
.width(20)
.height(20)
.border({ width: 2, color: todo.completed ? '#34C759' : '#CCCCCC' })
.borderRadius(10)
.backgroundColor(todo.completed ? '#34C759' : 'transparent')
.onClick(() => {
this.toggleTodo(todo.id);
})
// 待办文本
Text(todo.text)
.fontSize(16)
.fontColor(todo.completed ? '#999999' : '#333333')
.textDecoration(todo.completed ? { type: TextDecorationType.LineThrough } : null)
.layoutWeight(1)
// 设备标识
Text(todo.device === this.deviceId ? '本机' : '其他设备')
.fontSize(12)
.fontColor('#666666')
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.backgroundColor('#F0F0F0')
.borderRadius(12)
// 删除按钮
Image($r('app.media.delete'))
.width(20)
.height(20)
.onClick(() => {
this.deleteTodo(todo.id);
})
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
.shadow({ radius: 4, color: '#00000010' })
}
})
}
.layoutWeight(1)
// 同步控制
Row({ space: 12 }) {
Button('手动同步')
.width('50%')
.height(48)
.fontSize(14)
.backgroundColor('#34C759')
.fontColor(Color.White)
.onClick(() => {
this.distributedDataManager.sync();
})
Button('清空列表')
.width('50%')
.height(48)
.fontSize(14)
.backgroundColor('#FF3B30')
.fontColor(Color.White)
.onClick(async () => {
this.todoList = [];
await this.distributedDataManager.save('todo_list', []);
await this.distributedDataManager.sync();
})
}
.width('100%')
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('#F5F5F5')
}
}
五、硬件能力共享
5.1 摄像头共享
typescript
// ets/utils/CameraSharingManager.ts
import camera from '@ohos.multimedia.camera';
import image from '@ohos.multimedia.image';
class CameraSharingManager {
private cameraManager: camera.CameraManager | null = null;
private cameraInput: camera.CameraInput | null = null;
private previewOutput: camera.PreviewOutput | null = null;
private photoOutput: camera.PhotoOutput | null = null;
// 初始化摄像头
async initialize() {
try {
this.cameraManager = camera.getCameraManager(getContext(this));
// 获取摄像头列表
const cameras = this.cameraManager.getSupportedCameras();
if (cameras.length === 0) {
throw new Error('没有可用的摄像头');
}
// 使用第一个摄像头
const cameraDevice = cameras[0];
// 创建相机输入
this.cameraInput = this.cameraManager.createCameraInput(cameraDevice);
await this.cameraInput.open();
// 创建预览输出
const surfaceId = await this.createPreviewSurface();
this.previewOutput = this.cameraManager.createPreviewOutput(surfaceId);
// 创建拍照输出
this.photoOutput = this.cameraManager.createPhotoOutput();
// 创建会话
const session = this.cameraManager.createCaptureSession();
// 配置会话
session.beginConfig();
session.addInput(this.cameraInput);
session.addOutput(this.previewOutput);
session.addOutput(this.photoOutput);
await session.commitConfig();
// 启动会话
await session.start();
console.log('摄像头初始化成功');
return true;
} catch (error) {
console.error('摄像头初始化失败:', error);
return false;
}
}
// 创建预览表面
private async createPreviewSurface(): Promise<string> {
// 这里需要创建XComponent来显示预览
return 'preview_surface';
}
// 拍照
async takePhoto(): Promise<image.PixelMap | null> {
if (!this.photoOutput) return null;
try {
const photoSettings = {
rotation: camera.ImageRotation.ROTATION_0,
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,
location: { latitude: 0, longitude: 0, altitude: 0 }
};
await this.photoOutput.capture(photoSettings);
// 获取照片数据
const photo = await this.photoOutput.getLatestPhoto();
const imageData = await photo.main.getComponent(image.ComponentType.JPEG);
return imageData;
} catch (error) {
console.error('拍照失败:', error);
return null;
}
}
// 共享摄像头到其他设备
async shareCameraToDevice(deviceId: string): Promise<boolean> {
try {
// 这里需要实现摄像头流的编码和传输
console.log('共享摄像头到设备:', deviceId);
return true;
} catch (error) {
console.error('共享摄像头失败:', error);
return false;
}
}
// 释放资源
async release() {
if (this.cameraInput) {
await this.cameraInput.close();
}
if (this.cameraManager) {
// 停止会话并释放资源
}
}
}
export default new CameraSharingManager();
5.2 文件共享
typescript
// ets/utils/FileSharingManager.ts
import fileIo from '@ohos.fileio';
import fs from '@ohos.file.fs';
class FileSharingManager {
// 发送文件到其他设备
async sendFileToDevice(filePath: string, deviceId: string): Promise<boolean> {
try {
// 读取文件内容
const file = await fileIo.open(filePath, fileIo.OpenMode.READ_ONLY);
const stat = await fileIo.stat(filePath);
const buffer = new ArrayBuffer(stat.size);
await fileIo.read(file.fd, buffer);
await fileIo.close(file.fd);
// 这里需要实现文件传输逻辑
// 实际开发中会使用分布式文件系统或网络传输
console.log(`发送文件 ${filePath} 到设备 ${deviceId}, 大小: ${stat.size} 字节`);
return true;
} catch (error) {
console.error('发送文件失败:', error);
return false;
}
}
// 从其他设备接收文件
async receiveFileFromDevice(deviceId: string, fileName: string, fileData: ArrayBuffer): Promise<string | null> {
try {
const savePath = `${getContext(this).filesDir}/${fileName}`;
const file = await fileIo.open(savePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
await fileIo.write(file.fd, fileData);
await fileIo.close(file.fd);
console.log(`从设备 ${deviceId} 接收文件 ${fileName}, 保存到: ${savePath}`);
return savePath;
} catch (error) {
console.error('接收文件失败:', error);
return null;
}
}
// 获取共享文件列表
async getSharedFiles(deviceId: string): Promise<Array<string>> {
try {
// 这里需要从分布式存储获取文件列表
return ['document.pdf', 'photo.jpg', 'video.mp4'];
} catch (error) {
console.error('获取共享文件列表失败:', error);
return [];
}
}
}
export default new FileSharingManager();
六、多端协同安全
6.1 安全认证管理
typescript
// ets/utils/SecurityManager.ts
import userIAM from '@ohos.userIAM.userAuth';
class SecurityManager {
// 设备认证
async authenticateDevice(deviceId: string): Promise<boolean> {
try {
// 这里使用PIN码认证(实际应用应使用更安全的认证方式)
const result = await userIAM.authenticate({
challenge: deviceId,
authType: userIAM.AuthType.PIN,
authTrustLevel: userIAM.AuthTrustLevel.ATL3
});
return result === userIAM.ResultCode.SUCCESS;
} catch (error) {
console.error('设备认证失败:', error);
return false;
}
}
// 数据加密
encryptData(data: string, key: string): string {
// 这里实现数据加密逻辑
// 实际开发中应使用鸿蒙的安全加密框架
return btoa(data); // 简单示例,实际应用需要更安全的加密
}
// 数据解密
decryptData(encryptedData: string, key: string): string {
// 这里实现数据解密逻辑
return atob(encryptedData);
}
// 权限检查
checkPermission(permission: string): Promise<boolean> {
return new Promise((resolve) => {
// 检查应用权限
// 实际开发中应使用鸿蒙的权限管理API
resolve(true);
});
}
}
export default new SecurityManager();
七、实战:多端协同阅读应用
typescript
// ets/pages/ReadingApp.ets
@Entry
@Component
struct ReadingApp {
@State currentBook: { id: string, title: string, content: string, progress: number } | null = null;
@State connectedDevices: Array<{id: string, name: string}> = [];
@State readingPosition: number = 0;
@State fontSize: number = 16;
@State theme: 'light' | 'dark' = 'light';
private distributedDataManager = DistributedDataManager;
private continuationManager = ContinuationManager;
async aboutToAppear() {
// 初始化分布式数据
await this.distributedDataManager.initialize();
// 加载阅读进度
await this.loadReadingProgress();
// 监听数据同步
this.distributedDataManager.onDataChange((data) => {
if (data.key === 'reading_progress') {
this.handleProgressSync(data.value);
}
});
}
async loadReadingProgress() {
const progress = await this.distributedDataManager.get<any>('reading_progress');
if (progress) {
this.readingPosition = progress.position || 0;
this.fontSize = progress.fontSize || 16;
this.theme = progress.theme || 'light';
}
}
handleProgressSync(progress: any) {
if (progress && progress.position !== undefined) {
this.readingPosition = progress.position;
console.log('阅读进度已从其他设备同步');
}
}
async saveProgress() {
const progress = {
bookId: this.currentBook?.id,
position: this.readingPosition,
fontSize: this.fontSize,
theme: this.theme,
timestamp: Date.now(),
deviceId: DeviceInfoUtil.getDeviceInfo().deviceId
};
await this.distributedDataManager.save('reading_progress', progress);
await this.distributedDataManager.sync();
}
async transferReading(deviceId: string) {
if (!this.currentBook) return;
// 保存当前进度
await this.saveProgress();
// 开始流转
const selectedDeviceId = await this.continuationManager.showDevicePicker();
if (selectedDeviceId) {
console.log('流转阅读到设备:', selectedDeviceId);
// 这里实际会触发应用流转
// 流转后,目标设备会打开阅读应用并恢复进度
}
}
build() {
Column({ space: 20 }) {
// 顶部工具栏
Row({ space: 12 }) {
Text(this.currentBook?.title || '选择一本书')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Button('流转')
.width(80)
.height(36)
.fontSize(12)
.onClick(() => {
this.showDeviceSelector();
})
}
.width('100%')
.padding(16)
.backgroundColor(this.theme === 'dark' ? '#333333' : '#FFFFFF')
// 阅读区域
Scroll() {
Column({ space: 20 }) {
Text(this.currentBook?.content || '暂无内容')
.fontSize(this.fontSize)
.fontColor(this.theme === 'dark' ? '#FFFFFF' : '#333333')
.lineHeight(this.fontSize * 1.6)
}
.padding(20)
}
.onScroll((event: { scrollOffset: number }) => {
this.readingPosition = event.scrollOffset;
// 自动保存进度(防抖处理)
this.debouncedSave();
})
.layoutWeight(1)
.backgroundColor(this.theme === 'dark' ? '#1A1A1A' : '#F8F8F8')
// 底部控制栏
Row({ space: 20 }) {
// 字体大小控制
Row({ space: 8 }) {
Button('A-')
.width(40)
.height(40)
.fontSize(16)
.onClick(() => {
if (this.fontSize > 12) {
this.fontSize--;
this.saveProgress();
}
})
Text(`${this.fontSize}`)
.width(40)
.textAlign(TextAlign.Center)
.fontColor(this.theme === 'dark' ? '#FFFFFF' : '#333333')
Button('A+')
.width(40)
.height(40)
.fontSize(16)
.onClick(() => {
if (this.fontSize < 24) {
this.fontSize++;
this.saveProgress();
}
})
}
// 主题切换
Button(this.theme === 'light' ? '🌙' : '☀️')
.width(40)
.height(40)
.fontSize(16)
.onClick(() => {
this.theme = this.theme === 'light' ? 'dark' : 'light';
this.saveProgress();
})
// 进度显示
Text(`${Math.floor(this.readingPosition)}`)
.fontSize(14)
.fontColor(this.theme === 'dark' ? '#FFFFFF' : '#333333')
.layoutWeight(1)
.textAlign(TextAlign.End)
}
.width('100%')
.padding(16)
.backgroundColor(this.theme === 'dark' ? '#333333' : '#FFFFFF')
}
.width('100%')
.height('100%')
.backgroundColor(this.theme === 'dark' ? '#000000' : '#F5F5F5')
}
private showDeviceSelector() {
// 显示设备选择器
this.continuationManager.showDevicePicker().then(deviceId => {
if (deviceId) {
this.transferReading(deviceId);
}
});
}
private debouncedSave = this.debounce(() => {
this.saveProgress();
}, 1000);
private debounce(func: Function, delay: number) {
let timer: number | null = null;
return function(this: any, ...args: any[]) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
}
八、调试与优化
8.1 多端协同调试
typescript
// ets/utils/DistributedDebugger.ts
class DistributedDebugger {
static enableDebugLog() {
console.info('分布式调试模式已启用');
// 监听所有分布式事件
this.listenToDistributedEvents();
// 显示调试面板
this.showDebugPanel();
}
private static listenToDistributedEvents() {
// 这里可以监听各种分布式事件
console.log('开始监听分布式事件...');
}
private static showDebugPanel() {
// 在界面上显示调试信息
const debugInfo = {
deviceId: DeviceInfoUtil.getDeviceInfo().deviceId,
connectedDevices: [],
dataSyncStatus: '正常',
networkStatus: '在线'
};
console.table(debugInfo);
}
static logDataSync(data: any) {
console.group('数据同步日志');
console.log('时间:', new Date().toLocaleString());
console.log('数据:', data);
console.groupEnd();
}
}
8.2 性能监控
typescript
class DistributedPerformanceMonitor {
private metrics: Map<string, Array<number>> = new Map();
// 测量流转时间
static measureTransferTime(startTime: number) {
const duration = performance.now() - startTime;
console.log(`流转耗时: ${duration.toFixed(2)}ms`);
// 记录性能指标
this.recordMetric('transfer_time', duration);
}
// 测量数据同步时间
static measureSyncTime(dataSize: number, startTime: number) {
const duration = performance.now() - startTime;
const speed = dataSize / (duration / 1000); // bytes per second
console.log(`数据同步: ${dataSize} bytes, 耗时: ${duration.toFixed(2)}ms, 速度: ${(speed / 1024).toFixed(2)} KB/s`);
this.recordMetric('sync_speed', speed);
}
private static recordMetric(name: string, value: number) {
let metrics = this.metrics.get(name) || [];
metrics.push(value);
// 只保留最近的100个记录
if (metrics.length > 100) {
metrics = metrics.slice(-100);
}
this.metrics.set(name, metrics);
}
static getPerformanceReport() {
const report: any = {};
this.metrics.forEach((values, name) => {
if (values.length > 0) {
const sum = values.reduce((a, b) => a + b, 0);
const avg = sum / values.length;
const max = Math.max(...values);
const min = Math.min(...values);
report[name] = {
count: values.length,
average: avg,
max: max,
min: min,
latest: values[values.length - 1]
};
}
});
return report;
}
}
九、总结与下期预告
9.1 本文要点回顾
-
分布式基础:设备发现、连接和管理
-
应用流转:跨设备无缝接续应用体验
-
数据同步:分布式数据存储和实时同步
-
硬件共享:摄像头、文件等硬件能力共享
-
安全机制:多端协同的安全认证和加密
-
实战应用:多端协同阅读、待办等完整应用
9.2 下期预告:《鸿蒙开发之:性能优化与调试技巧》
下篇文章将深入讲解:
-
应用性能分析与监控
-
内存管理和优化
-
渲染性能优化
-
网络请求优化
-
启动速度优化
-
调试工具和技巧
动手挑战
任务1:实现多端协同画板
要求:
-
支持多设备同时绘画
-
实时同步绘画内容
-
支持不同颜色和画笔大小
-
保存和加载绘画作品
任务2:实现多端协同游戏
要求:
-
支持多设备联机游戏
-
实时同步游戏状态
-
支持语音聊天
-
游戏进度云端同步
任务3:实现智能家居控制中心
要求:
-
统一控制多设备家居
-
设备状态实时同步
-
支持场景模式
-
远程控制和自动化
将你的代码分享到评论区,我会挑选优秀实现进行详细点评!
常见问题解答
Q:多端协同需要设备都在同一个网络吗?
A:通常需要在同一局域网,但鸿蒙也支持远程协同(需要通过华为账号等机制)。
Q:流转应用时数据会同步传输吗?
A:流转时只传输应用状态数据,大文件数据可以通过分布式数据框架同步。
Q:如何保证多端协同的安全性?
A:鸿蒙提供了端到端的加密通信、设备认证、权限控制等多层安全机制。
Q:多端协同对设备性能要求高吗?
A:基础的数据同步对性能要求不高,但视频流转等实时性要求高的场景需要较好的网络和设备性能。
PS:现在HarmonyOS应用开发者认证正在做活动,初级和高级都可以免费学习及考试,赶快加入班级学习啦:【注意,考试只能从此唯一链接进入】
https://developer.huawei.com/consumer/cn/training/classDetail/33f85412dc974764831435dc1c03427c?type=1?ha_source=hmosclass&ha_sourceld=89000248
版权声明:本文为《鸿蒙开发系列》第8篇,原创文章,转载请注明出处。
标签:#HarmonyOS #鸿蒙开发 #多端协同 #分布式 #应用流转 #华为开发者
更多推荐




所有评论(0)