HarmonyOS跨端迁移开发代码演示
目录
- 说些废话
- 开源代码
- 环境
- 代码
-
- ability_main.xml
- config.json
- MainAbility.java
- MainAbilitySlice.java
- 测试
说些废话
官方文档:跨端迁移开发指导(基于java开发)
下面环境里写的两台真机我测试的时候无法正常产生回迁效果,所以实际上我是用的远程模拟器操作成功的,但是我懒得删我的设备信息了。
模拟器不需要登录华为账号,但是需要在 设置-超级终端-允许被发现 处打开能够被附近设备发现。
开源代码
CrossSiteMigration
环境
HUAWEI MatePad Pro 10.8英寸 2019款
Mate 10 Pro 全网通版
DevEco Studio 3.0.0.993 Release
SDK 6(使用java)
我看的《公共事件开发指导》更新于2022-10-28 18:02
代码
ability_main.xml
<DirectionalLayout xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:height="match_parent" ohos:width="match_parent" ohos:alignment="center" ohos:orientation="vertical"> <Text ohos:id="$+id:text_register" ohos:height="match_content" ohos:width="match_content" ohos:layout_alignment="horizontal_center" ohos:text="注册流转服务" ohos:text_size="40vp" /> <Text ohos:id="$+id:text_show" ohos:height="match_content" ohos:width="match_content" ohos:layout_alignment="horizontal_center" ohos:text="列出可流转的设备" ohos:scrollable="true" ohos:text_size="40vp" /> <Text ohos:id="$+id:text_startMigration" ohos:height="match_content" ohos:width="match_content" ohos:layout_alignment="horizontal_center" ohos:text="开始迁移" ohos:scrollable="true" ohos:text_size="40vp" /> <Text ohos:id="$+id:text_showParams" ohos:height="match_content" ohos:width="match_content" ohos:layout_alignment="horizontal_center" ohos:text="这里展示数据:无" ohos:scrollable="true" ohos:text_size="40vp" /> <Text ohos:id="$+id:text_returnMigration" ohos:height="match_content" ohos:width="match_content" ohos:layout_alignment="horizontal_center" ohos:text="迁移回去" ohos:scrollable="true" ohos:text_size="40vp" /></DirectionalLayout>
config.json
长度问题只放module部分。
"module": { "package": "com.openvalley.cyj.migration", "name": ".MyApplication", "mainAbility": "com.openvalley.cyj.migration.MainAbility", "deviceType": [ "phone", "tablet" ], "distro": { "deliveryWithInstall": true, "moduleName": "entry", "moduleType": "entry", "installationFree": false }, "abilities": [ { "skills": [ { "entities": ["entity.system.home" ], "actions": ["action.system.home" ] } ], "name": "com.openvalley.cyj.migration.MainAbility", "description": "$string:mainability_description", "icon": "$media:icon", "label": "$string:entry_MainAbility", "launchType": "standard", "orientation": "unspecified", "visible": true, "type": "page" } ], "reqPermissions": [ { "name": "ohos.permission.DISTRIBUTED_DATASYNC" } ] }
MainAbility.java
package com.openvalley.cyj.migration;import com.openvalley.cyj.migration.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.hiviewdfx.HiLog;import ohos.hiviewdfx.HiLogLabel;import ohos.security.SystemPermission;public class MainAbility extends Ability implements IAbilityContinuation { private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00001, MainAbility.class.getSimpleName()); @Override public void onStart(Intent intent) { super.onStart(intent); super.setMainRoute(MainAbilitySlice.class.getName()); verifyAndRequestSelfPermission(); } / * 在此处验证和请求用户权限 */ private void verifyAndRequestSelfPermission() { try{ //返回值0有,-1没有 if(verifyCallingOrSelfPermission(SystemPermission.DISTRIBUTED_DATASYNC) == IBundleManager.PERMISSION_GRANTED){// if(verifySelfPermission(SystemPermission.LOCATION) == IBundleManager.PERMISSION_GRANTED){ //如果有权限 }else { //如果没授权就看这个权限能否动态授权 if(canRequestPermission(SystemPermission.DISTRIBUTED_DATASYNC)){ //如果可以弹窗授权 requestPermissionsFromUser(new String[] {SystemPermission.DISTRIBUTED_DATASYNC}, 0x10001); }else { //如果不能动态授权 return ; } } }catch (Exception e){ e.printStackTrace(); } } / * 授权的回调 * @param requestCode * @param permissions * @param grantResults */ @Override public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults); if(requestCode == 0x10001){ if(grantResults[0] == IBundleManager.PERMISSION_GRANTED){ //如果授权成功(0) HiLog.info(LABEL_LOG, permissions[0] + "权限授权成功。"); }else { //如果没有授权成功(-1) return ; } } } / * 准备开始迁移的回调 * @return */ @Override public boolean onStartContinuation() { //返回值为true才发起迁移 HiLog.info(LABEL_LOG, "MainAbility onStartContinuation"); return true; } / * 当保存数据(要迁移的数据)的回调 * @param intentParams * @return */ @Override public boolean onSaveData(IntentParams intentParams) { HiLog.info(LABEL_LOG, "MainAbility onSaveData"); return true; } / * 当恢复数据的回调(应该是被迁移的设备调用 * @param intentParams * @return */ @Override public boolean onRestoreData(IntentParams intentParams) { //返回为true代表恢复数据成功 HiLog.info(LABEL_LOG, "MainAbility onRestoreData"); return true; } / * 迁移完成的回调 * @param i */ @Override public void onCompleteContinuation(int i) { HiLog.info(LABEL_LOG, " MainAbility onCompleteContinuation"); } / * 迁移过程中失败的回调 */ @Override public void onRemoteTerminated() { IAbilityContinuation.super.onRemoteTerminated(); HiLog.info(LABEL_LOG, "MainAbility onRemoteTerminated"); } / * 回迁允许的情况下,远端中断 * @param errorCode */ @Override public void onFailedContinuation(int errorCode) { IAbilityContinuation.super.onFailedContinuation(errorCode); HiLog.info(LABEL_LOG, "MainAbility onFailedContinuation"); }}
MainAbilitySlice.java
package com.openvalley.cyj.migration.slice;import com.openvalley.cyj.migration.ResourceTable;import ohos.aafwk.ability.AbilitySlice;import ohos.aafwk.ability.IAbilityContinuation;import ohos.aafwk.ability.continuation.*;import ohos.aafwk.content.Intent;import ohos.aafwk.content.IntentParams;import ohos.agp.components.Text;import ohos.hiviewdfx.HiLog;import ohos.hiviewdfx.HiLogLabel;public class MainAbilitySlice extends AbilitySlice implements IAbilityContinuation { private static final HiLogLabel LABEL_LOG = new HiLogLabel(HiLog.LOG_APP, 0x00001, MainAbilitySlice.class.getSimpleName()); Text text_register = null; Text text_show = null; Text text_startMigration = null; Text text_showParams = null; Text text_returnMigration = null; IContinuationRegisterManager continuationRegisterManager = null; IContinuationDeviceCallback continuationDeviceCallback = null; RequestCallback requestCallback = null; String jsonParams = null; int abilityToken = 0; String deviceId = null; String params = null; boolean isMigration = false; @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); initContinuationRegisterManager(); initComponent(); } / * 初始化注册管理类 */ private void initContinuationRegisterManager(){continuationRegisterManager = getContinuationRegisterManager();//设备的回调(是在列出了设备列表后,选择某个设备进行流转连接成功或者断开时调用)continuationDeviceCallback = new IContinuationDeviceCallback() { @Override public void onConnected(ContinuationDeviceInfo deviceInfo) { HiLog.info(LABEL_LOG, "onConnected()"); deviceId = deviceInfo.getDeviceId(); HiLog.info(LABEL_LOG, "onConnected() 连接成功。 deviceId = " + deviceId); continuationRegisterManager.updateConnectStatus(abilityToken, deviceId, DeviceConnectState.CONNECTED.getState(), requestCallback); } @Override public void onDeviceConnectDone(String s, String s1) { HiLog.info(LABEL_LOG, "onDeviceConnectDone()"); } @Override public void onDisconnected(String deviceId) { HiLog.info(LABEL_LOG, "onDisconnected()"); } @Override public void onDeviceDisconnectDone(String s) { HiLog.info(LABEL_LOG, "onDeviceDisconnectDone()"); }};//请求的回调(注册到服务中心成功) requestCallback = new RequestCallback() { @Override public void onResult(int i) { if(i > 0){ //为了保证更新数据时这个值还在,所以在if里写 abilityToken = i; HiLog.info(LABEL_LOG, "onResult() 注册成功。 abilityToken = " + abilityToken); }else { HiLog.info(LABEL_LOG, "onResult() 其他操作。 abilityToken = " + i); } } }; } / * 初始化组件 */ private void initComponent(){ text_register = (Text)findComponentById(ResourceTable.Id_text_register); text_register.setClickedListener(listen -> register()); text_show = (Text)findComponentById(ResourceTable.Id_text_show); text_show.setClickedListener(listen -> show()); text_startMigration = (Text)findComponentById(ResourceTable.Id_text_startMigration); text_startMigration.setClickedListener(listen -> startMigration()); text_showParams = (Text)findComponentById(ResourceTable.Id_text_showParams); text_showParams.setText("这里展示数据:" + params); text_returnMigration = (Text)findComponentById(ResourceTable.Id_text_returnMigration); text_returnMigration.setClickedListener(listen -> returnMigration()); } / * 点击按钮进行流转服务注册 */ private void register(){ if(continuationRegisterManager != null){ HiLog.info(LABEL_LOG, "register() 开始注册。"); continuationRegisterManager.register(getBundleName(), getExtraParams(), continuationDeviceCallback, requestCallback); } } / * 展示可流转的设备 */ private void show(){ if(continuationRegisterManager != null && abilityToken > 0){ continuationRegisterManager.showDeviceList(abilityToken, getExtraParams(), requestCallback); } } / * 开始迁移 */ private void startMigration(){ if(continuationRegisterManager != null && deviceId != null){ HiLog.info(LABEL_LOG, "startMigration() 开始迁移。");// continueAbility(deviceId); continueAbilityReversibly(deviceId); isMigration = true; HiLog.info(LABEL_LOG, "startMigration() 迁移结束。"); //如果是不回迁的,这边的页面就可以销毁掉// terminateAbility(); } } / * 迁移回原设备 */ private void returnMigration(){// ContinuationState. try{ boolean reverseContinueAbility = reverseContinueAbility(); HiLog.info(LABEL_LOG, "reverseContinueAbility = " + reverseContinueAbility); isMigration = false; }catch (Exception e){ HiLog.info(LABEL_LOG, "e = " + e.getMessage()); } } / * 获得注册时 额外的一些参数 * @return */ private ExtraParams getExtraParams(){ ExtraParams extraParams = new ExtraParams(); String[] devType = {ExtraParams.DEVICETYPE_SMART_PHONE, ExtraParams.DEVICETYPE_SMART_PAD}; //显示的列表包含那些设备类型 extraParams.setDevType(devType); //添加描述(没出来) extraParams.setDescription("这是一个描述。"); //如果不写,就会默认以注册时的BundleName作为targetBundleName extraParams.setTargetBundleName(getBundleName()); //设备过滤 jsonParams = "\"{" + "\"filter\":{" +"\"commonFilter\":{" + "\"system\":{" + //目标设备对应的HarmonyOS版本 要≥ "\"harmonyVersion\":\"2.0.0\"" + "}," +// "}" + //1为同账号,1|256为不同账号 "\"groupType\":\"1|256\"," + //0x00000004需要在同一局域网下,0x00030004不需要在同一局域网下 "\"curComType\": 0x00030004," + //为空就不做版本兼容性检查,要做版本兼容性检查时,需要传入目标应用包名。 "\"faFilter\":\"{" + "\"targetBundleName\":\"com.openvalley.cyj.migration\"" + "}\"" +"}" + "}," + "\"transferScene\":0," + "\"remoteAuthenticationDescription\": \"拉起HiVision扫描弹框描述\"" + "}\"";// HiLog.info(LABEL_LOG, jsonParams); extraParams.setJsonParams(jsonParams); return extraParams; } @Override public void onActive() { super.onActive(); } @Override public void onForeground(Intent intent) { super.onForeground(intent); } @Override protected void onStop() { if(continuationRegisterManager != null && abilityToken > 0){ continuationRegisterManager.unregister(abilityToken, requestCallback); } } / * 准备开始迁移的回调 * @return */ @Override public boolean onStartContinuation() { //返回值为true才发起迁移 HiLog.info(LABEL_LOG, "MainAbilitySlice onStartContinuation"); return true; } / * 当保存数据(要迁移的数据)的回调 * @param intentParams * @return */ @Override public boolean onSaveData(IntentParams intentParams) { HiLog.info(LABEL_LOG, "MainAbilitySlice onSaveData"); intentParams.setParam("userName", "陈依劼"); return true; } / * 当恢复数据的回调(应该是被迁移的设备调用 * @param intentParams * @return */ @Override public boolean onRestoreData(IntentParams intentParams) { //返回为true代表恢复数据成功 HiLog.info(LABEL_LOG, "MainAbilitySlice onRestoreData"); Object userName = intentParams.getParam("userName"); if(userName != null){ params = (String)userName; } return true; } / * 迁移完成的回调 * @param i */ @Override public void onCompleteContinuation(int i) { HiLog.info(LABEL_LOG, "MainAbilitySlice onCompleteContinuation"); } / * 迁移过程中失败的回调 */ @Override public void onRemoteTerminated() { HiLog.info(LABEL_LOG, "MainAbilitySlice onRemoteTerminated"); } / * 回迁允许的情况下,远端中断 * @param errorCode */ @Override public void onFailedContinuation(int errorCode) { IAbilityContinuation.super.onFailedContinuation(errorCode); HiLog.info(LABEL_LOG, "MainAbilitySlice onFailedContinuation"); }}
测试
注意要先把想迁移到的设备的上的程序先授权。