鸿蒙os多设备如何实现,鸿蒙OS中如何实现跨设备迁移?

本文详细介绍了在鸿蒙OS中如何实现分布式任务调度,包括远程启动FA、业务无缝迁移以及可逆迁移。通过声明权限、使用特定接口,如startAbility和continueAbility,开发者可以在不同设备间迁移应用,实现跨设备的业务连续性。同时,文章还阐述了回迁过程,确保数据在迁移过程中的完整性和一致性。
摘要由CSDN通过智能技术生成

原标题:鸿蒙OS中如何实现跨设备迁移?

6c22558a8b089ad37651484016c7d5d7.png

01

分布式任务调度概述

在 HarmonyOS 中,分布式任务调度平台对搭载 HarmonyOS 的多设备构筑的“超级虚拟终端”提供统一的组件管理能力,为应用定义统一的能力基线、接口形式、数据结构、服务描述语言,屏蔽硬件差异;支持远程启动、远程调用、业务无缝迁移等分布式任务。

02

实现调度的约束与限制

①远程调用 PA/FA,开发者需要在 Intent 中设置支持分布式的标记(例如:Intent.FLAG_ABILITYSLICE_MULTI_DEVICE 表示该应用支持分布式调度),否则将无法获得分布式能力。

②开发者通过在 config.json 中的 reqPermissions 字段里添加权限申请,以获取跨设备连接的能力和分布式数据传输的权限:

分布式数据传输的权限:

{ "name": "ohos.permission.servicebus.ACCESS_SERVICE"}

三方应用使用权限:

{ "name": "ohos.permission.servicebus.DISTRIBUTED_DATASYNC"}

系统应用使用权限:

{ "name": "com.huawei.hwddmp.servicebus.BIND_SERVICE"}

另外还有三个获取分布式设备信息需要的权限:

{ "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"},

{ "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"},

{ "name": "ohos.permission.GET_BUNDLE_INFO"}

注意:还需要在开发的时候,要在 Ability 里主动声明,要用到的权限。

FA(Feature Ability,Page 模板的 Ability)的调用支持启动和迁移行为,在进行调度时:

当启动 FA 时,需要开发者在 Intent 中指定对端设备的 deviceId、bundleName 和 abilityName。

FA 的迁移实现相同 bundleName 和 abilityName 的 FA 跨设备迁移,因此需要指定迁移设备的 deviceId。

03

实现场景介绍

下面以设备 A(本地设备)和设备 B(远端设备)为例,介绍下面我们要实现的场景:

设备 A 启动设备 B 的 FA: 在设备 A 上通过本地应用提供的启动按钮,启动设备 B 上对应的 FA。

设备 A 的 FA 迁移至设备 B: 设备 A 上通过本地应用提供的迁移按钮,将设备 A 的业务无缝迁移到设备 B 中。

设备 A 的 FA 迁移至设备 B, 还可以实现主动撤回迁移。

04

具体实现前先了解要用的接口

①启动远程 FA

startAbility(Intent intent )接口提供启动指定设备上 FA 和 PA 的能力,Intent 中指定待启动 FA 的设备 deviceId、bundleName 和 abilityName。

②迁移 FA

continueAbility(String deviceId )接口提供将本地 FA 迁移到指定设备上的能力。

continueAbilityReversibly(String deviceId )接口提供将本地 FA 迁移到指定设备上的能力,这种迁移可撤回,reverseContinueAbility 接口提供撤回迁移的能力。

05

实战远程启动 FA 页面

①编程实现上面场景的界面

ability_main.xml:

< DirectionalLayout

xmlns:ohos= "http://schemas.huawei.com/res/ohos"

ohos:height= "match_parent"

ohos:width= "match_parent"

ohos:orientation= "vertical">

< Button

ohos:id= "$+id:migration_btn_01"

ohos:height= "match_content"

ohos:width= "300vp"

ohos:text= "1.启动远程设备的FA"

ohos:text_size= "20fp"

ohos:text_color= "#ffffff"

ohos:background_element= "$graphic:button_bg"

ohos:layout_alignment= "horizontal_center"

ohos:top_padding= "8vp"

ohos:bottom_padding= "8vp"

ohos:left_padding= "40vp"

ohos:right_padding= "40vp"

ohos:top_margin= "20vp"

/>

< Button

ohos:id= "$+id:migration_btn_02"

ohos:height= "match_content"

ohos:width= "300vp"

ohos:text= "2.迁移到远程设备"

ohos:text_size= "20fp"

ohos:text_color= "#ffffff"

ohos:background_element= "$graphic:button_bg"

ohos:layout_alignment= "horizontal_center"

ohos:top_padding= "8vp"

ohos:bottom_padding= "8vp"

ohos:left_padding= "40vp"

ohos:right_padding= "40vp"

ohos:top_margin= "20vp"

/>

< Button

ohos:id= "$+id:migration_btn_03"

ohos:height= "match_content"

ohos:width= "300vp"

ohos:text= "3.可迁回的迁移远程设备"

ohos:text_size= "20fp"

ohos:text_color= "#ffffff"

ohos:background_element= "$graphic:button_bg"

ohos:layout_alignment= "horizontal_center"

ohos:top_padding= "8vp"

ohos:bottom_padding= "8vp"

ohos:left_padding= "40vp"

ohos:right_padding= "40vp"

ohos:top_margin= "20vp"

/>

DirectionalLayout>

button_bg.xml:

< shapexmlns:ohos= "http://schemas.huawei.com/res/ohos"

ohos:shape= "rectangle">

< solidohos:color= "#007DFF"/>

< cornersohos:radius= "40"/>

shape>

MigrationAbility 和 MigrationBackAbility:

// 调用AbilitySlice模板实现一个用于控制基础功能的FA

// Ability和AbilitySlice类均需要实现IAbilityContinuation及其方法,才可以实现FA迁移。AbilitySlice的代码示例如下

publicclassSampleSliceextendsAbilitySliceimplementsIAbilityContinuation{

@Override

publicvoidonStart(Intent intent){

super.onStart(intent);

super.setUIContent(layout);

}

ability_migration.xml:

< DirectionalLayout

xmlns:ohos= "http://schemas.huawei.com/res/ohos"

ohos:height= "match_parent"

ohos:width= "match_parent"

ohos:background_element= "#00ffff"

ohos:orientation= "vertical">

< Text

ohos:id= "$+id:text_title"

ohos:height= "match_content"

ohos:width= "250vp"

ohos:background_element= "#0088bb"

ohos:layout_alignment= "horizontal_center"

ohos:text= "下面是一个可编辑的文本框"

ohos:text_size= "50"

ohos:padding= "5vp"

ohos:top_margin= "30vp"

/>

< TextField

ohos:id= "$+id:textfield_back"

ohos:height= "250vp"

ohos:width= "250vp"

ohos:hint= "请输入..."

ohos:layout_alignment= "horizontal_center"

ohos:background_element= "#ffffff"

ohos:text_color= "#888888"

ohos:text_size= "20fp"

ohos:padding= "5vp"

/>

< Button

ohos:id= "$+id:migration_button"

ohos:height= "match_content"

ohos:width= "match_content"

ohos:text= "点击迁移"

ohos:text_size= "20fp"

ohos:text_color= "#ffffff"

ohos:background_element= "$graphic:button_bg"

ohos:top_padding= "8vp"

ohos:bottom_padding= "8vp"

ohos:left_padding= "50vp"

ohos:right_padding= "50vp"

ohos:layout_alignment= "horizontal_center"

ohos:top_margin= "30vp"

/>

DirectionalLayout>

ability_migration_back.xml 比 ability_migration.xml 多一个迁回按钮,另外主页上点击按钮跳转等,略...

②使用分布式能力要求开发者在 Ability 对应的 config.json 中声明多设备协同访问的权限:

三方应用部署权限、分布式数据传输的权限、系统应用使用权限的申请:

{

"reqPermissions": [

{ "name": "ohos.permission.DISTRIBUTED_DATASYNC"},

{ "name": "ohos.permission.servicebus.ACCESS_SERVICE"},

{ "name": "com.huawei.hwddmp.servicebus.BIND_SERVICE"}

]

}

声明分布式获取设备列表及设备信息的权限,如下所示:

{

"reqPermissions": [

{ "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"},

{ "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"},

{ "name": "ohos.permission.GET_BUNDLE_INFO"}

]

}

对于三方应用还要求在实现 Ability 的代码中显式声明需要使用的权限。

publicclassSampleSliceextendsAbilitySliceimplementsIAbilityContinuation{

@Override

publicvoidonStart(Intent intent){

// 开发者显示声明需要使用的权限

requestPermissionsFromUser( newString[]{ "ohos.permission.DISTRIBUTED_DATASYNC",

"ohos.permission.servicebus.ACCESS_SERVICE",

"com.huawei.hwddmp.servicebus.BIND_SERVICE"}, 0);

super.onStart(intent);

}

}

③为启动远程 FA 的按钮添加点击事件,获取设备信息,实现启动远程 FA 的能力。

Button btn1 = (Button) findComponentById(ResourceTable.Id_migration_btn_01);

btn1.setClickedListener( newComponent.ClickedListener {

@Override

public voidonClick(Component component) {

// 调用DeviceManager的getDeviceList接口,通过FLAG_GET_ONLINE_DEVICE标记获得在线设备列表

List onlineDevices = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);

// 判断组网设备是否为空

if(onlineDevices.isEmpty) {

return;

}

intnumDevices = onlineDevices.size;

ArrayList< String> deviceIds = newArrayList<>(numDevices);

ArrayList< String> deviceNames = newArrayList<>(numDevices);

onlineDevices.forEach((device) -> {

deviceIds.add(device.getDeviceId);

deviceNames.add(device.getDeviceName);

});

// 我们这里只有两个设备,所以选择首个设备作为目标设备

// 开发者也可按照具体场景,通过别的方式进行设备选择

StringselectDeviceId = deviceIds. get( 0);

//获取设备ID,最好放到工具类里,很多地方要用!

if(selectDeviceId!= null){

Intent intent2 = newIntent;

Operation operation = newIntent.OperationBuilder

.withDeviceId(selectDeviceId)

.withBundleName( "cn.ybzy.hmsdemo")

.withAbilityName( "cn.ybzy.hmsdemo.RemoteAbility")

.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)

.build;

intent2.setOperation(operation);

// 通过AbilitySlice包含的startAbility接口实现跨设备启动FA

startAbility(intent2);

}

}

});

06

实现业务在设备间无缝迁移

实战将设备 A 运行时的 FA 迁移到设备 B,实现业务在设备间无缝迁移。

MigrationAbility:

publicclassMigrationAbilityextendsAbilityimplementsIAbilityContinuation{

@Override

publicvoidonStart(Intent intent){

super.onStart(intent);

super.setMainRoute(MigrationAbilitySlice.class.getName);

}

@Override

publicbooleanonStartContinuation{

returntrue;

}

@Override

publicbooleanonSaveData(IntentParams intentParams){

returntrue;

}

@Override

publicbooleanonRestoreData(IntentParams intentParams){

returntrue;

}

@Override

publicvoidonCompleteContinuation( inti){

}

}

MigrationAbilitySlice:

publicclassMigrationAbilitySliceextendsAbilitySliceimplementsIAbilityContinuation{

TextField textField;

String textStr = "请输入数据...";

@Override

publicvoidonStart(Intent intent){

super.onStart(intent);

super.setUIContent(ResourceTable.Layout_ability_migration);

textField = (TextField)findComponentById(ResourceTable.Id_textfield_migration);

textField.setText(textStr);

Button btn = (Button) findComponentById(ResourceTable.Id_migration_button);

btn.setClickedListener( newComponent.ClickedListener {

@Override

publicvoidonClick(Component component){

String deviceId = getDeviceId;

if(deviceId!= null){

continueAbility(deviceId);

}

}

});

}

privateString getDeviceId{

// 调用DeviceManager的getDeviceList接口,通过FLAG_GET_ONLINE_DEVICE标记获得在线设备列表

List onlineDevices = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);

// 判断组网设备是否为空

if(onlineDevices.isEmpty) {

returnnull;

}

intnumDevices = onlineDevices.size;

ArrayList deviceIds = newArrayList<>(numDevices);

ArrayList deviceNames = newArrayList<>(numDevices);

onlineDevices.forEach((device) -> {

deviceIds.add(device.getDeviceId);

deviceNames.add(device.getDeviceName);

});

// 我们这里只有两个设备,所以选择首个设备作为目标设备

// 开发者也可按照具体场景,通过别的方式进行设备选择

String selectDeviceId = deviceIds.get( 0);

returnselectDeviceId;

}

@Override

publicbooleanonStartContinuation{

returntrue;

}

@Override

publicbooleanonSaveData(IntentParams intentParams){

intentParams.setParam( "data",textField.getText);

returntrue;

}

@Override

publicbooleanonRestoreData(IntentParams intentParams){

textStr = intentParams.getParam( "data").toString;

returntrue;

}

@Override

publicvoidonCompleteContinuation( inti){

}

@Override

publicvoidonRemoteTerminated{

}

}

此外,不同于启动行为,FA 的迁移还涉及到状态数据的传递。为此,继承的 IAbilityContinuation 接口为开发者提供迁移过程中特定事件的管理能力。通过自定义迁移事件相关的行为,最终实现对 Ability 的迁移。

主要以较为常用的两个事件,包括迁移发起端完成迁移的回调 onCompleteContinuation(int result) 以及接收到远端迁移行为传递数据的回调 onRestoreData(IntentParams restoreData)。

其他还包括迁移到远端设备的 FA 关闭的回调 onRemoteTerminated、用于本地迁移发起时保存状态数据的回调 onSaveData(IntentParams saveData)和本地发起迁移的回调 onStartContinuation。

07

请求回迁

Button btn1 = (Button) findComponentById(ResourceTable.Id_migration_button_back);

btn1.setClickedListener( newComponent.ClickedListener {

@Override

publicvoidonClick(Component component){

String deviceId = DeviceUtils.getDeviceId;

if(deviceId!= null){

continueAbilityReversibly(deviceId); //可撤回迁移

}

}

});

Button btn2 = (Button) findComponentById(ResourceTable.Id_migration_button_back2);

btn2.setClickedListener( newComponent.ClickedListener {

@Override

publicvoidonClick(Component component){

reverseContinueAbility; //撤回迁移

}

});

①设备 A 上的 Page 请求回迁。

②系统回调设备 B 上 Page 及其 AbilitySlice 栈中所有 AbilitySlice 实例的 IAbilityContinuation.onStartContinuation 方法,以确认当前是否可以立即迁移。

③如果可以立即迁移,则系统回调设备 B 上 Page 及其 AbilitySlice 栈中所有 AbilitySlice 实例的 IAbilityContinuation.onSaveData 方法,以便保存回迁后恢复状态必须的数据。

④如果保存数据成功,则系统在设备 A 上 Page 恢复 AbilitySlice 栈,然后回调 IAbilityContinuation.onRestoreData 方法,传递此前保存的数据。

⑤如果数据恢复成功,则系统终止设备 B 上 Page 的生命周期。

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值