流轉(zhuǎn)在 HarmonyOS 中泛指多設(shè)備分布式操作,也是 HarmonyOS 的亮點(diǎn)之一。
流轉(zhuǎn)按體驗(yàn)可以分為跨端遷移和多端協(xié)同,這里主要跟大家講一下如何進(jìn)行跨端遷移,以及我在項(xiàng)目開(kāi)發(fā)過(guò)程中,所遇到的問(wèn)題與解決方法。
具體概念這里就不做過(guò)多的贅述了,大家可以查閱官方文檔:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/hop-overview-0000001092995092
開(kāi)發(fā)步驟
在開(kāi)發(fā)過(guò)程中,我們可以根據(jù)業(yè)務(wù)需求分為以下兩種場(chǎng)景:
-
同個(gè) FA 之間的遷移(Ability1—Ability1)
-
不同 FA 之間的遷移(Ability1—Ability2)
下面給大家介紹一下以上兩種場(chǎng)景的具體的開(kāi)發(fā)步驟。 ①同個(gè) FA 之間的遷移
同個(gè) FA 之間的遷移是指不同設(shè)備端安裝了同個(gè) FA,官方文檔已經(jīng)有比較詳細(xì)的開(kāi)發(fā)步驟,下面只給大家講一下需要注意的事項(xiàng)及我所遇到的問(wèn)題避免大家踩坑。
我們?cè)趧?chuàng)建完一個(gè) FA 之后,因?yàn)槲覀兇蟛块T(mén)的業(yè)務(wù)邏輯都是在 AbilitySlice,所以我們?cè)?Ability 及 AbilitySlice 都要去實(shí)現(xiàn) IAbilityContinuation 接口。
并且將 Ability 中實(shí)現(xiàn)的 onStartContinuation()、onSaveData(IntentParams intentParams)、onRestoreData(IntentParams intentParams)的返回值,都設(shè)為 true。
publicclassMainAbilityextendsAbilityimplementsIAbilityContinuation{
@Override
publicbooleanonStartContinuation(){
returntrue;
}
@Override
publicbooleanonSaveData(IntentParamsintentParams){
returntrue;
}
@Override
publicbooleanonRestoreData(IntentParamsintentParams){
returntrue;
}
//省略部分代碼
...
}
在對(duì)應(yīng)的 FA 模塊的 config.json 中,配置對(duì)應(yīng)的權(quán)限,且在代碼中也需要?jiǎng)討B(tài)申請(qǐng)。
"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)){
//是否可以申請(qǐng)彈框授權(quán)(首次申請(qǐng)或者用戶(hù)未選擇禁止且不再提示)
requestPermissionsFromUser(
newString[]{SystemPermission.DISTRIBUTED_DATASYNC},PERMISSIONS_REQUEST_DISTRIBUTED);
}
定義相關(guān)參數(shù)、設(shè)置流轉(zhuǎn)任務(wù)管理服務(wù)回調(diào)函數(shù)、注冊(cè)流轉(zhuǎn)任務(wù)管理服務(wù)、管理流轉(zhuǎn)的目標(biāo)設(shè)備,同時(shí)需要在流轉(zhuǎn)結(jié)束時(shí)解注冊(cè)流轉(zhuǎn)任務(wù)管理服務(wù)。
//流轉(zhuǎn)應(yīng)用包名
privateStringBUNDLE_NAME="XXX.XXX.XXX";
//注冊(cè)流轉(zhuǎn)任務(wù)管理服務(wù)后返回的Abilitytoken
privateintabilityToken;
//用戶(hù)在設(shè)備列表中選擇設(shè)備后返回的設(shè)備ID
privateStringselectDeviceId;
//獲取流轉(zhuǎn)任務(wù)管理服務(wù)管理類(lèi)
privateIContinuationRegisterManagercontinuationRegisterManager;
//設(shè)置流轉(zhuǎn)任務(wù)管理服務(wù)設(shè)備狀態(tài)變更的回調(diào)
privateIContinuationDeviceCallbackcontinuationDeviceCallback=newIContinuationDeviceCallback(){
@Override
publicvoidonDeviceConnectDone(StringdeviceId,StringdeviceType){
selectDeviceId=deviceId;
continuationRegisterManager.updateConnectStatus(abilityToken,selectDeviceId,DeviceConnectState.CONNECTING.getState(),null);
...
}
@Override
publicvoidonDeviceDisconnectDone(Strings){
getUITaskDispatcher().asyncDispatch(()->{
continuationRegisterManager.updateConnectStatus(abilityToken,selectDeviceId,DeviceConnectState.DIS_CONNECTING.getState(),null);
});
unRegisterContinuation();
}
};
//設(shè)置注冊(cè)流轉(zhuǎn)任務(wù)管理服務(wù)回調(diào)
privateRequestCallbackrequestCallback=newRequestCallback(){
@Override
publicvoidonResult(intresult){
abilityToken=result;
}
};
...
@Override
publicvoidonStart(Intentintent){
...
continuationRegisterManager=getContinuationRegisterManager();
}
@Override
publicvoidonStop(){
super.onStop();
//解注冊(cè)流轉(zhuǎn)任務(wù)管理服務(wù)
continuationRegisterManager.unregister(abilityToken,null);
//斷開(kāi)流轉(zhuǎn)任務(wù)管理服務(wù)連接
continuationRegisterManager.disconnect();
}
在 Api5 的時(shí)候 IContinuationDeviceCallback 的回調(diào)接口跟官方文檔有些出入,當(dāng)你選擇設(shè)備后會(huì)在 onDeviceConnectDone 返回你所選擇的設(shè)備 ID 及設(shè)備類(lèi)型。
注冊(cè)流轉(zhuǎn)服務(wù)之后我們便可以調(diào)起系統(tǒng)流轉(zhuǎn)選擇設(shè)備彈窗,可以通過(guò) ExtraParams 對(duì)設(shè)備進(jìn)行過(guò)濾,如不需要過(guò)濾,可不傳。
ExtraParamsparams=newExtraParams();
String[]devTypes=newString[]{ExtraParams.DEVICETYPE_SMART_PHONE,ExtraParams.DEVICETYPE_SMART_WATCH,ExtraParams.DEVICETYPE_SMART_PAD};
params.setDevType(devTypes);
registerContinuation();
//顯示選擇設(shè)備列表
continuationRegisterManager.showDeviceList(abilityToken,params,newRequestCallback(){
@Override
publicvoidonResult(intresult){
}
});
選擇完設(shè)備之后會(huì)通過(guò)上述的 IContinuationDeviceCallback 的 onDeviceConnectDone 方法進(jìn)行回調(diào)。
之后通過(guò) continueAbility 方法傳入目標(biāo)設(shè)備的 DeviceID,將運(yùn)行的 FA 遷移到目標(biāo)設(shè)備,實(shí)現(xiàn)業(yè)務(wù)在設(shè)備間無(wú)縫遷移。
//設(shè)置流轉(zhuǎn)任務(wù)管理服務(wù)設(shè)備狀態(tài)變更的回調(diào)
privateIContinuationDeviceCallbackcontinuationDeviceCallback=newIContinuationDeviceCallback(){
@Override
publicvoidonDeviceConnectDone(StringdeviceId,StringdeviceType){
selectDeviceId=deviceId;
getUITaskDispatcher().asyncDispatch(()->{
continuationRegisterManager.updateConnectStatus(abilityToken,selectDeviceId,DeviceConnectState.CONNECTING.getState(),null);
});
if(selectDeviceId!=null){
continueAbility(selectDeviceId);
}
...
}
@Override
publicvoidonDeviceDisconnectDone(Strings){
...
unRegisterContinuation();
}
};
在 FA 遷移中我覺(jué)得最主要的部分就是狀態(tài)和數(shù)據(jù)的傳遞,要讓用戶(hù)體驗(yàn)到”無(wú)縫“的用戶(hù)體驗(yàn),需要通過(guò)實(shí)現(xiàn) IAbilityContinuation 接口來(lái)實(shí)現(xiàn)數(shù)據(jù)的傳遞。
主要代碼如下:
@Override
publicbooleanonSaveData(IntentParamssaveData){
//根據(jù)業(yè)務(wù)需求,在這里去設(shè)置需要傳遞的數(shù)據(jù)
saveData.setParam("continueParam",continueParam);
returntrue;
}
@Override
publicbooleanonRestoreData(IntentParamsrestoreData){
//遠(yuǎn)端FA遷移傳來(lái)的狀態(tài)數(shù)據(jù),開(kāi)發(fā)者可以按照自身業(yè)務(wù)對(duì)這些數(shù)據(jù)進(jìn)行處理
Objectdata=restoreData.getParam("continueParam");
getUITaskDispatcher().asyncDispatch(()->{
});
returntrue;
}
需要注意的是,在 onRestoreData 處理數(shù)據(jù)更新 UI 的時(shí)候,需要在 UI 線(xiàn)程中去更新,否則會(huì)報(bào)錯(cuò)。 ②不同 FA 之間的遷移 在實(shí)際開(kāi)發(fā)中可能會(huì)因?yàn)樵O(shè)備端的部分需求、UI 的不同,例如車(chē)機(jī)、手機(jī)、手表,從而開(kāi)發(fā)了不同的 FA。
不同 FA 之間的遷移幾乎與同個(gè) FA 之間遷移配置一致,只是我們的 AbilitySlice 不需要再實(shí)現(xiàn) IAbilityContinuation 接口來(lái)實(shí)現(xiàn)數(shù)據(jù)的同步,而是通過(guò) Intent,具體實(shí)現(xiàn)如下。
首先我們先在選擇設(shè)備成功后的回調(diào) IContinuationDeviceCallback 初始化分布式環(huán)境。
//設(shè)置流轉(zhuǎn)任務(wù)管理服務(wù)設(shè)備狀態(tài)變更的回調(diào)
privateIContinuationDeviceCallbackcontinuationDeviceCallback=newIContinuationDeviceCallback(){
@Override
publicvoidonDeviceConnectDone(StringdeviceId,StringdeviceType){
selectDeviceId=deviceId;
//省略部分代碼
...
try{
//初始化分布式環(huán)境
DeviceManager.initDistributedEnvironment(selectDeviceId,newIInitCallback(){
@Override
publicvoidonInitSuccess(Stringsuccess){
}
@Override
publicvoidonInitFailure(Stringfailure,intresult){
}
});
}catch(RemoteExceptione){
e.printStackTrace();
}
...
}
....
};
之前我們是通過(guò) continueAbility() 方法進(jìn)行跳轉(zhuǎn),而現(xiàn)在我們需要通過(guò) Intent 方法進(jìn)行跳轉(zhuǎn)。
Intentintent=newIntent();
Operationoperation=newIntent.OperationBuilder()
.withDeviceId(deviceId)
.withBundleName(bundleName)
.withAbilityName(abilityName)
.withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
.build();
intent.setOperation(operation);
IntentParamsintentParams=newIntentParams();
//通過(guò)IntentParams傳遞參數(shù)
...
startAbility(intent);
在接收方,我們可以通過(guò) onStart(Intent intent) 方法接受傳遞過(guò)來(lái)的參數(shù),再根據(jù)自己的業(yè)務(wù)邏輯實(shí)現(xiàn)數(shù)據(jù)同步。 ③自定義設(shè)備選擇彈窗 在實(shí)際項(xiàng)目開(kāi)發(fā)中我們也可以自定義流轉(zhuǎn)彈窗樣式,但并不推薦這種方式,經(jīng)測(cè)試發(fā)現(xiàn)只有在兩個(gè)設(shè)備通過(guò)藍(lán)牙連接的時(shí)候才能獲取到設(shè)備列表,只有在特定的場(chǎng)景。
例如手機(jī)與車(chē)機(jī)、手機(jī)與手表在實(shí)際使用過(guò)程中我們基本上是會(huì)保持藍(lán)牙連接的,通過(guò)這種方式實(shí)現(xiàn)流轉(zhuǎn)會(huì)更穩(wěn)定。但如果不能保持藍(lán)牙實(shí)時(shí)連接的場(chǎng)景則不推薦。
官方 API提供了 DeviceManager.getDeviceList() 來(lái)獲取遠(yuǎn)端設(shè)備,具體代碼如下。
publicstaticListgetDeviceList(){
//調(diào)用DeviceManager的getDeviceList接口,通過(guò)FLAG_GET_ONLINE_DEVICE標(biāo)記獲得在線(xiàn)設(shè)備列表
ListonlineDevices=DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
//判斷組網(wǎng)設(shè)備是否為空
if(onlineDevices==null){
LogUtil.e(TAG,"onlinedevicesisnull");
returnnewArrayList<>();
}
returnonlineDevices;
}
獲取到設(shè)備列表后,我們就可以自行實(shí)現(xiàn)頁(yè)面了,在上述的 showDeviceList() 彈出設(shè)備列表的位置替換成自己的彈窗即可。
結(jié)語(yǔ)
目前在 DevEco Studio 2.1 Release 以上版本已經(jīng)支持跨端遷移的模擬器了。
如果沒(méi)有顯示出來(lái)可以在 Settings-DevEco Labs 勾選 Enable Super Device。
以上過(guò)程是在實(shí)際開(kāi)發(fā)過(guò)程中慢慢摸索得出,如有不對(duì)的地方,歡迎在評(píng)論區(qū)指出,共同探討(附下載)。
https://harmonyos.51cto.com/posts/9013
-
鴻蒙系統(tǒng)
+關(guān)注
關(guān)注
183文章
2637瀏覽量
66512 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1980瀏覽量
30337
原文標(biāo)題:HarmonyOS流轉(zhuǎn),替你踩坑了?。?!
文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論