跨端遷移
概述
在用戶使用設(shè)備的過(guò)程中,當(dāng)使用情境發(fā)生變化時(shí)(例如從室內(nèi)走到戶外或者周?chē)懈m合的設(shè)備等),之前使用的設(shè)備可能已經(jīng)不適合繼續(xù)當(dāng)前的任務(wù),此時(shí),用戶可以選擇新的設(shè)備來(lái)繼續(xù)當(dāng)前的任務(wù),原設(shè)備可按需決定是否退出任務(wù),這個(gè)就是跨端遷移的場(chǎng)景。常見(jiàn)的跨端遷移場(chǎng)景實(shí)例:在平板上播放的視頻,遷移到智慧屏繼續(xù)播放,從而獲得更佳的觀看體驗(yàn);平板上的視頻應(yīng)用退出。在應(yīng)用開(kāi)發(fā)層面,跨端遷移指在A端運(yùn)行的UIAbility遷移到B端上,完成遷移后,B端UIAbility繼續(xù)任務(wù),而A端UIAbility可按需決定是否退出。
跨端遷移的核心任務(wù)是將應(yīng)用的當(dāng)前狀態(tài)(包括頁(yè)面控件、狀態(tài)變量等)無(wú)縫遷移到另一設(shè)備,從而在新設(shè)備上無(wú)縫接續(xù)應(yīng)用體驗(yàn)。這意味著用戶在一臺(tái)設(shè)備上進(jìn)行的操作可以在另一臺(tái)設(shè)備的相同應(yīng)用中快速切換并無(wú)縫銜接。
主要功能包括:
- 支持用戶自定義數(shù)據(jù)存儲(chǔ)及恢復(fù)。
- 支持頁(yè)面路由信息和頁(yè)面控件狀態(tài)數(shù)據(jù)的存儲(chǔ)及恢復(fù)。
- 支持應(yīng)用兼容性檢測(cè)。
- 支持應(yīng)用根據(jù)實(shí)際使用場(chǎng)景動(dòng)態(tài)設(shè)置遷移狀態(tài)(默認(rèn)遷移狀態(tài)為 ACTIVE 激活狀態(tài))。例如,編輯類(lèi)應(yīng)用在編輯文本的頁(yè)面下才需要遷移,其他頁(yè)面不需要遷移,則可以通過(guò)[
setMissionContinueState
]進(jìn)行控制。 - 支持應(yīng)用動(dòng)態(tài)選擇是否進(jìn)行頁(yè)面棧恢復(fù)(默認(rèn)進(jìn)行頁(yè)面棧信息恢復(fù))。例如,應(yīng)用希望自定義遷移到其他設(shè)備后顯示的頁(yè)面,則可以通過(guò)[
SUPPORT_CONTINUE_PAGE_STACK_KEY
]進(jìn)行控制。 - 支持應(yīng)用動(dòng)態(tài)選擇遷移成功后是否退出遷移源端應(yīng)用(默認(rèn)遷移成功后退出遷移源端應(yīng)用)??梢酝ㄟ^(guò)[
SUPPORT_CONTINUE_SOURCE_EXIT_KEY
]進(jìn)行控制。說(shuō)明:
開(kāi)發(fā)者可以開(kāi)發(fā)具有遷移能力的應(yīng)用,遷移的觸發(fā)由系統(tǒng)應(yīng)用完成。
運(yùn)作機(jī)制
- 在源端,通過(guò)
UIAbility
的[onContinue()
]回調(diào),開(kāi)發(fā)者可以保存待接續(xù)的業(yè)務(wù)數(shù)據(jù)。例如,在瀏覽器應(yīng)用中完成跨端遷移,開(kāi)發(fā)者需要使用[onContinue()
]回調(diào)保存頁(yè)面URL等業(yè)務(wù)內(nèi)容,而系統(tǒng)將自動(dòng)保存頁(yè)面狀態(tài),如當(dāng)前瀏覽進(jìn)度。 - 分布式框架提供了跨設(shè)備應(yīng)用界面、頁(yè)面棧以及業(yè)務(wù)數(shù)據(jù)的保存和恢復(fù)機(jī)制,它負(fù)責(zé)將數(shù)據(jù)從源端發(fā)送到對(duì)端。
- 在對(duì)端,同一
UIAbility
可以通過(guò)[onCreate()
](冷啟動(dòng))和[onNewWant()
](熱啟動(dòng))接口來(lái)恢復(fù)業(yè)務(wù)數(shù)據(jù)。
跨端遷移流程
以從對(duì)端的遷移入口發(fā)起遷移為例,跨端遷移流程如下圖所示。
約束限制
- 跨端遷移要求在同一
UIAbility
之間進(jìn)行,也就是需要相同的bundleName
、abilityName
和簽名信息。 - 為了獲得最佳體驗(yàn),使用
wantParam
傳輸?shù)臄?shù)據(jù)需要控制在100KB以下。
開(kāi)發(fā)步驟
在[module.json5配置文件]的abilities標(biāo)簽中配置跨端遷移標(biāo)簽
continuable
。{ "module": { // ... "abilities": [ { // ... "continuable": true, // 配置UIAbility支持遷移 } ] } }
說(shuō)明:
根據(jù)需要配置應(yīng)用啟動(dòng)模式類(lèi)型,配置詳情請(qǐng)參照[UIAbility組件啟動(dòng)模式]。
在源端
UIAbility
中實(shí)現(xiàn)[onContinue()
]回調(diào)。
當(dāng)UIAbility
實(shí)例觸發(fā)遷移時(shí),[onContinue()
]回調(diào)在源端被調(diào)用,開(kāi)發(fā)者可以在該接口中通過(guò)同步或異步的方式來(lái)保存遷移數(shù)據(jù),實(shí)現(xiàn)應(yīng)用兼容性檢測(cè),決定是否支持此次遷移。- 保存遷移數(shù)據(jù):開(kāi)發(fā)者可以將要遷移的數(shù)據(jù)通過(guò)鍵值對(duì)的方式保存在
wantParam
參數(shù)中。 - 應(yīng)用兼容性檢測(cè):開(kāi)發(fā)者可以通過(guò)從
wantParam
參數(shù)中獲取對(duì)端應(yīng)用的版本號(hào)與源端應(yīng)用版本號(hào)做兼容性校驗(yàn)。開(kāi)發(fā)者可以在觸發(fā)遷移時(shí)從[onContinue()
]回調(diào)中wantParam.version
獲取到遷移對(duì)端應(yīng)用的版本號(hào)與遷移源端應(yīng)用版本號(hào)做兼容校驗(yàn)。 - 遷移決策:開(kāi)發(fā)者可以通過(guò)[
onContinue()
]回調(diào)的返回值決定是否支持此次遷移,接口返回值詳見(jiàn)[AbilityConstant.OnContinueResult
]。
import AbilityConstant from '@ohos.app.ability.AbilityConstant'; import hilog from '@ohos.hilog'; import UIAbility from '@ohos.app.ability.UIAbility'; const TAG: string = '[MigrationAbility]'; const DOMAIN_NUMBER: number = 0xFF00; export default class MigrationAbility extends UIAbility { onContinue(wantParam: Record< string, Object >):AbilityConstant.OnContinueResult { let version = wantParam.version; let targetDevice = wantParam.targetDevice; hilog.info(DOMAIN_NUMBER, TAG, `onContinue version = ${version}, targetDevice: ${targetDevice}`); // 準(zhǔn)備遷移數(shù)據(jù) // 獲取源端版本號(hào) let versionSrc: number = -1; // 請(qǐng)?zhí)畛渚唧w獲取版本號(hào)的代碼 // 兼容性校驗(yàn) if (version !== versionSrc) { // 在兼容性校驗(yàn)不通過(guò)時(shí)返回MISMATCH return AbilityConstant.OnContinueResult.MISMATCH; } // 將要遷移的數(shù)據(jù)保存在wantParam的自定義字段(例如data)中 const continueInput = '遷移的數(shù)據(jù)'; wantParam['data'] = continueInput; return AbilityConstant.OnContinueResult.AGREE; } }
- 保存遷移數(shù)據(jù):開(kāi)發(fā)者可以將要遷移的數(shù)據(jù)通過(guò)鍵值對(duì)的方式保存在
源端設(shè)備
UIAbility
實(shí)例在冷啟動(dòng)和熱啟動(dòng)情況下分別會(huì)調(diào)用不同的接口來(lái)恢復(fù)數(shù)據(jù)和加載UI。 在對(duì)端設(shè)備的UIAbility
中,需要實(shí)現(xiàn)[onCreate()
]/[onNewWant()
]接口來(lái)恢復(fù)遷移數(shù)據(jù)。不同情況下的函數(shù)調(diào)用如下圖所示:- 通過(guò)在[
onCreate()
]/[onNewWant()
]回調(diào)中檢查launchReason
,可以判斷此次啟動(dòng)是否有遷移觸發(fā)。 - 開(kāi)發(fā)者可以從
want
中獲取之前保存的遷移數(shù)據(jù) - 數(shù)據(jù)恢復(fù)后調(diào)用
restoreWindowStage()
來(lái)觸發(fā) 頁(yè)面恢復(fù) ,包括頁(yè)面棧信息。
import AbilityConstant from '@ohos.app.ability.AbilityConstant'; import hilog from '@ohos.hilog'; import UIAbility from '@ohos.app.ability.UIAbility'; import type Want from '@ohos.app.ability.Want'; const TAG: string = '[MigrationAbility]'; const DOMAIN_NUMBER: number = 0xFF00; export default class MigrationAbility extends UIAbility { storage : LocalStorage = new LocalStorage(); onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', 'Ability onCreate'); if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) { // 將上述保存的數(shù)據(jù)從want.parameters中取出恢復(fù) let continueInput = ''; if (want.parameters !== undefined) { continueInput = JSON.stringify(want.parameters.data); hilog.info(DOMAIN_NUMBER, TAG, `continue input ${JSON.stringify(continueInput)}`); } // 觸發(fā)頁(yè)面恢復(fù) this.context.restoreWindowStage(this.storage); } } onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void { hilog.info(DOMAIN_NUMBER, TAG, 'onNewWant'); if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) { // 將上述保存的數(shù)據(jù)從want.parameters中取出恢復(fù) let continueInput = ''; if (want.parameters !== undefined) { continueInput = JSON.stringify(want.parameters.data); hilog.info(DOMAIN_NUMBER, TAG, `continue input ${JSON.stringify(continueInput)}`); } // 觸發(fā)頁(yè)面恢復(fù) this.context.restoreWindowStage(this.storage); } } }
- 通過(guò)在[
可選配置遷移能力
動(dòng)態(tài)配置遷移能力
從API version 10開(kāi)始,提供了支持動(dòng)態(tài)配置遷移能力的功能。即應(yīng)用可以根據(jù)實(shí)際使用場(chǎng)景,在需要遷移時(shí)開(kāi)啟應(yīng)用遷移能力;在業(yè)務(wù)不需要遷移時(shí)則可以關(guān)閉遷移能力。
開(kāi)發(fā)者可以通過(guò)調(diào)用[setMissionContinueState()
]接口對(duì)遷移能力進(jìn)行設(shè)置。默認(rèn)狀態(tài)下,應(yīng)用的遷移能力為ACTIVE狀態(tài),即遷移能力開(kāi)啟,可以遷移。
設(shè)置遷移能力的時(shí)機(jī)
遷移能力的改變可以根據(jù)實(shí)際業(yè)務(wù)需求和代碼實(shí)現(xiàn),發(fā)生在應(yīng)用生命周期的絕大多數(shù)時(shí)機(jī)。本文介紹常用的幾種配置方式。
在UIAbility
的[onCreate()
]回調(diào)中調(diào)用接口,可以在應(yīng)用創(chuàng)建時(shí)設(shè)置應(yīng)用的遷移狀態(tài)。
// MigrationAbility.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import type Want from '@ohos.app.ability.Want';
const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
export default class MigrationAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// ...
this.context.setMissionContinueState(AbilityConstant.ContinueState.INACTIVE, (result) = > {
hilog.info(DOMAIN_NUMBER, TAG, `setMissionContinueState INACTIVE result: ${JSON.stringify(result)}`);
});
// ...
}
}
在頁(yè)面的onPageShow()
回調(diào)中調(diào)用接口,可以設(shè)置單個(gè)頁(yè)面出現(xiàn)時(shí)應(yīng)用的遷移狀態(tài)。
// Page_MigrationAbilityFirst.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
@Entry
@Component
struct Page_MigrationAbilityFirst {
private context = getContext(this) as common.UIAbilityContext;
build() {
// ...
}
// ...
onPageShow(){
// 進(jìn)入該頁(yè)面時(shí),將應(yīng)用設(shè)置為可遷移狀態(tài)
this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) = > {
hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
});
}
}
在某個(gè)組件的觸發(fā)事件中設(shè)置應(yīng)用遷移能力。
// Page_MigrationAbilityFirst.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import common from '@ohos.app.ability.common';
import hilog from '@ohos.hilog';
import promptAction from '@ohos.promptAction'
import router from '@ohos.router';
const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
@Entry
@Component
struct Page_MigrationAbilityFirst {
private context = getContext(this) as common.UIAbilityContext;
build() {
Column() {
//...
List({ initialIndex: 0 }) {
ListItem() {
Row() {
//...
}
.onClick(() = > {
// 點(diǎn)擊該按鈕時(shí),將應(yīng)用設(shè)置為可遷移狀態(tài)
this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) = > {
hilog.info(DOMAIN_NUMBER, TAG, '%{public}s', `setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
promptAction.showToast({
message: $r('app.string.Success')
});
});
})
}
//...
}
//...
}
//...
}
}
保證遷移連續(xù)性
由于遷移加載時(shí),對(duì)端拉起的應(yīng)用可能執(zhí)行過(guò)自己的遷移狀態(tài)設(shè)置命令(例如,冷啟動(dòng)時(shí)對(duì)端在[onCreate()
]中設(shè)置了 INACTIVE ;熱啟動(dòng)時(shí)對(duì)端已打開(kāi)了不可遷移的頁(yè)面,遷移狀態(tài)為 INACTIVE 等情況)。為了保證遷移過(guò)后的應(yīng)用依然具有可以遷移回源端的能力,應(yīng)在 [onCreate()
]/[onNewWant()
]的遷移調(diào)用判斷中,將遷移狀態(tài)設(shè)置為 ACTIVE 。
// MigrationAbility.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import type Want from '@ohos.app.ability.Want';
const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
export default class MigrationAbility extends UIAbility {
// ...
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// ...
if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
// ...
}
// 調(diào)用原因?yàn)檫w移時(shí),設(shè)置狀態(tài)為可遷移,應(yīng)對(duì)冷啟動(dòng)情況
this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) = > {
hilog.info(DOMAIN_NUMBER, TAG, `setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
});
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// ...
// 調(diào)用原因?yàn)檫w移時(shí),設(shè)置狀態(tài)為可遷移,應(yīng)對(duì)熱啟動(dòng)情況
if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) = > {
hilog.info(DOMAIN_NUMBER, TAG, `setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
});
}
}
// ...
}
按需遷移頁(yè)面棧
支持應(yīng)用動(dòng)態(tài)選擇是否進(jìn)行頁(yè)面棧恢復(fù)(默認(rèn)進(jìn)行頁(yè)面棧信息恢復(fù))。如果應(yīng)用不想使用系統(tǒng)默認(rèn)恢復(fù)的頁(yè)面棧,則可以設(shè)置不進(jìn)行頁(yè)面棧遷移,而需要在onWindowStageRestore()
設(shè)置遷移后進(jìn)入的頁(yè)面,參數(shù)定義見(jiàn)[SUPPORT_CONTINUE_PAGE_STACK_KEY]。
應(yīng)用在源端的頁(yè)面棧中存在Index和Second路由,而在對(duì)端恢復(fù)時(shí)不需要按照源端頁(yè)面棧進(jìn)行恢復(fù),需要恢復(fù)到指定頁(yè)面。
例如,UIAbility
遷移不需要自動(dòng)遷移頁(yè)面棧信息。
// MigrationAbility.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import wantConstant from '@ohos.app.ability.wantConstant';
import hilog from '@ohos.hilog';
import type window from '@ohos.window';
const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
export default class MigrationAbility extends UIAbility {
// ...
onContinue(wantParam: Record< string, Object >):AbilityConstant.OnContinueResult {
hilog.info(DOMAIN_NUMBER, TAG, `onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`);
wantParam[wantConstant.Params.SUPPORT_CONTINUE_PAGE_STACK_KEY] = false;
return AbilityConstant.OnContinueResult.AGREE;
}
onWindowStageRestore(windowStage: window.WindowStage) : void {
// 若不需要自動(dòng)遷移頁(yè)面棧信息,則需要在此處設(shè)置應(yīng)用遷移后進(jìn)入的頁(yè)面
windowStage.loadContent('pages/page_migrationability/Page_MigrationAbilityThird', (err, data) = > {
if (err.code) {
hilog.error(DOMAIN_NUMBER, TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
});
}
}
按需退出
支持應(yīng)用動(dòng)態(tài)選擇遷移成功后是否退出遷移源端應(yīng)用(默認(rèn)遷移成功后退出遷移源端應(yīng)用)。如果應(yīng)用不想讓系統(tǒng)自動(dòng)退出遷移源端應(yīng)用,則可以設(shè)置不退出,參數(shù)定義見(jiàn)[SUPPORT_CONTINUE_SOURCE_EXIT_KEY]。
示例:UIAbility
設(shè)置遷移成功后,源端不需要退出遷移應(yīng)用。
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import wantConstant from '@ohos.app.ability.wantConstant';
import hilog from '@ohos.hilog';
const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
export default class MigrationAbility extends UIAbility {
// ...
onContinue(wantParam: Record< string, Object >):AbilityConstant.OnContinueResult {
hilog.info(DOMAIN_NUMBER, TAG, `onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`);
wantParam[wantConstant.Params.SUPPORT_CONTINUE_SOURCE_EXIT_KEY] = false;
return AbilityConstant.OnContinueResult.AGREE;
}
}
跨端遷移中的數(shù)據(jù)遷移
當(dāng)前推薦兩種不同的數(shù)據(jù)遷移方式,開(kāi)發(fā)者可以根據(jù)實(shí)際使用需要進(jìn)行選擇。
說(shuō)明:
部分ArkUI組件支持通過(guò)配置
restoreId
的方式,在遷移后將特定狀態(tài)恢復(fù)到對(duì)端設(shè)備。
如果涉及分布式對(duì)象遷移時(shí)應(yīng)注意:
- 需要申請(qǐng)
ohos.permission.DISTRIBUTED_DATASYNC
權(quán)限。- 同時(shí)需要在應(yīng)用首次啟動(dòng)時(shí)彈窗向用戶申請(qǐng)授權(quán)。
使用wantParam遷移數(shù)據(jù)
在需要遷移的數(shù)據(jù)較少(100KB以下)時(shí),開(kāi)發(fā)者可以選擇在wantParam
中增加字段進(jìn)行數(shù)據(jù)遷移。示例如下:
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import UIAbility from '@ohos.app.ability.UIAbility';
import type Want from '@ohos.app.ability.Want';
const TAG: string = '[MigrationAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
export default class MigrationAbility extends UIAbility {
// 源端保存
onContinue(wantParam: Record< string, Object >):AbilityConstant.OnContinueResult {
// 將要遷移的數(shù)據(jù)保存在wantParam的自定義字段(例如data)中
const continueInput = '遷移的數(shù)據(jù)';
wantParam['data'] = continueInput;
return AbilityConstant.OnContinueResult.AGREE;
}
// 對(duì)端恢復(fù)
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
if (launchParam.launchReason === AbilityConstant.LaunchReason.CONTINUATION) {
// 將上述保存的數(shù)據(jù)取出恢復(fù)
let continueInput = '';
if (want.parameters !== undefined) {
continueInput = JSON.stringify(want.parameters.data);
hilog.info(DOMAIN_NUMBER, TAG, `continue input ${continueInput}`);
}
// 觸發(fā)頁(yè)面恢復(fù)
this.context.restoreWindowStage(this.storage);
}
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
let continueInput = '';
if (want.parameters !== undefined) {
continueInput = JSON.stringify(want.parameters.data);
hilog.info(DOMAIN_NUMBER, TAG, `continue input ${JSON.stringify(continueInput)}`);
}
// 觸發(fā)頁(yè)面恢復(fù)
this.context.restoreWindowStage(this.storage);
}
}
}
使用分布式對(duì)象遷移數(shù)據(jù)
當(dāng)需要遷移的數(shù)據(jù)較大(100KB以上)或數(shù)據(jù)以文件形式存在時(shí),可以選擇[分布式對(duì)象]進(jìn)行數(shù)據(jù)遷移。其中,對(duì)于文件的遷移,可以使用分布式對(duì)象提供的[資產(chǎn)]遷移方式進(jìn)行。
- 在源端
onContinue()
接口中創(chuàng)建一個(gè)分布式數(shù)據(jù)對(duì)象[DataObject
],將所要遷移的數(shù)據(jù)填充到分布式對(duì)象數(shù)據(jù)中,并將生成的sessionId
通過(guò)want
傳遞到對(duì)端。 - 對(duì)端在
onCreate()/onNewWant
中進(jìn)行數(shù)據(jù)恢復(fù)時(shí),可以從want中讀取該sessionId
,通過(guò)分布式對(duì)象恢復(fù)數(shù)據(jù)。
說(shuō)明: 自API 12起,為了保證更高的成功率,文件數(shù)據(jù)的遷移不建議繼續(xù)通過(guò)[跨設(shè)備文件訪問(wèn)]實(shí)現(xiàn),推薦使用分布式對(duì)象攜帶資產(chǎn)的方式進(jìn)行。開(kāi)發(fā)者此前通過(guò)跨設(shè)備文件訪問(wèn)實(shí)現(xiàn)的文件遷移依然可以使用。
驗(yàn)證指導(dǎo)
為方便開(kāi)發(fā)者驗(yàn)證已開(kāi)發(fā)的可遷移應(yīng)用,系統(tǒng)提供了一個(gè)全局任務(wù)中心demo作為遷移的入口。下面介紹通過(guò)安裝全局任務(wù)中心來(lái)驗(yàn)證遷移的方式。
1. 編譯安裝全局任務(wù)中心
配置環(huán)境
public-SDK不支持開(kāi)發(fā)者使用所有的系統(tǒng)API,例如:全局任務(wù)中心使用的[ @ohos.distributedDeviceManager ]不包括在public_SDK中。因此為了正確編譯安裝全局任務(wù)中心,開(kāi)發(fā)者需要替換full-SDK,具體操作可參見(jiàn)[替換指南]。
說(shuō)明 :
本文中的截圖僅為參考,具體的顯示界面請(qǐng)以實(shí)際使用的DevEco Studio和SDK的版本為準(zhǔn)。
下載MissionCenter_Demo[示例代碼]
編譯工程文件
?a.新建一個(gè)工程,找到對(duì)應(yīng)的文件夾替換下載文件
?b.自動(dòng)簽名,編譯安裝。
?DevEco的自動(dòng)簽名模板默認(rèn)簽名權(quán)限為normal級(jí)。而本應(yīng)用設(shè)計(jì)到ohos.permission.MANAGE_MISSIONS權(quán)限為system_core級(jí)別。自動(dòng)生成的簽名無(wú)法獲得足夠的權(quán)限,所以需要將權(quán)限升級(jí)為system_core級(jí)別,然后簽名。
?c.系統(tǒng)權(quán)限設(shè)置(以api10目錄為例): 將Sdk目錄下的openharmonyapi版本(如:10)toolchainslibUnsignedReleasedProfileTemplate.json文件中的"apl":"normal"改為"apl":"system_core"。
- 點(diǎn)擊file->Project Structure。
- 點(diǎn)擊Signing Configs 點(diǎn)擊OK。
- 連接開(kāi)發(fā)板運(yùn)行生成demo。
2. 設(shè)備組網(wǎng)
- 打開(kāi)A,B兩設(shè)備的計(jì)算器。
- 點(diǎn)擊右上角箭頭選擇B設(shè)備。
- 在B設(shè)備選擇信任設(shè)備,彈出PIN碼。
- 在A設(shè)備輸入PIN碼。
- 已組網(wǎng)成功,驗(yàn)證方法:在A設(shè)備輸入數(shù)字,B設(shè)備同步出現(xiàn)則證明組網(wǎng)成功。
3. 發(fā)起遷移
在B設(shè)備打開(kāi)多設(shè)備協(xié)同權(quán)限的應(yīng)用,A設(shè)備打開(kāi)全局任務(wù)中心demo,A設(shè)備出現(xiàn)A設(shè)備名稱(即:本機(jī):OpenHarmony 3.2)和B設(shè)備名稱(OpenHarmony 3.2)。
點(diǎn)擊B設(shè)備名稱,然后出現(xiàn)B設(shè)備的應(yīng)用。
最后將應(yīng)用拖拽到A設(shè)備名稱處,A設(shè)備應(yīng)用被拉起,B設(shè)備應(yīng)用退出。
.
審核編輯 黃宇
-
組件
+關(guān)注
關(guān)注
1文章
532瀏覽量
18424 -
SDK
+關(guān)注
關(guān)注
3文章
1077瀏覽量
49108 -
鴻蒙
+關(guān)注
關(guān)注
60文章
2620瀏覽量
44060
發(fā)布評(píng)論請(qǐng)先 登錄
鴻蒙OS 跨設(shè)備遷移
AKI跨語(yǔ)言調(diào)用庫(kù)神助攻C/C++代碼遷移至HarmonyOS NEXT
#2020征文-手機(jī)#【鴻蒙基地】鴻蒙跨設(shè)備啟動(dòng)窗口:Page Ability
#2020征文-手機(jī)#【鴻蒙基地】鴻蒙跨設(shè)備啟動(dòng)窗口:Page Ability
HarmonyOS應(yīng)用框架如何解決多設(shè)備交互問(wèn)題?
新能力讓數(shù)據(jù)多端協(xié)同更便捷,數(shù)據(jù)跨端遷移更高效!
DevEco Studio 2.1跨平臺(tái)設(shè)備交互使用示例
鴻蒙流轉(zhuǎn)跨端遷移失敗是什么原因?是否跟機(jī)型有關(guān)?
HarmonyOS應(yīng)用開(kāi)發(fā)-DiseributedVideoCodelab跨設(shè)備視頻遷移
華為發(fā)布HarmonyOS2,全新桌面支持應(yīng)用跨設(shè)備流轉(zhuǎn)
什么是HarmonyOS“跨設(shè)備遷移”?
HarmonyOS中如何進(jìn)行跨端遷移
鴻蒙開(kāi)發(fā):應(yīng)用組件跨設(shè)備交互(流轉(zhuǎn))【多端協(xié)同】

評(píng)論