当前位置: 首页 > 科技观察

【鸿蒙基地】Harmonyos跨设备启动窗口:PageAbility

时间:2023-03-20 12:01:21 科技观察

更多信息请访问:与华为官方共建的Harmonyos技术社区https://harmonyos.51cto.com/#zzHarmonyOS核心特性(卖点之一points)是软总线技术,PageAbility的跨设备迁移是软总线的具体技术实现。所谓PageAbility的跨设备迁移,是指DeviceA中的特定App调用DeviceB中的App的PageAbility,这是有前提的,即A设备和B设备都安装了同一个App。如果B设备上没有安装该App,B设备会自动从华为应用商店下载该App。当然,这个过程是完全无声的。下载完成后,会自动激活相应的页面能力。该技术不仅可以启动另一台设备上的PageAbility,还可以向另一台设备上的PageAbility传输数据。该技术的主要应用场景之一是可以将设备A上完成的一半工作迁移到设备B上继续。比如你在家要回平板电脑上的EMail,但有急事需要出门,你可以把平板电脑上写了一半的EMail转移到手机上,剩下的需要自己完成路上的工作。一、跨设备迁移前的准备在进行跨设备迁移之前,需要为HarmonyOS设备做一些准备工作:(1)打开HarmonyOS设备的蓝牙;(2)HarmonyOS设备需要连接Wi-Fi,并且多个HarmonyOS需要在同一网段;(3)多台HarmonyOS设备需要使用同一个华为开发者账号登录,如图1所示。图1使用同一个华为开发者账号登录(4)点击“设置”>“更多连接”>“多设备”collaboration”进入多设备协同窗口,打开多设备协同开关,如图2所示。图2多设备协同(5)修改HarmonyOS设备名称。点击“设置”>“蓝牙”>“设备名称”,进入设备名称窗口,输入新的名称,如图3所示。虽然这一步不是必须的,但是如果你有多台鸿蒙设备,可能很多鸿蒙设备都有相同或相似的名称。为了更好的区分不同的鸿蒙设备,建议修改鸿蒙设备名称。图3修改HarmonyOS设备名称2获取设备列表跨设备迁移使用设备ID来区分不同的设备,因此首先获取所有可用设备的ID。获取设备ID需要调用DeviceManager.getDeviceList方法,该方法返回一个DeviceInfo类型的List对象,用于描述设备的相关信息,包括设备ID和设备名称(设备名称设置在上一节)等,实现代码如下:ListdeviceInfoList=DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);getDeviceList方法有一个参数,是一个int类型的值,表示获取设备处于哪个状态的信息。可以指定的值如下:(1)DeviceInfo.FLAG_GET_ONLINE_DEVICE:获取所有在线设备的信息;(2)DeviceInfo.FLAG_GET_OFFLINE_DEVICE:获取所有离线设备的信息;(3)DeviceInfo.FLAG_GET_ALL_DEVICE:获取所有设备的信息;通常使用第一个值是获取所有在线设备的信息,因为PageAbility只有在设备在线时才能迁移到设备上。下面给出一个案例。这个案例实现了一个通用的PageAbility来显示可用设备的列表。单击设备将返回设备的ID。device_ids.xml布局文件中放置一个ListContainer组件,用于显示和获取。有关所有可用设备的信息。实现代码如下:publicclassDeviceIdsAbilityextendsAbility{//保存获取的所有设备的信息privateListdeviceInfos;privateListContainerlistContainerDeviceIds;//获取所有可用设备的相关信息publicstaticListgetAvailableDeviceIds(){ListdeviceInfoLister.设备getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);if(deviceInfoList==null){returnnewArrayList<>();}if(deviceInfoList.size()==0){returnnewArrayList<>();}returndeviceInfoList;}@OverridepublicvoidonStart(Intentintent){super.onStart(intent);super.setUIContent(ResourceTable.Layout_device_ids);deviceInfos=getAvailableDeviceIds();listContainerDeviceIds=,(ListContainer)findComponentById(ResourceTable.Id_listcontainer_deviceids);if(listContainerDeviceIds!=null){//为ListContainer设置组件项目监听器listContainerDeviceIds.setItemClickedListener(newListContainer.ItemClickedListener(){@OverridepublicvoidonItemClicked(ListContainerlistContainer,Componentcomponent,inti,longl){//当一个列表项(设备)被点击时,会获取设备的ID并将此ID作为PageAbility//StringdeviceId=deviceInfos.get(i).getDeviceId();Intentintent=newIntent();intent.setParam("deviceId",deviceId);setResult(100)的结果返回,intent);//关闭当前PageAbilityterminateAbility();}});//为ListContainer设置ProviderlistContainerDeviceIds.setItemProvider(newRecycleItemProvider(){@OverridepublicintgetCount(){returndeviceInfos.size();}@OverridepublicObjectgetItem(inti){returndevicecomponent.get(i);}@OverridepubliclonggetItemId(inti){returni;}@OverridepublicComponentgetComponent(inti,Componentcomponent,ComponentContainercomponentContainer){if(component==null){//如果component为null,表示没有可用的列表项视图,因此要从布局文件中加载一个新的视图对象//component=(DirectionalLayout)LayoutScatter.getInstance(DeviceIdsAbility.this).parse(ResourceTable.Layout_device_id_item,null,false);}TexttextDeviceName=(Text)component。findComponentById(ResourceTable.Id_text_device_name);TexttextDeviceId=(Text)component.findComponentById(ResourceTable.Id_text_device_id);if(textDeviceName!=null){//显示设备名称textDeviceName.setText(deviceInfos.get(i).getDeviceName());}if(textDeviceId!=null){//显示设备IDtextDeviceId.setText(deviceInfos.get(i).getDeviceId());}returncomponent;}});}}}在DeviceIdsAbility类中为ListContainer组件加载列表项时,getComponent方法中使用第二个参数component,即列表的根视图物品。如果component为null,则表示没有可用的列表项视图,因此需要创建一个新的列表项视图。如果不为null,则表示还可以使用其他未显示的列表项视图,只需要替换该视图的Text组件中显示的信息即可。最后在config.json文件中添加一些分发相关的权限。"reqPermissions":[{"name":"ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"},{"name":"com.huawei.permission.ACCESS_DISTRIBUTED_ABILITY_GROUP"},{"name":"ohos.permission.DISTRIBUTED_DATASYNC"}]运行程序,你会看到如图4所示的设备列表。图4获取可用设备的ID需要注意的是,DeviceManager.getDeviceList方法只能获取其他设备的信息,不能获取自身的信息。例如,有设备A、设备B和设备C,在设备A中,只能获取到设备B和设备C的信息,无法获取到设备A的信息。设备B和设备C中的行为也类似。3根据设备ID调用PageAbility。PageAbility如果要跨设备访问,必须实现IAbilityContinuation接口,否则会抛出异常。该接口中有4个方法必须实现,其含义如下:publicinterfaceIAbilityContinuation{//开始迁移,如果返回true,表示可以开始迁移booleanonStartContinuation();//开始传输数据,如果返回true,表示数据传输成功booleanonSaveData(IntentParamsvar1);//开始恢复数据,如果返回true,表示数据恢复成功booleanonRestoreData(IntentParamsvar1);//PageAbility迁移完成voidonCompleteContinuation(intvar1));}假设PageAbility从设备A迁移到设备B,在设备A调用onStartContinuation方法和onSaveData方法,在设备B调用onRestoreData方法和onCompleteContinuation方法,为了迁移PageAbility,需要在设备A上执行以下代码:continueAbility(deviceId);其中deviceID是设备ID。调用该方法后,A设备上会依次调用onStartContinuation方法和onSaveData方法,B设备上会依次调用onRestoreData方法和onCompleteContinuation方法。onSaveData方法和onRestoreData方法都有一个IntentParams类型的参数,通过它可以通过PageAbility在设备A和设备B之间传递数据(用法类似于Intent)。通常在onRestoreData方法中,恢复PageAbility从设备A迁移到设备B时的数据。下面给出一个实际案例。在PageAbility上放置一个TextField组件,在组件中输入一些文本,然后点击按钮,将PageAbility迁移到另一部HarmonyOS手机上,并恢复迁移状态。数据。实现代码如下:publicclassCrossDevicePageAbilityextendsAbilityimplementsIAbilityContinuation{privateListdeviceInfos;privateListContainerlistContainerDeviceIds;privateTextFieldtextFieldContent;privateStringcontent;//授权方法privatevoidrequestPermission(){//否则Java下面申请权限的PageAbility代码不会响应/传递String[]permission={"ohos.permission.DISTRIBUTED_DATASYNC"};ListapplyPermissions=newArrayList<>();for(Stringelement:permission){//验证是否获得权限if(verifySelfPermission(element)!=0){if(canRequestPermission(element)){//如果没有获取到权限,将权限添加到权限列表applyPermissions.add(element);}else{}}else{}}//申请相应的permissionrequestPermissionsFromUser(applyPermissions.toArray(newString[0]),0);}//要成功跨设备迁移PageAbility,该方法必须返回true@OverridepublicbooleanonStartContinuation(){returntrue;}@OverridepublicbooleanonSaveData(IntentParamsintentParams){//保存要传输的数据intentParams.setParam("content",textFieldContent.getText());returntrue;}@OverridepublicbooleanonRestoreData(IntentParamsintentParams){//获取传入的数据content=String.valueOf(intentParams.getParam("content"));returntrue;}@OverridepublicvoidonCompleteContinuation(inti){}@OverrideprotectedvoidonAbilityResult(intrequestCode,intresultCode,IntentresultData){//之后选择设备,使用返回的设备ID进行迁移PageAbilityif(resultCode==100&&requestCode==99){//获取设备IDStringdeviceId=resultData.getStringParam("deviceId");Tools.showTip(this,deviceId);//交叉-deviceMigratePageAbilitycontinueAbility(deviceId);}}@OverridepublicvoidonStart(Intentintent){super.onStart(intent);super.setUIContent(ResourceTable.Layout_cross_device_page_ability);//申请权限requestPermission();Buttonbutton=(Button)findComponentById(ResourceTable.Id_vdeab_button)if(button!=null){button.setClickedListener(newComponent.ClickedListener(){@OverridepublicvoidonClick(Componentcomponent){//显示列表列表窗口IntentintentPageAbility=newIntent();Operationoperation=newIntent.OperationBuilder().withBundleName("com.unitymarvel.demo").withAbilityName("com.unitymarvel.demo.ability.DeviceIdsAbility").build();intentPageAbility.setOperation(operation);startAbilityForResult(intentPageAbility,99);}});}textFieldContent=(TextField)findComponentById(ResourceTable.Id_textfield_content);if(textFieldContent!=null){//恢复TextField组件中的数据textFieldContent.setText(content);}}}阅读这段代码需要理解以下几点:(1)要成功迁移PageAbility并成功传输数据,onStartContinuation方法、onSaveData方法和onRestoreData方法必须返回true。如果读者使用IDE的自动代码生成功能,这些方法默认会返回false。请将它们的返回值设置为Changeittotrue;(2)HarmonyOS有一些权限。在config.json中声明它们是不够的。您还需要使用Java代码来申请。例如跨设备迁移PageAbility,需要使用Java代码申请ohos.permission。DISTRIBUTED_DATASYNC权限。如果是第一次申请,会弹出如图5所示的授权对话框,点击“AlwaysAllow”按钮关闭对话框,第二次申请权限不会弹出对话框;(3)因为onRestoreData方法是在onStart方法之前调用的,所以在onRestoreData方法中不能直接使用组件对象,因为组件对象通常是在onStart方法中创建的。所以当调用onRestoreData方法时,这些组件对象还是空的。正确的做法是在onRestoreData方法中将需要恢复的数据保存到成员变量中,然后在onStart方法中创建组件对象后使用这些变量恢复组件中的数据。(4)本例考虑多台HarmonyOS设备的迁移,所以用到上一节写的设备列表窗口。在开始跨设备迁移PageAbility之前,会弹出一个设备列表窗口。当用户选择一个设备时,会返回设备的ID,然后在onAbilityResult方法中获取返回的设备ID,最后使用continueAbility方法迁移PageAbility。;图5授权对话框现在运行程序,关闭授权对话框,在TextField组件中输入一些内容,最后点击“跨设备迁移页面能力”按钮,会弹出一个设备列表窗口。在选择的设备上弹出相同的PageAbility,TextField组件的数据与原设备上的完全一致,如图6所示。注意,只要被调用方安装了App,迁移后的App无论设备是否启动了App,PageAbility都会自动弹出。图6页面能力跨设备迁移效果/974126.html?版权归作者及鸿蒙技术社区所有。如需转载,请注明出处,否则将追究法律责任。更多信息请访问:与华为共建HarmonyOS技术社区https://harmonyos.51cto.com/#zz