HarmonyOS流转之跨端迁移

想了解更多内容,跨端请访问:

和华为官方合作共建的迁移鸿蒙技术社区

https://harmonyos.51cto.com

前言

流转在HarmonyOS中泛指多设备分布式操作,也是跨端HarmonyOS的亮点之一。流转按体验可以分为跨端迁移和多端协同,迁移这里主要跟大家讲一下如何进行跨端迁移,跨端以及我在项目开发过程中,迁移所遇到的跨端问题与解决方法。

具体概念这里就不做过多的迁移赘述了,大家可以查阅官方文档。跨端

开发步骤

在开发过程中,迁移我们可以根据业务需求分为以下两种场景:

同个FA之间的跨端迁移(Ability1—Ability1); 不同FA之间的迁移(Ability1—Ability2)。

下面给大家介绍一下以上两种场景的迁移具体的开发步骤。

同个FA之间的跨端迁移

同个FA之间的迁移是指不同设备端安装了同个FA,官方文档已经有比较详细的迁移开发步骤,下面只给大家讲一下需要注意的跨端事项及我所遇到的问题避免大家踩坑。

1.我们在创建完一个FA之后,因为我们大部门的业务逻辑都是在AbilitySlice,云服务器提供商所以我们在Ability及AbilitySlice都要去实现IAbilityContinuation 接口,并且将Ability中实现的onStartContinuation()、onSaveData(IntentParams intentParams)、onRestoreData(IntentParams intentParams)的返回值,都设为true。

public class MainAbility extends Ability implements IAbilityContinuation {      @Override     public boolean onStartContinuation() {          return true;     }     @Override     public boolean onSaveData(IntentParams intentParams) {          return true;     }     @Override     public boolean onRestoreData(IntentParams intentParams) {          return true;     }     //省略部分代码     ... } 

 2.在对应的FA模块的config.json中,配置对应的权限,且在代码中也需要动态申请。

"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"} ]  if (canRequestPermission(SystemPermission.DISTRIBUTED_DATASYNC)) {      // 是否可以申请弹框授权(首次申请或者用户未选择禁止且不再提示)     requestPermissionsFromUser(             new String[]{ SystemPermission.DISTRIBUTED_DATASYNC}, PERMISSIONS_REQUEST_DISTRIBUTED); } 

3.定义相关参数、设置流转任务管理服务回调函数、注册流转任务管理服务、管理流转的目标设备,同时需要在流转结束时解注册流转任务管理服务。

// 流转应用包名    private String BUNDLE_NAME = "XXX.XXX.XXX";     // 注册流转任务管理服务后返回的Ability token    private int abilityToken;     // 用户在设备列表中选择设备后返回的设备ID    private String selectDeviceId;    // 获取流转任务管理服务管理类    private IContinuationRegisterManager continuationRegisterManager; // 设置流转任务管理服务设备状态变更的回调 private IContinuationDeviceCallback continuationDeviceCallback = new IContinuationDeviceCallback() {     @Override    public void onDeviceConnectDone(String deviceId, String deviceType) {         selectDeviceId = deviceId;        continuationRegisterManager.updateConnectStatus(abilityToken, selectDeviceId, DeviceConnectState.CONNECTING.getState(), null);     ...    }    @Override    public void onDeviceDisconnectDone(String s) {         getUITaskDispatcher().asyncDispatch(() -> {             continuationRegisterManager.updateConnectStatus(abilityToken, selectDeviceId, DeviceConnectState.DIS_CONNECTING.getState(), null);        });        unRegisterContinuation();    } ;  // 设置注册流转任务管理服务回调    private RequestCallback requestCallback = new RequestCallback() {         @Override        public void onResult(int result) {             abilityToken = result;        }    };    ...    @Override    public void onStart(Intent intent) {         ...        continuationRegisterManager = getContinuationRegisterManager();    }    @Override    public void onStop() {         super.onStop();        // 解注册流转任务管理服务        continuationRegisterManager.unregister(abilityToken, null);        // 断开流转任务管理服务连接        continuationRegisterManager.disconnect();    } 

 在Api5的时候IContinuationDeviceCallback的回调接口跟官方文档有些出入,当你选择设备后会在onDeviceConnectDone返回你所选择的设备ID及设备类型。

4.注册流转服务之后我们便可以调起系统流转选择设备弹窗,可以通过ExtraParams对设备进行过滤,如不需要过滤,可不传。

ExtraParams params = new ExtraParams(); String[] devTypes = new String[]{ ExtraParams.DEVICETYPE_SMART_PHONE, ExtraParams.DEVICETYPE_SMART_WATCH, ExtraParams.DEVICETYPE_SMART_PAD}; params.setDevType(devTypes); registerContinuation(); // 显示选择设备列表 continuationRegisterManager.showDeviceList(abilityToken, params, new RequestCallback() {      @Override     public void onResult(int result) {      } }); 

 5.选择完设备之后会通过上述的亿华云IContinuationDeviceCallback的onDeviceConnectDone方法进行回调,之后通过continueAbility方法传入目标设备的DeviceID,将运行的FA迁移到目标设备,实现业务在设备间无缝迁移。

// 设置流转任务管理服务设备状态变更的回调 private IContinuationDeviceCallback continuationDeviceCallback = new IContinuationDeviceCallback() {      @Override     public void onDeviceConnectDone(String deviceId, String deviceType) {          selectDeviceId = deviceId;         getUITaskDispatcher().asyncDispatch(() -> {              continuationRegisterManager.updateConnectStatus(abilityToken, selectDeviceId, DeviceConnectState.CONNECTING.getState(), null);         });         if (selectDeviceId != null) {              continueAbility(selectDeviceId);         }         ...     }     @Override     public void onDeviceDisconnectDone(String s) {          ...         unRegisterContinuation();     } }; 

 6.在FA迁移中我觉得最主要的部分就是状态和数据的传递,要让用户体验到”无缝“的用户体验,需要通过实现IAbilityContinuation接口来实现数据的传递,主要代码如下:

@Override public boolean onSaveData(IntentParams saveData) {        //根据业务需求,在这里去设置需要传递的数据       saveData.setParam("continueParam", continueParam);       return true;  } @Override public boolean onRestoreData(IntentParams restoreData) {        // 远端FA迁移传来的状态数据,开发者可以按照自身业务对这些数据进行处理       Object data = restoreData.getParam("continueParam");       getUITaskDispatcher().asyncDispatch(() -> {          });       return true;  } 

 需要注意的是,在onRestoreData处理数据更新UI的时候,需要在UI线程中去更新,否则会报错。

不同FA之间的迁移

在实际开发中可能会因为设备端的部分需求、UI的不同,例如车机、云南idc服务商手机、手表,从而开发了不同的FA。不同FA之间的迁移几乎与同个FA之间迁移配置一致,只是我们的AbilitySlice不需要再实现IAbilityContinuation接口来实现数据的同步,而是通过Intent,具体实现如下。

1.首先,我们先在选择设备成功后的回调IContinuationDeviceCallback初始化分布式环境。

// 设置流转任务管理服务设备状态变更的回调 private IContinuationDeviceCallback continuationDeviceCallback = new IContinuationDeviceCallback() {      @Override     public void onDeviceConnectDone(String deviceId, String deviceType) {          selectDeviceId = deviceId;         //省略部分代码         ...         try {              // 初始化分布式环境             DeviceManager.initDistributedEnvironment(selectDeviceId, new IInitCallback() {                  @Override                 public void onInitSuccess(String success) {                  }                 @Override                 public void onInitFailure(String failure, int result) {                  }             });         } catch (RemoteException e) {              e.printStackTrace();         }        ...     }   .... }; 

2.之前,我们是通过continueAbility()方法进行跳转,而现在我们需要通过Intent方法进行跳转。

Intent intent = new Intent(); Operation operation = new Intent.OperationBuilder()         .withDeviceId(deviceId)         .withBundleName(bundleName)         .withAbilityName(abilityName)         .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)         .build(); intent.setOperation(operation); IntentParams intentParams = new IntentParams(); //通过IntentParams传递参数 ... startAbility(intent); 

 在接收方,我们可以通过onStart(Intent intent)方法接受传递过来的参数,再根据自己的业务逻辑实现数据同步。

自定义设备选择弹窗

在实际项目开发中我们也可以自定义流转弹窗样式,但并不推荐这种方式,经测试发现只有在两个设备通过蓝牙连接的时候才能获取到设备列表,只有在特定的场景,例如手机与车机、手机与手表在实际使用过程中我们基本上是会保持蓝牙连接的,通过这种方式实现流转会更稳定。但如果不能保持蓝牙实时连接的场景则不推荐。

1.官方API提供了DeviceManager.getDeviceList()来获取远端设备,具体代码如下:

public static List<DeviceInfo> getDeviceList() {      // 调用DeviceManager的getDeviceList接口,通过FLAG_GET_ONLINE_DEVICE标记获得在线设备列表     List<DeviceInfo> onlineDevices = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);     // 判断组网设备是否为空     if (onlineDevices == null) {          LogUtil.e(TAG, "online devices is null");         return new ArrayList<>();     }     return onlineDevices; } 

 2.获取到设备列表后,我们就可以自行实现页面了,在上述的showDeviceList()弹出设备列表的位置替换成自己的弹窗即可。

效果展示

结语

目前在DevEco Studio 2.1 Release以上版本已经支持跨端迁移的模拟器了,如果没有显示出来可以在Settings-DevEco Labs 勾选Enable Super Device。

文章相关附件可以点击下面的原文链接前往下载:

https://harmonyos.51cto.com/resource/1426

想了解更多内容,请访问:

和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

系统运维
上一篇:对数据中心停机说不,谈谈施耐德电气UPS产品的创新技术
下一篇:戴尔科技人工智能方案 助力企业加速AI技术研究