HarmonyOS 鸿蒙Next实现多设备协同

HarmonyOS 鸿蒙Next实现多设备协同 在前面的文章中,已经介绍了如何实现跨设备迁移。本节在上节的基础上,稍作改造,以实现多设备之间的协同。

选择模板

选择Empty Ablity(Java)

创建项目

创建名为ContinueRemoteFACollaboration的项目作为演示

项目创建完成之后,会自动生成基础的代码结构,接下来直接在该结构上进行微调即可。

MainAbility实现implements IAbilityContinuation接口

MainAbility实现implements IAbilityContinuation接口,代码如下:

package com.waylau.hmos.continueremotefacollaboration;

import com.waylau.hmos.continueremotefacollaboration.slice.MainAbilitySlice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.IAbilityContinuation;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.bundle.IBundleManager;
import ohos.security.SystemPermission;
import java.util.ArrayList;
import java.util.List;

/**
* 设备迁移与回迁
*
* @author <a href="https://waylau.com">Way Lau</a>
*/
public class MainAbility extends Ability implements IAbilityContinuation {
@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setMainRoute(MainAbilitySlice.class.getName());
}

@Override
public boolean onStartContinuation() {
    // 重写
    return true;
}

@Override
public boolean onSaveData(IntentParams intentParams) {
    // 重写
    return true;
}

@Override
public boolean onRestoreData(IntentParams intentParams) {
    // 重写
    return true;
}

@Override
public void onCompleteContinuation(int i) {
}
}

上述代码,重点是重写onStartContinuationonSaveDataonRestoreData等方法。

申明权限

在项目的对应的config.json中声明跨端迁移访问的权限:ohos.permission.DISTRIBUTED_DATASYNC以及获取分布式设备信息的相关的权限。在config.json中的配置如下:

{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
},
{
"name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
},
{
"name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
},
{
"name": "ohos.permission.GET_BUNDLE_INFO"
}
]
...
}
...
}

同时修改MainAbility,显示申明ohos.permission.DISTRIBUTED_DATASYNC权限,最终,MainAbility完整代码如下:

package com.waylau.hmos.continueremotefacollaboration;

import com.waylau.hmos.continueremotefacollaboration.slice.MainAbilitySlice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.IAbilityContinuation;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.IntentParams;
import ohos.security.SystemPermission;
import java.util.ArrayList;
import java.util.List;

/**
* 设备迁移与回迁
*
* @author <a href="https://waylau.com">Way Lau</a>
*/
public class MainAbility extends Ability implements IAbilityContinuation {
@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setMainRoute(MainAbilitySlice.class.getName());
    requestPermission();
}

//获取权限
private void requestPermission() {
    String[] permission = {
        SystemPermission.DISTRIBUTED_DATASYNC
    };
    List<String> applyPermissions = new ArrayList<>();
    for (String element : permission) {
        if (verifySelfPermission(element) != 0) {
            if (canRequestPermission(element)) {
                applyPermissions.add(element);
            }
        }
    }
    requestPermissionsFromUser(applyPermissions.toArray(new String[0]), 0);
}

@Override
public boolean onStartContinuation() {
    // 重写
    return true;
}

@Override
public boolean onSaveData(IntentParams intentParams) {
    // 重写
    return true;
}

@Override
public boolean onRestoreData(IntentParams intentParams) {
    // 重写
    return true;
}

@Override
public void onCompleteContinuation(int i) {
}
}

设计界面与布局

修改ability_main.xml布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <TextField
        ohos:id="$+id:message_textfield"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:hint="输入信息"
        ohos:top_margin="100vp"
        ohos:left_margin="24vp"
        ohos:padding="5vp"
        ohos:background_element="$graphic:background_ability_main"
        ohos:text_alignment="center"
        ohos:right_margin="24vp"
        ohos:text_size="28vp"/>

    <Button
        ohos:id="$+id:button_continue_remote_fa"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:top_margin="8vp"
        ohos:background_element="$graphic:background_ability_main"
        ohos:layout_alignment="horizontal_center"
        ohos:text="迁移"
        ohos:text_size="40vp"/>
</DirectionalLayout>

同时,修改background_ability_main.xml样式文件如下:

<?xml version="1.0" encoding="UTF-8" ?>
<shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
       ohos:shape="rectangle">
    <corners
        ohos:radius="10"/>
    <solid
        ohos:color="#FAEBD7"/>
</shape>

修改MainAbilitySlice

核心的逻辑都集中到了MainAbilitySlice中。MainAbilitySlice同样也要实现implements IAbilityContinuation接口,代码如下:

public class MainAbilitySlice extends AbilitySlice implements IAbilityContinuation {
private static final String TAG = MainAbilitySlice.class.getSimpleName();
private static final HiLogLabel LABEL_LOG =
    new HiLogLabel(HiLog.LOG_APP, 0x00001, TAG);

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);
}

@Override
public void onActive() {
    super.onActive();
}

@Override
public void onForeground(Intent intent) {
    super.onForeground(intent);
}

@Override
public boolean onStartContinuation() {
    // 重写
    return true;
}

@Override
public boolean onSaveData(IntentParams intentParams) {
    // 重写
    // 保存回迁后恢复状态必须的数据
    intentParams.setParam(MESSAGE_KEY, messageTextField.getText());
    return true;
}

@Override
public boolean onRestoreData(IntentParams intentParams) {
    // 重写
    // 传递此前保存的数据
    if (intentParams.getParam(MESSAGE_KEY) instanceof String) {
        message = (String) intentParams.getParam(MESSAGE_KEY);
        isContinued = true;
    }
    return true;
}

@Override
public void onCompleteContinuation(int i) {
    // 终止
    terminate();
}
}

上述代码,重点是重写onStartContinuationonSaveDataonRestoreDataonCompleteContinuation等方法。其中,onSaveData用于保存回迁后恢复状态必须的数据; onRestoreData传递此前保存的数据。onCompleteContinuation方法用于终止Page。

接着为“迁移”“回迁”按钮设置点击事件,代码如下:

private String message;
private boolean isContinued;
private TextField messageTextField;

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);
    // 监听跨端迁移FA的事件
    Button buttonContinueRemoteFA = (
        Button) findComponentById(ResourceTable.Id_button_continue_remote_fa);
    buttonContinueRemoteFA.setClickedListener(listener -> continueRemoteFA());

    // 设置输入框内容
    messageTextField = (TextField) findComponentById(ResourceTable.Id_message_textfield);
    if (isContinued && message != null) {
        messageTextField.setText(message);
    }
}

private void continueRemoteFA() {
    HiLog.info(LABEL_LOG, "before startRemoteFA");
    String deviceId = DeviceUtils.getDeviceId();
    HiLog.info(LABEL_LOG, "get deviceId: %{public}s", deviceId);
    if (deviceId != null) {
        // 发起迁移流程
        // continueAbility()是不可回迁的
        // continueAbilityReversibly() 是可以回迁的
        continueAbility(deviceId);
    }
}

上述代码:

  • 可以通过continueAbility或者continueAbilityReversibly方法来执行迁移。需要注意的是continueAbility()是不可回迁的,而continueAbilityReversibly()是可以回迁的。本例子是使用了continueAbility方法。
  • continueAbility方法可以指定待迁移的设备的ID,该ID通过DeviceUtils工具类获取。
  • Message用于表示设备迁移时的状态数据。

DeviceUtils

DeviceUtils代码如下:

package com.waylau.hmos.continueremotefacollaboration;

import ohos.distributedschedule.interwork.DeviceInfo;
import ohos.distributedschedule.interwork.DeviceManager;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import java.util.ArrayList;
import java.util.List;

/**
* 获取当前组网下可迁移的设备id列表
*
* @author <a href="https://waylau.com">Way Lau</a>
*/
public class DeviceUtils {
private static final String TAG = DeviceUtils.class.getSimpleName();
private static final HiLogLabel LABEL_LOG =
    new HiLogLabel(HiLog.LOG_APP, 0x00001, TAG);

private DeviceUtils() {}

// 获取当前组网下可迁移的设备id列表
public static List<String> getAvailableDeviceId() {
    List<String> deviceIds = new ArrayList<>();
    List<DeviceInfo> deviceInfoList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ALL_DEVICE);
    if (deviceInfoList == null) {
        return deviceIds;
    }
    if (deviceInfoList.size() == 0) {
        HiLog.warn(LABEL_LOG, "did not find other device");
        return deviceIds;
    }
    for (DeviceInfo deviceInfo : deviceInfoList) {
        deviceIds.add(deviceInfo.getDeviceId());
    }
    return deviceIds;
}

// 获取当前组网下可迁移的设备id
// 如果有多个则取第一个
public static String getDeviceId() {
    String deviceId = "";
    List<String> outerDevices = DeviceUtils.getAvailableDeviceId();
    if (outerDevices == null || outerDevices.size() == 0) {
        HiLog.warn(LABEL_LOG, "did not find other device");
    } else {
        for (String item : outerDevices) {
            HiLog.info(LABEL_LOG, "outerDevices:%{public}s", item);
        }
        deviceId = outerDevices.get(0);
    }
    HiLog.info(LABEL_LOG, "getDeviceId:%{public}s", deviceId);
    return deviceId;
}
}

DeviceUtilsgetDeviceId方法用于获取在线设备列表。如果有多个,则取任意一个。

运行

为了演示多个设备的迁移情况,需要启动“Super device”,同时启动手机和平台两个模拟器。

将项目同时在这两个模拟器里面运行。

此时,假设手机为设备A,作为源设备,平台为设备B,作为目标设备。

在设备A上,在输入框中输入一些信息,比如“hello”。

而后点击“迁移”按钮,此时可以看到,Page已经迁移到了设备B上了。说明迁移成功了。

在设备B上可以继续对输入框进行编辑,比如输入“world”。

而后点击“迁移”按钮,此时可以看到,Page从设备B迁移到了设备A了。同时,在设备B上输入的内容,也同时迁移到了设备A上,这样就实现了多设备之间的协同。

参考


更多关于HarmonyOS 鸿蒙Next实现多设备协同的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

为啥我的app流转到电视上不是全屏呢?

更多关于HarmonyOS 鸿蒙Next实现多设备协同的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS Next通过分布式技术实现多设备协同,主要包括以下关键技术:

  1. 分布式软总线:通过虚拟化的通信方式,将不同设备的硬件能力整合成一个“超级终端”,实现设备间的无缝连接。

  2. 分布式数据管理:跨设备数据同步与共享,确保数据一致性,提升用户体验。

  3. 分布式任务调度:根据设备性能和用户需求,智能分配任务,优化资源利用。

  4. 统一控制中心:用户可通过一个设备集中管理所有连接的设备,简化操作流程。

这些技术共同构建了HarmonyOS Next的多设备协同能力,提升了跨设备操作的便捷性和效率。

回到顶部