目前来看,鸿蒙应用的跨设备分布式调度并不复杂,跟在本应用内调用没有太大却区别,只是多了权限管理和设备管理的相关参数和配置。

这里我将官方文档的代码整理一下,等待以后验证。

首先配置权限,根据已经验证了的DataAbility可知,权限是配置在请求方的Ability的配置文件里的

      {
        "skills": [
          {
            "entities": [
              "entity.system.home"
            ],
            "actions": [
              "action.system.home"
            ]
          }
        ],
        "orientation": "unspecified",
        "name": "com.example.distributeddemo.MainAbility",
        "icon": "$media:icon",
        "description": "$string:mainability_description",
        "label": "DistributedDemo",
        "type": "page",
        "launchType": "standard",
        "reqPermissions": [
          {
            "name": "ohos.permission.DISTRIBUTED_DATASYNC"
          }
        ]
      }

上面reqPermissions就是配置权限,使该Ability支持任务调度,然后就是改造AbilitySlice

首先要实现IAbilityContinuation接口,并实现接口方法,并在onStart里显式申明权限

public class SampleSlice extends AbilitySlice implements IAbilityContinuation {
    @Override
    public void onStart(Intent intent) {
        // 开发者显示声明需要使用的权限
        requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"}, 0);
        super.onStart(intent);        
    }
}

然后编写UI,添加几个按钮:

<?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:orientation="vertical">
    <Button
        ohos:id="$+id:btn_start_remote_fa"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="远程启动FA"
        ohos:text_size="19fp"
        ohos:text_color="#FFFFFF"
        ohos:top_padding="8vp"
        ohos:layout_alignment="center"
        ohos:bottom_padding="8vp"
        ohos:right_padding="70vp"
        ohos:left_padding="70vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:center_in_parent="true"
        ohos:bottom_margin="10vp"/>
    <Button
        ohos:id="$+id:btn_continue_remote_fa"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="远程迁移FA"
        ohos:text_size="19fp"
        ohos:text_color="#FFFFFF"
        ohos:top_padding="8vp"
        ohos:layout_alignment="center"
        ohos:bottom_padding="8vp"
        ohos:right_padding="70vp"
        ohos:left_padding="70vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:center_in_parent="true"
        ohos:bottom_margin="10vp"/>
    <Button
        ohos:id="$+id:btn_start_remote_pa"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="远程启动PA"
        ohos:text_size="19fp"
        ohos:text_color="#FFFFFF"
        ohos:top_padding="8vp"
        ohos:layout_alignment="center"
        ohos:bottom_padding="8vp"
        ohos:right_padding="70vp"
        ohos:left_padding="70vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:center_in_parent="true"
        ohos:bottom_margin="10vp"/>
    <Button
        ohos:id="$+id:btn_stop_remote_pa"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="远程关闭PA"
        ohos:text_size="19fp"
        ohos:text_color="#FFFFFF"
        ohos:top_padding="8vp"
        ohos:layout_alignment="center"
        ohos:bottom_padding="8vp"
        ohos:right_padding="70vp"
        ohos:left_padding="70vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:center_in_parent="true"
        ohos:bottom_margin="10vp"/>
    <Button
        ohos:id="$+id:btn_connect_remote_pa"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="连接远程PA"
        ohos:text_size="19fp"
        ohos:text_color="#FFFFFF"
        ohos:top_padding="8vp"
        ohos:layout_alignment="center"
        ohos:bottom_padding="8vp"
        ohos:right_padding="70vp"
        ohos:left_padding="70vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:center_in_parent="true"
        ohos:bottom_margin="10vp"/>
    <Button
        ohos:id="$+id:btn_control_remote_pa"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="控制连接PA"
        ohos:text_size="19fp"
        ohos:text_color="#FFFFFF"
        ohos:top_padding="8vp"
        ohos:layout_alignment="center"
        ohos:bottom_padding="8vp"
        ohos:right_padding="70vp"
        ohos:left_padding="70vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:center_in_parent="true"
        ohos:bottom_margin="10vp"/>
    <Button
        ohos:id="$+id:btn_disconnect_remote_pa"
        ohos:width="match_content"
        ohos:height="match_content"
        ohos:text="断开远程PA"
        ohos:text_size="19fp"
        ohos:text_color="#FFFFFF"
        ohos:top_padding="8vp"
        ohos:layout_alignment="center"
        ohos:bottom_padding="8vp"
        ohos:right_padding="70vp"
        ohos:left_padding="70vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:center_in_parent="true"
        ohos:bottom_margin="10vp"/>

</DirectionalLayout>

初始化按钮,并添加点击事件:

    private MyRemoteProxy mProxy = null;
    private Button btnConnectRemotePA;
    private Button btnControlRemotePA;
    private Button btnContinueRemoteFA;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_main);
        requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"}, 0);
        InsideListener listener = new InsideListener();
        findComponentById(ResourceTable.Id_btn_start_remote_fa).setClickedListener(listener);
        findComponentById(ResourceTable.Id_btn_start_remote_pa).setClickedListener(listener);
        findComponentById(ResourceTable.Id_btn_stop_remote_pa).setClickedListener(listener);
        btnContinueRemoteFA = (Button) findComponentById(ResourceTable.Id_btn_continue_remote_fa);
        btnContinueRemoteFA.setClickedListener(listener);
        btnConnectRemotePA = (Button) findComponentById(ResourceTable.Id_btn_connect_remote_pa);
        btnConnectRemotePA.setClickedListener(listener);
        btnControlRemotePA = (Button) findComponentById(ResourceTable.Id_btn_control_remote_pa);
        btnControlRemotePA.setClickedListener(listener);
        findComponentById(ResourceTable.Id_btn_disconnect_remote_pa).setClickedListener(listener);
    }

class InsideListener implements Component.ClickedListener {

        @Override
        public void onClick(Component component) {
            switch (component.getId()) {
                case ResourceTable.Id_btn_start_remote_fa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_start_remote_fa");
                    
                    break;
                case ResourceTable.Id_btn_continue_remote_fa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_continue_remote_fa");
                    
                    break;
                case ResourceTable.Id_btn_start_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_start_remote_pa");
                    
                    break;
                case ResourceTable.Id_btn_stop_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_stop_remote_pa");
                    break;
                case ResourceTable.Id_btn_connect_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_connect_remote_pa");
                    
                    break;
                case ResourceTable.Id_btn_control_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_control_remote_pa");
                    break;
                case ResourceTable.Id_btn_disconnect_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_disconnect_remote_pa");
                    
                    break;
                default:
                    break;
            }
        }
    }

通过设备管理DeviceManager提供的getDeviceList接口获取设备列表,并选择一个设备:

 // ISelectResult是一个自定义接口,用来处理指定设备deviceId后执行的行为
    interface ISelectResult {
        void onSelectResult(String deviceId);
    }

    // 获得设备列表,开发者可在得到的在线设备列表中选择目标设备执行操作
    private void scheduleRemoteAbility(ISelectResult listener) {
        // 调用DeviceManager的getDeviceList接口,通过FLAG_GET_ONLINE_DEVICE标记获得在线设备列表
        List<DeviceInfo> onlineDevices = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
        // 判断组网设备是否为空
        if (onlineDevices.isEmpty()) {
            listener.onSelectResult(null);
            return;
        }
        int numDevices = onlineDevices.size();
        ArrayList<String> deviceIds = new ArrayList<>(numDevices);
        ArrayList<String> deviceNames = new ArrayList<>(numDevices);
        onlineDevices.forEach((device) -> {
            deviceIds.add(device.getDeviceId());
            deviceNames.add(device.getDeviceName());
        });
        // 以选择首个设备作为目标设备为例
        // 开发者也可按照具体场景,通过别的方式进行设备选择
        String selectDeviceId = deviceIds.get(0);
        listener.onSelectResult(selectDeviceId);
    }

各个按钮对应的点击事件:

class InsideListener implements Component.ClickedListener {

        @Override
        public void onClick(Component component) {
            switch (component.getId()) {
                case ResourceTable.Id_btn_start_remote_fa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_start_remote_fa");
                    // 启动远程PA
                    scheduleRemoteAbility(new ISelectResult() {
                        @Override
                        public void onSelectResult(String deviceId) {
                            if (deviceId != null) {
                                Intent intent = new Intent();
                                // 通过scheduleRemoteAbility指定目标设备deviceId
                                // 指定待启动FA的bundleName和abilityName
                                // 例如:bundleName = "com.huawei.helloworld"
                                //       abilityName = "com.huawei.helloworld.SampleFeatureAbility"
                                // 设置分布式标记,表明当前涉及分布式能力
                                Operation operation = new Intent.OperationBuilder()
                                        .withDeviceId(deviceId)
                                        .withBundleName("目标bundleName")
                                        .withAbilityName("目标abilityName")
                                        .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                                        .build();
                                intent.setOperation(operation);
                                // 通过AbilitySlice包含的startAbility接口实现跨设备启动FA
                                startAbility(intent);
                            }
                        }
                    });
                    break;
                case ResourceTable.Id_btn_continue_remote_fa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_continue_remote_fa");
                    // 用户选择设备后实现业务迁移
                    scheduleRemoteAbility(new ISelectResult() {
                        @Override
                        public void onSelectResult(String deviceId) {
                            continueAbility(deviceId);
                        }
                    });
                    break;
                case ResourceTable.Id_btn_start_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_start_remote_pa");
                    // 启动远程PA
                    scheduleRemoteAbility(new ISelectResult() {
                        @Override
                        public void onSelectResult(String deviceId) {
                            if (deviceId != null) {
                                Intent intentToStartPA = new Intent();
                                // bundleName和abilityName与待启动PA对应
                                // 例如:bundleName = "com.huawei.helloworld"
                                //       abilityName = "com.huawei.helloworld.SampleParticleAbility"
                                Operation operation = new Intent.OperationBuilder()
                                        .withDeviceId(deviceId)
                                        .withBundleName("目标bundleName")
                                        .withAbilityName("目标abilityName")
                                        .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                                        .build();
                                intentToStartPA.setOperation(operation);
                                startAbility(intentToStartPA);
                            }
                        }
                    });
                    break;
                case ResourceTable.Id_btn_stop_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_stop_remote_pa");
                    scheduleRemoteAbility(new ISelectResult() {
                        @Override
                        public void onSelectResult(String deviceId) {
                            if (deviceId != null) {
                                Intent intentToStopPA = new Intent();
                                // bundleName和abilityName与待关闭PA对应
                                // 例如:bundleName = "com.huawei.helloworld"
                                //       abilityName = "com.huawei.helloworld.SampleParticleAbility"
                                Operation operation = new Intent.OperationBuilder()
                                        .withDeviceId(deviceId)
                                        .withBundleName("目标bundleName")
                                        .withAbilityName("目标abilityName")
                                        .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                                        .build();
                                intentToStopPA.setOperation(operation);
                                stopAbility(intentToStopPA);
                            }
                        }
                    });
                    break;
                case ResourceTable.Id_btn_connect_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_connect_remote_pa");
                    scheduleRemoteAbility(new ISelectResult() {
                        @Override
                        public void onSelectResult(String deviceId) {
                            if (deviceId != null) {
                                Intent connectPAIntent = new Intent();
                                // bundleName和abilityName与待连接的PA一一对应
                                // 例如:bundleName = "com.huawei.helloworld"
                                //       abilityName = "com.huawei.helloworld.SampleParticleAbility"
                                Operation operation = new Intent.OperationBuilder()
                                        .withDeviceId(deviceId)
                                        .withBundleName("目标bundleName")
                                        .withAbilityName("目标abilityName")
                                        .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                                        .build();
                                connectPAIntent.setOperation(operation);
                                connectAbility(connectPAIntent, conn);
                            }
                        }
                    });
                    break;
                case ResourceTable.Id_btn_control_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_control_remote_pa");
                    if (mProxy != null) {
                        int ret = -1;
                        try {
                            ret = mProxy.plus(10, 20);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        btnControlRemotePA.setText("控制连接 result = " + ret);
                    }
                    break;
                case ResourceTable.Id_btn_disconnect_remote_pa:
                    HiLog.info(LABEL_LOG, "MainAbilitySlice btn_disconnect_remote_pa");
                    btnConnectRemotePA.setText("连接远程PA");
                    btnControlRemotePA.setText("控制连接PA");
                    disconnectAbility(conn);
                    break;
                default:
                    break;
            }
        }
    }

最后,FA跨设备迁移的生命周期方法:

流程参见;https://blog.csdn.net/y280903468/article/details/111770977

@Override
    public boolean onSaveData(IntentParams saveData) {
        String exampleData = String.valueOf(System.currentTimeMillis());
        saveData.setParam("continueParam", exampleData);
        return true;
    }

    @Override
    public boolean onRestoreData(IntentParams restoreData) {
        // 远端FA迁移传来的状态数据,开发者可以按照特定的场景对这些数据进行处理
        Object data = restoreData.getParam("continueParam");
        return true;
    }

    @Override
    public void onCompleteContinuation(int result) {
        btnContinueRemoteFA.setText("ContinueAbility Done");
    }

 

https://download.csdn.net/download/y280903468/14004469

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐