HarmonyOS APP开发之Continuation开发

举报
Jack20 发表于 2026/06/19 23:24:24 2026/06/19
【摘要】 小知识前面两篇文章聊的都是Ability迁移,但HarmonyOS的分布式能力不止于此。Continuation(继续能力)是一个更灵活、更轻量的跨设备流转机制。打个比方,Ability迁移像是"搬家"——整个应用打包带走;而Continuation像是"串门"——你可以只带走某个功能模块,或者在不同设备上同时运行同一个应用的不同部分。举个例子:你在手机上看地图导航,想用平板看更大的地图,...

小知识

前面两篇文章聊的都是Ability迁移,但HarmonyOS的分布式能力不止于此。Continuation(继续能力)是一个更灵活、更轻量的跨设备流转机制。

打个比方,Ability迁移像是"搬家"——整个应用打包带走;而Continuation像是"串门"——你可以只带走某个功能模块,或者在不同设备上同时运行同一个应用的不同部分。

举个例子:你在手机上看地图导航,想用平板看更大的地图,但手机上还想继续听语音导航。这种场景下,Ability迁移就不合适了——它会完全把应用"搬走",手机上就没法继续用了。这时候就需要Continuation,它可以让地图界面流转到平板,而语音播报继续在手机上运行。

Continuation的核心思想是"按需流转"——不是全有或全无,而是根据场景选择需要流转的部分。这种灵活性,让分布式体验更加自然。

核心原理

Continuation架构

Continuation基于以下几个核心概念:

  1. ContinuationRegisterManager:注册管理器,负责声明可流转的能力
  2. ContinuationDeviceManager:设备管理器,负责设备发现和选择
  3. ContinuationContext:流转上下文,负责实际的流转操作
  4. ContinuationState:流转状态,追踪流转的进度和结果

Continuation与Ability迁移的区别

特性 Ability迁移 Continuation
流转粒度 整个Ability 可指定的Ability或组件
源设备状态 冻结或销毁 可继续运行
回迁支持 需要显式触发 自动支持
适用场景 完全切换设备 多设备协同
灵活性 较低 较高

Continuation生命周期

// Continuation状态流转
enum ContinuationStage {
    IDLE = 'idle',              // 空闲,未发起流转
    CONNECTING = 'connecting',  // 正在连接目标设备
    TRANSFERRING = 'transferring', // 正在传输数据
    ACTIVE = 'active',         // 流转激活,目标设备运行中
    REVERSING = 'reversing',   // 正在回迁
    DISCONNECTED = 'disconnected' // 已断开
}

代码实战

示例一:基础Continuation注册与流转

这是最基础的Continuation使用示例,展示如何注册流转能力并发起流转。

// ContinuationManager.ets
import continuationManager from '@ohos.continuationManager';
import deviceManager from '@ohos.distributedDeviceManager';
import Want from '@ohos.app.ability.Want';
import common from '@ohos.app.ability.common';

export class ContinuationManager {
    private context: common.UIAbilityContext;
    private continuationManager: continuationManager.ContinuationManager | null = null;
    private deviceManager: deviceManager.DeviceManager | null = null;
    private continuationToken: string = '';
    
    // 流转状态回调
    private onStateChange: ((state: ContinuationStage) => void) | null = null;
    private onDeviceChange: ((devices: DeviceInfo[]) => void) | null = null;

    constructor(context: common.UIAbilityContext) {
        this.context = context;
    }

    // 初始化Continuation管理器
    async initialize(): Promise<void> {
        console.info('[ContinuationManager] Initializing...');
        
        try {
            // 1. 创建设备管理器
            this.deviceManager = deviceManager.createDeviceManager(
                this.context.applicationInfo.name
            );
            
            // 2. 创建Continuation管理器
            this.continuationManager = continuationManager.createContinuationManager(
                this.context.applicationInfo.name
            );
            
            // 3. 注册Continuation能力
            await this.registerContinuation();
            
            // 4. 监听设备变化
            this.setupDeviceListener();
            
            console.info('[ContinuationManager] Initialized successfully');
        } catch (error) {
            console.error('[ContinuationManager] Initialize failed:', error);
            throw error;
        }
    }

    // 注册Continuation能力
    private async registerContinuation(): Promise<void> {
        if (!this.continuationManager) return;
        
        // 定义可流转的Ability信息
        const continuationInfo: continuationManager.ContinuationInfo = {
            deviceType: continuationManager.DeviceType.DEVICE_TYPE_PHONE | 
                        continuationManager.DeviceType.DEVICE_TYPE_TABLET |
                        continuationManager.DeviceType.DEVICE_TYPE_TV,
            // 过滤条件:只流转特定Ability
            filter: {
                bundleName: this.context.applicationInfo.name,
                abilityName: 'MainAbility'
            }
        };
        
        // 注册并获取token
        this.continuationToken = await this.continuationManager.register(continuationInfo);
        
        console.info('[ContinuationManager] Registered, token:', this.continuationToken);
        
        // 监听流转状态变化
        this.continuationManager.on('continuationStateChange', 
            (token: string, deviceId: string, state: continuationManager.ContinuationState) => {
                this.handleStateChange(token, deviceId, state);
            });
    }

    // 设置设备监听
    private setupDeviceListener(): void {
        if (!this.deviceManager) return;
        
        // 监听设备上线
        this.deviceManager.on('deviceStateChange', (data: deviceManager.DeviceInfo) => {
            console.info('[ContinuationManager] Device state changed:', 
                data.deviceName, data.deviceState);
            
            // 刷新设备列表
            this.refreshDeviceList();
        });
        
        // 初始获取设备列表
        this.refreshDeviceList();
    }

    // 刷新设备列表
    private async refreshDeviceList(): Promise<void> {
        if (!this.deviceManager) return;
        
        try {
            const devices = this.deviceManager.getTrustedDeviceListSync();
            
            // 转换为统一的设备信息格式
            const deviceInfos: DeviceInfo[] = devices.map(d => ({
                deviceId: d.deviceId,
                deviceName: d.deviceName,
                deviceType: this.mapDeviceType(d.deviceType),
                isOnline: d.deviceState === deviceManager.DeviceState.ONLINE
            }));
            
            // 通知设备列表更新
            if (this.onDeviceChange) {
                this.onDeviceChange(deviceInfos);
            }
        } catch (error) {
            console.error('[ContinuationManager] Failed to refresh devices:', error);
        }
    }

    // 发起流转
    async startContinuation(targetDeviceId: string): Promise<boolean> {
        console.info('[ContinuationManager] Starting continuation to:', targetDeviceId);
        
        if (!this.continuationManager || !this.continuationToken) {
            console.error('[ContinuationManager] Not initialized');
            return false;
        }
        
        try {
            // 通知状态变化
            this.notifyStateChange(ContinuationStage.CONNECTING);
            
            // 构建流转参数
            const connectOptions: continuationManager.ConnectOptions = {
                deviceId: targetDeviceId,
                // 流转模式:PUSH推送到目标设备
                continuationMode: continuationManager.ContinuationMode.PUSH,
                // 回迁模式:支持自动回迁
                reversible: true
            };
            
            // 发起流转
            await this.continuationManager.connect(this.continuationToken, connectOptions);
            
            console.info('[ContinuationManager] Continuation started');
            this.notifyStateChange(ContinuationStage.TRANSFERRING);
            
            return true;
        } catch (error) {
            console.error('[ContinuationManager] Start continuation failed:', error);
            this.notifyStateChange(ContinuationStage.IDLE);
            return false;
        }
    }

    // 取消流转
    async cancelContinuation(): Promise<void> {
        if (!this.continuationManager || !this.continuationToken) return;
        
        try {
            await this.continuationManager.disconnect(this.continuationToken);
            console.info('[ContinuationManager] Continuation cancelled');
            this.notifyStateChange(ContinuationStage.IDLE);
        } catch (error) {
            console.error('[ContinuationManager] Cancel failed:', error);
        }
    }

    // 处理流转状态变化
    private handleStateChange(
        token: string, 
        deviceId: string, 
        state: continuationManager.ContinuationState
    ): void {
        console.info('[ContinuationManager] State changed:', state);
        
        switch (state) {
            case continuationManager.ContinuationState.CONNECTED:
                this.notifyStateChange(ContinuationStage.ACTIVE);
                break;
            case continuationManager.ContinuationState.DISCONNECTED:
                this.notifyStateChange(ContinuationStage.DISCONNECTED);
                break;
            case continuationManager.ContinuationState.REVERSING:
                this.notifyStateChange(ContinuationStage.REVERSING);
                break;
        }
    }

    // 通知状态变化
    private notifyStateChange(state: ContinuationStage): void {
        if (this.onStateChange) {
            this.onStateChange(state);
        }
    }

    // 设备类型映射
    private mapDeviceType(type: number): DeviceType {
        switch (type) {
            case 1: return DeviceType.PHONE;
            case 2: return DeviceType.TABLET;
            case 3: return DeviceType.TV;
            case 4: return DeviceType.WATCH;
            default: return DeviceType.UNKNOWN;
        }
    }

    // 设置回调
    setOnStateChange(callback: (state: ContinuationStage) => void): void {
        this.onStateChange = callback;
    }

    setOnDeviceChange(callback: (devices: DeviceInfo[]) => void): void {
        this.onDeviceChange = callback;
    }

    // 销毁
    destroy(): void {
        if (this.continuationManager && this.continuationToken) {
            this.continuationManager.unregister(this.continuationToken);
            continuationManager.releaseContinuationManager(this.continuationManager);
        }
        
        if (this.deviceManager) {
            deviceManager.releaseDeviceManager(this.deviceManager);
        }
        
        this.continuationManager = null;
        this.deviceManager = null;
    }
}

// 枚举定义
enum ContinuationStage {
    IDLE = 'idle',
    CONNECTING = 'connecting',
    TRANSFERRING = 'transferring',
    ACTIVE = 'active',
    REVERSING = 'reversing',
    DISCONNECTED = 'disconnected'
}

enum DeviceType {
    UNKNOWN = 'unknown',
    PHONE = 'phone',
    TABLET = 'tablet',
    TV = 'tv',
    WATCH = 'watch'
}

interface DeviceInfo {
    deviceId: string;
    deviceName: string;
    deviceType: DeviceType;
    isOnline: boolean;
}

示例二:带状态同步的Continuation

Continuation流转时需要同步应用状态,这个示例展示如何在流转过程中传递和恢复状态。

// StatefulContinuationAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import continuationManager from '@ohos.continuationManager';

export default class StatefulContinuationAbility extends UIAbility {
    // 应用状态
    private appState: ApplicationState = {
        currentPage: 'home',
        userPreferences: {},
        navigationStack: [],
        formData: {}
    };

    // Continuation管理器
    private continuationManager: continuationManager.ContinuationManager | null = null;
    private continuationToken: string = '';

    async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
        console.info('[StatefulAbility] onCreate');
        
        // 初始化Continuation
        await this.initContinuation();
        
        // 处理Continuation启动
        if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
            this.restoreStateFromContinuation(want);
        }
    }

    // 初始化Continuation
    private async initContinuation(): Promise<void> {
        try {
            this.continuationManager = continuationManager.createContinuationManager(
                this.context.applicationInfo.name
            );
            
            // 注册时指定状态保存回调
            const info: continuationManager.ContinuationInfo = {
                deviceType: continuationManager.DeviceType.DEVICE_TYPE_PHONE |
                            continuationManager.DeviceType.DEVICE_TYPE_TABLET,
                // 关键:指定状态保存回调
                onSaveState: (want: Want): boolean => {
                    return this.onSaveContinuationState(want);
                },
                // 指定状态恢复回调
                onRestoreState: (want: Want): boolean => {
                    return this.onRestoreContinuationState(want);
                }
            };
            
            this.continuationToken = await this.continuationManager.register(info);
            
            console.info('[StatefulAbility] Continuation registered');
        } catch (error) {
            console.error('[StatefulAbility] Init failed:', error);
        }
    }

    // 保存Continuation状态
    private onSaveContinuationState(want: Want): boolean {
        console.info('[StatefulAbility] Saving continuation state');
        
        // 序列化当前状态
        const stateData: ContinuationStateData = {
            // 页面信息
            currentPage: this.appState.currentPage,
            // 导航栈
            navigationStack: JSON.stringify(this.appState.navigationStack),
            // 用户偏好
            userPreferences: JSON.stringify(this.appState.userPreferences),
            // 表单数据(如果有未提交的表单)
            formData: JSON.stringify(this.appState.formData),
            // 时间戳
            timestamp: Date.now(),
            // 版本号(用于兼容性检查)
            version: '1.0'
        };
        
        // 写入Want参数
        want.parameters = {
            ...want.parameters,
            'continuationState': JSON.stringify(stateData)
        };
        
        return true;
    }

    // 恢复Continuation状态
    private onRestoreContinuationState(want: Want): boolean {
        console.info('[StatefulAbility] Restoring continuation state');
        
        if (!want.parameters?.['continuationState']) {
            console.warn('[StatefulAbility] No continuation state found');
            return false;
        }
        
        try {
            const stateData: ContinuationStateData = 
                JSON.parse(want.parameters['continuationState'] as string);
            
            // 版本兼容性检查
            if (stateData.version !== '1.0') {
                console.warn('[StatefulAbility] Version mismatch:', stateData.version);
                return false;
            }
            
            // 恢复状态
            this.appState.currentPage = stateData.currentPage;
            this.appState.navigationStack = JSON.parse(stateData.navigationStack);
            this.appState.userPreferences = JSON.parse(stateData.userPreferences);
            this.appState.formData = JSON.parse(stateData.formData);
            
            // 计算流转耗时
            const elapsed = Date.now() - stateData.timestamp;
            console.info('[StatefulAbility] State restored, elapsed:', elapsed, 'ms');
            
            return true;
        } catch (error) {
            console.error('[StatefulAbility] Restore failed:', error);
            return false;
        }
    }

    // 发起Continuation
    async continueTo(targetDeviceId: string): Promise<void> {
        if (!this.continuationManager || !this.continuationToken) {
            console.error('[StatefulAbility] Continuation not initialized');
            return;
        }
        
        try {
            // 在发起流转前,保存最新状态
            this.saveCurrentState();
            
            // 发起流转
            await this.continuationManager.connect(this.continuationToken, {
                deviceId: targetDeviceId,
                continuationMode: continuationManager.ContinuationMode.PUSH,
                reversible: true
            });
            
            console.info('[StatefulAbility] Continuation started');
        } catch (error) {
            console.error('[StatefulAbility] Continue failed:', error);
        }
    }

    // 保存当前状态(在流转前调用)
    private saveCurrentState(): void {
        // 从UI获取最新状态
        const currentPage = AppStorage.get<string>('currentPage') || 'home';
        const navStack = AppStorage.get<any[]>('navigationStack') || [];
        const formData = AppStorage.get<Record<string, any>>('formData') || {};
        
        this.appState.currentPage = currentPage;
        this.appState.navigationStack = navStack;
        this.appState.formData = formData;
        
        console.info('[StatefulAbility] Current state saved');
    }

    // 从Continuation恢复状态
    private restoreStateFromContinuation(want: Want): void {
        if (this.onRestoreContinuationState(want)) {
            // 通知UI恢复
            this.notifyUIRestore();
        }
    }

    // 通知UI恢复状态
    private notifyUIRestore(): void {
        // 通过AppStorage通知页面
        AppStorage.setOrCreate('restorePage', this.appState.currentPage);
        AppStorage.setOrCreate('restoreNavStack', this.appState.navigationStack);
        AppStorage.setOrCreate('restoreFormData', this.appState.formData);
        AppStorage.setOrCreate('restoreUserPrefs', this.appState.userPreferences);
        
        console.info('[StatefulAbility] UI notified for restore');
    }

    // 更新应用状态(供UI调用)
    updateAppState(key: string, value: any): void {
        switch (key) {
            case 'currentPage':
                this.appState.currentPage = value;
                break;
            case 'formData':
                this.appState.formData = value;
                break;
            default:
                this.appState.userPreferences[key] = value;
        }
    }
}

// 接口定义
interface ApplicationState {
    currentPage: string;
    userPreferences: Record<string, any>;
    navigationStack: any[];
    formData: Record<string, any>;
}

interface ContinuationStateData {
    currentPage: string;
    navigationStack: string;
    userPreferences: string;
    formData: string;
    timestamp: number;
    version: string;
}

示例三:多设备协同Continuation

Continuation的强大之处在于支持多设备协同——同一应用可以同时在多个设备上运行,各司其职。

// MultiDeviceContinuation.ets
import continuationManager from '@ohos.continuationManager';
import deviceManager from '@ohos.distributedDeviceManager';
import distributedData from '@ohos.data.distributedData';

export class MultiDeviceContinuation {
    private continuationManager: continuationManager.ContinuationManager | null = null;
    private deviceManager: deviceManager.DeviceManager | null = null;
    private kvStore: distributedData.SingleKVStore | null = null;
    
    // 活跃的Continuation会话
    private activeSessions: Map<string, ContinuationSession> = new Map();

    async initialize(): Promise<void> {
        // 初始化管理器
        this.continuationManager = continuationManager.createContinuationManager('com.example.app');
        this.deviceManager = deviceManager.createDeviceManager('com.example.app');
        
        // 初始化分布式数据存储,用于多设备间状态同步
        await this.initDistributedStore();
        
        // 注册Continuation
        await this.registerMultiDeviceContinuation();
    }

    // 初始化分布式存储
    private async initDistributedStore(): Promise<void> {
        const kvManager = distributedData.createKVManager({
            bundleName: 'com.example.app',
            userInfo: { userId: 'default', userType: distributedData.UserType.SAME_USER_ID }
        });
        
        this.kvStore = await kvManager.getKVStore({
            storeId: 'multi_device_continuation',
            securityLevel: distributedData.SecurityLevel.S1
        });
        
        // 监听远程数据变化
        this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_REMOTE,
            (data: distributedData.ChangeNotification) => {
                this.handleRemoteSync(data);
            });
    }

    // 注册多设备Continuation
    private async registerMultiDeviceContinuation(): Promise<void> {
        if (!this.continuationManager) return;
        
        const info: continuationManager.ContinuationInfo = {
            deviceType: continuationManager.DeviceType.DEVICE_TYPE_PHONE |
                        continuationManager.DeviceType.DEVICE_TYPE_TABLET |
                        continuationManager.DeviceType.DEVICE_TYPE_TV,
            // 关键:使用COLLABORATE模式,允许多设备同时运行
            continuationMode: continuationManager.ContinuationMode.COLLABORATE
        };
        
        const token = await this.continuationManager.register(info);
        
        // 监听新设备连接
        this.continuationManager.on('deviceConnect', 
            (deviceId: string, session: continuationManager.ContinuationSession) => {
                this.handleDeviceConnect(deviceId, session);
            });
        
        // 监听设备断开
        this.continuationManager.on('deviceDisconnect',
            (deviceId: string) => {
                this.handleDeviceDisconnect(deviceId);
            });
    }

    // 处理设备连接
    private handleDeviceConnect(
        deviceId: string, 
        session: continuationManager.ContinuationSession
    ): void {
        console.info('[MultiDevice] Device connected:', deviceId);
        
        // 创建会话记录
        const continuationSession: ContinuationSession = {
            deviceId: deviceId,
            sessionId: session.sessionId,
            role: this.determineDeviceRole(deviceId),
            connectedAt: Date.now(),
            state: 'active'
        };
        
        this.activeSessions.set(deviceId, continuationSession);
        
        // 根据设备角色分配任务
        this.assignTaskByRole(continuationSession);
        
        // 同步当前状态到新设备
        this.syncStateToDevice(deviceId);
    }

    // 处理设备断开
    private handleDeviceDisconnect(deviceId: string): void {
        console.info('[MultiDevice] Device disconnected:', deviceId);
        
        const session = this.activeSessions.get(deviceId);
        if (session) {
            // 重新分配该设备的任务
            this.reassignTasks(session);
            
            // 移除会话记录
            this.activeSessions.delete(deviceId);
        }
    }

    // 确定设备角色
    private determineDeviceRole(deviceId: string): DeviceRole {
        if (!this.deviceManager) return DeviceRole.UNKNOWN;
        
        const devices = this.deviceManager.getTrustedDeviceListSync();
        const device = devices.find(d => d.deviceId === deviceId);
        
        if (!device) return DeviceRole.UNKNOWN;
        
        // 根据设备类型分配角色
        switch (device.deviceType) {
            case 3: // TV
                return DeviceRole.DISPLAY; // 显示角色:展示内容
            case 2: // Tablet
                return DeviceRole.CONTROL; // 控制角色:交互操作
            case 1: // Phone
                return DeviceRole.INPUT; // 输入角色:数据输入
            default:
                return DeviceRole.AUXILIARY;
        }
    }

    // 根据角色分配任务
    private assignTaskByRole(session: ContinuationSession): void {
        console.info('[MultiDevice] Assigning task for role:', session.role);
        
        const taskAssignment: TaskAssignment = {
            deviceId: session.deviceId,
            role: session.role,
            tasks: []
        };
        
        switch (session.role) {
            case DeviceRole.DISPLAY:
                // 显示设备:负责渲染主内容
                taskAssignment.tasks = ['render_main_content', 'display_fullscreen'];
                break;
            case DeviceRole.CONTROL:
                // 控制设备:负责交互控制
                taskAssignment.tasks = ['handle_interaction', 'show_controls'];
                break;
            case DeviceRole.INPUT:
                // 输入设备:负责数据输入
                taskAssignment.tasks = ['handle_input', 'show_input_panel'];
                break;
        }
        
        // 保存任务分配到分布式存储
        this.saveTaskAssignment(taskAssignment);
        
        // 通知设备执行任务
        this.notifyDeviceTask(session.deviceId, taskAssignment);
    }

    // 重新分配任务
    private reassignTasks(disconnectedSession: ContinuationSession): void {
        console.info('[MultiDevice] Reassigning tasks from:', disconnectedSession.deviceId);
        
        // 获取其他活跃设备
        const activeDevices = Array.from(this.activeSessions.values());
        
        if (activeDevices.length === 0) {
            // 没有其他设备,本地承担所有任务
            this.takeOverAllTasks();
            return;
        }
        
        // 根据剩余设备的角色重新分配
        const tasksToReassign = this.getTasksByRole(disconnectedSession.role);
        
        for (const task of tasksToReassign) {
            // 找到最适合承担该任务的设备
            const targetDevice = this.findBestDeviceForTask(task, activeDevices);
            if (targetDevice) {
                this.assignTaskToDevice(task, targetDevice);
            }
        }
    }

    // 同步状态到设备
    private async syncStateToDevice(deviceId: string): Promise<void> {
        if (!this.kvStore) return;
        
        // 获取当前完整状态
        const currentState = await this.getCurrentState();
        
        // 发送到目标设备
        await this.kvStore.put(`sync_${deviceId}`, {
            key: `sync_${deviceId}`,
            value: JSON.stringify(currentState)
        });
    }

    // 处理远程同步
    private handleRemoteSync(data: distributedData.ChangeNotification): void {
        if (!data.updateRecords || data.updateRecords.length === 0) return;
        
        for (const record of data.updateRecords) {
            const key = record.key;
            
            if (key.startsWith('task_')) {
                // 任务分配更新
                this.applyTaskAssignment(JSON.parse(record.value.value as string));
            } else if (key.startsWith('sync_')) {
                // 状态同步
                this.applyStateSync(JSON.parse(record.value.value as string));
            }
        }
    }

    // 保存任务分配
    private async saveTaskAssignment(assignment: TaskAssignment): Promise<void> {
        if (!this.kvStore) return;
        
        await this.kvStore.put(`task_${assignment.deviceId}`, {
            key: `task_${assignment.deviceId}`,
            value: JSON.stringify(assignment)
        });
    }

    // 通知设备任务
    private notifyDeviceTask(deviceId: string, assignment: TaskAssignment): void {
        // 通过Continuation发送消息
        if (this.continuationManager) {
            this.continuationManager.sendData(deviceId, {
                type: 'task_assignment',
                assignment: assignment
            });
        }
    }

    // 辅助方法
    private async getCurrentState(): Promise<any> {
        return {}; // 实际实现需要获取当前状态
    }

    private applyTaskAssignment(assignment: TaskAssignment): void {
        console.info('[MultiDevice] Applying task assignment:', assignment);
    }

    private applyStateSync(state: any): void {
        console.info('[MultiDevice] Applying state sync');
    }

    private getTasksByRole(role: DeviceRole): string[] {
        return []; // 实际实现
    }

    private findBestDeviceForTask(task: string, devices: ContinuationSession[]): ContinuationSession | null {
        return devices[0] || null; // 实际实现
    }

    private assignTaskToDevice(task: string, device: ContinuationSession): void {
        console.info('[MultiDevice] Assigning task to device:', task, device.deviceId);
    }

    private takeOverAllTasks(): void {
        console.info('[MultiDevice] Taking over all tasks');
    }
}

// 枚举和接口
enum DeviceRole {
    UNKNOWN = 'unknown',
    DISPLAY = 'display',
    CONTROL = 'control',
    INPUT = 'input',
    AUXILIARY = 'auxiliary'
}

interface ContinuationSession {
    deviceId: string;
    sessionId: string;
    role: DeviceRole;
    connectedAt: number;
    state: 'active' | 'inactive' | 'disconnecting';
}

interface TaskAssignment {
    deviceId: string;
    role: DeviceRole;
    tasks: string[];
}

踩坑与注意事项

坑一:Continuation注册时机错误

问题描述:在Ability的onCreate中注册Continuation,但此时UI还未创建,导致状态保存回调无法获取UI数据。

解决方案:在onWindowStageCreate后注册,或在状态保存时从AppStorage获取数据。

坑二:设备角色分配冲突

问题描述:多设备协同时,两个相同类型的设备连接,角色分配产生冲突。

解决方案:实现优先级机制

private determineDeviceRoleWithPriority(deviceId: string, existingRoles: DeviceRole[]): DeviceRole {
    const baseRole = this.determineDeviceRole(deviceId);
    
    // 如果该角色已被占用,降级为辅助角色
    if (existingRoles.includes(baseRole)) {
        return DeviceRole.AUXILIARY;
    }
    
    return baseRole;
}

坑三:状态同步延迟导致不一致

问题描述:多设备间状态同步存在延迟,导致短时间内各设备状态不一致。

解决方案:实现乐观锁或版本号机制

interface VersionedState {
    version: number;
    state: any;
    deviceId: string;
    timestamp: number;
}

private mergeStates(local: VersionedState, remote: VersionedState): VersionedState {
    // 使用版本号和设备ID作为冲突解决依据
    if (remote.version > local.version) {
        return remote;
    } else if (remote.version === local.version && remote.timestamp > local.timestamp) {
        return remote;
    }
    return local;
}

HarmonyOS 6适配

新增Continuation分组

HarmonyOS 6支持Continuation分组,可以将不同的功能模块分配到不同设备:

// 定义Continuation分组
const groups: continuationManager.ContinuationGroup[] = [
    {
        groupId: 'main_display',
        abilities: ['MainAbility'],
        preferredDeviceType: continuationManager.DeviceType.DEVICE_TYPE_TV
    },
    {
        groupId: 'control_panel',
        abilities: ['ControlAbility'],
        preferredDeviceType: continuationManager.DeviceType.DEVICE_TYPE_TABLET
    },
    {
        groupId: 'input_method',
        abilities: ['InputAbility'],
        preferredDeviceType: continuationManager.DeviceType.DEVICE_TYPE_PHONE
    }
];

// 注册分组Continuation
await this.continuationManager.registerGroups(groups);

增强的设备能力查询

// 查询设备特定能力
const capabilities = await this.continuationManager.queryDeviceCapabilities(deviceId, [
    'screen_size',
    'input_methods',
    'audio_output',
    'camera'
]);

console.info('Device capabilities:', capabilities);
// 输出示例:
// {
//   screen_size: { width: 1920, height: 1080 },
//   input_methods: ['touch', 'keyboard', 'mouse'],
//   audio_output: ['speaker', 'bluetooth'],
//   camera: { available: true, resolution: '4K' }
// }

总结

Continuation是HarmonyOS分布式能力的进阶形态,相比Ability迁移,它提供了更灵活的流转粒度和更丰富的协同模式。

核心要点

  1. 按需流转:不是全有或全无,可以根据场景选择流转的内容
  2. 多设备协同:同一应用可以在多个设备上同时运行,各司其职
  3. 状态同步:通过分布式数据存储实现多设备间状态一致性
  4. 角色分配:根据设备类型和能力自动分配任务角色

最佳实践

  • 合理设计状态数据结构,确保可序列化和可恢复
  • 实现设备角色分配和任务调度逻辑
  • 处理设备连接、断开、重连等边界情况
  • 使用分布式存储实现状态同步
  • 做好冲突检测和解决机制

Continuation打开了多设备协同的大门,让"超级终端"的概念真正落地。下一篇我们将探讨分布式窗口,看看如何实现跨设备的窗口投射。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。