跨端遷移
概述
在用戶使用設(shè)備的過程中,當(dāng)使用情境發(fā)生變化時(shí)(例如從室內(nèi)走到戶外或者周圍有更適合的設(shè)備等),之前使用的設(shè)備可能已經(jīng)不適合繼續(xù)當(dāng)前的任務(wù),此時(shí),用戶可以選擇新的設(shè)備來繼續(xù)當(dāng)前的任務(wù),原設(shè)備可按需決定是否退出任務(wù),這個(gè)就是跨端遷移的場景。常見的跨端遷移場景實(shí)例:在平板上播放的視頻,遷移到智慧屏繼續(xù)播放,從而獲得更佳的觀看體驗(yàn);平板上的視頻應(yīng)用退出。在應(yīng)用開發(fā)層面,跨端遷移指在A端運(yùn)行的UIAbility遷移到B端上,完成遷移后,B端UIAbility繼續(xù)任務(wù),而A端UIAbility可按需決定是否退出。
跨端遷移的核心任務(wù)是將應(yīng)用的當(dāng)前狀態(tài)(包括頁面控件、狀態(tài)變量等)無縫遷移到另一設(shè)備,從而在新設(shè)備上無縫接續(xù)應(yīng)用體驗(yàn)。這意味著用戶在一臺設(shè)備上進(jìn)行的操作可以在另一臺設(shè)備的相同應(yīng)用中快速切換并無縫銜接。
主要功能包括:
- 支持用戶自定義數(shù)據(jù)存儲及恢復(fù)。
- 支持頁面路由信息和頁面控件狀態(tài)數(shù)據(jù)的存儲及恢復(fù)。
- 支持應(yīng)用兼容性檢測。
- 支持應(yīng)用根據(jù)實(shí)際使用場景動態(tài)設(shè)置遷移狀態(tài)(默認(rèn)遷移狀態(tài)為 ACTIVE 激活狀態(tài))。例如,編輯類應(yīng)用在編輯文本的頁面下才需要遷移,其他頁面不需要遷移,則可以通過[
setMissionContinueState
]進(jìn)行控制。 - 支持應(yīng)用動態(tài)選擇是否進(jìn)行頁面?;謴?fù)(默認(rèn)進(jìn)行頁面棧信息恢復(fù))。例如,應(yīng)用希望自定義遷移到其他設(shè)備后顯示的頁面,則可以通過[
SUPPORT_CONTINUE_PAGE_STACK_KEY
]進(jìn)行控制。 - 支持應(yīng)用動態(tài)選擇遷移成功后是否退出遷移源端應(yīng)用(默認(rèn)遷移成功后退出遷移源端應(yīng)用)。可以通過[
SUPPORT_CONTINUE_SOURCE_EXIT_KEY
]進(jìn)行控制。說明:
開發(fā)者可以開發(fā)具有遷移能力的應(yīng)用,遷移的觸發(fā)由系統(tǒng)應(yīng)用完成。
運(yùn)作機(jī)制
- 在源端,通過
UIAbility
的[onContinue()
]回調(diào),開發(fā)者可以保存待接續(xù)的業(yè)務(wù)數(shù)據(jù)。例如,在瀏覽器應(yīng)用中完成跨端遷移,開發(fā)者需要使用[onContinue()
]回調(diào)保存頁面URL等業(yè)務(wù)內(nèi)容,而系統(tǒng)將自動保存頁面狀態(tài),如當(dāng)前瀏覽進(jìn)度。 - 分布式框架提供了跨設(shè)備應(yīng)用界面、頁面棧以及業(yè)務(wù)數(shù)據(jù)的保存和恢復(fù)機(jī)制,它負(fù)責(zé)將數(shù)據(jù)從源端發(fā)送到對端。
- 在對端,同一
UIAbility
可以通過[onCreate()
](冷啟動)和[onNewWant()
](熱啟動)接口來恢復(fù)業(yè)務(wù)數(shù)據(jù)。
跨端遷移流程
以從對端的遷移入口發(fā)起遷移為例,跨端遷移流程如下圖所示。
約束限制
- 跨端遷移要求在同一
UIAbility
之間進(jìn)行,也就是需要相同的bundleName
、abilityName
和簽名信息。 - 為了獲得最佳體驗(yàn),使用
wantParam
傳輸?shù)臄?shù)據(jù)需要控制在100KB以下。
開發(fā)步驟
在[module.json5配置文件]的abilities標(biāo)簽中配置跨端遷移標(biāo)簽
continuable
。{ "module": { // ... "abilities": [ { // ... "continuable": true, // 配置UIAbility支持遷移 } ] } }
說明:
根據(jù)需要配置應(yīng)用啟動模式類型,配置詳情請參照[UIAbility組件啟動模式]。
在源端
UIAbility
中實(shí)現(xiàn)[onContinue()
]回調(diào)。
當(dāng)UIAbility
實(shí)例觸發(fā)遷移時(shí),[onContinue()
]回調(diào)在源端被調(diào)用,開發(fā)者可以在該接口中通過同步或異步的方式來保存遷移數(shù)據(jù),實(shí)現(xiàn)應(yīng)用兼容性檢測,決定是否支持此次遷移。- 保存遷移數(shù)據(jù):開發(fā)者可以將要遷移的數(shù)據(jù)通過鍵值對的方式保存在
wantParam
參數(shù)中。 - 應(yīng)用兼容性檢測:開發(fā)者可以通過從
wantParam
參數(shù)中獲取對端應(yīng)用的版本號與源端應(yīng)用版本號做兼容性校驗(yàn)。開發(fā)者可以在觸發(fā)遷移時(shí)從[onContinue()
]回調(diào)中wantParam.version
獲取到遷移對端應(yīng)用的版本號與遷移源端應(yīng)用版本號做兼容校驗(yàn)。 - 遷移決策:開發(fā)者可以通過[
onContinue()
]回調(diào)的返回值決定是否支持此次遷移,接口返回值詳見[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ù) // 獲取源端版本號 let versionSrc: number = -1; // 請?zhí)畛渚唧w獲取版本號的代碼 // 兼容性校驗(yàn) if (version !== versionSrc) { // 在兼容性校驗(yàn)不通過時(shí)返回MISMATCH return AbilityConstant.OnContinueResult.MISMATCH; } // 將要遷移的數(shù)據(jù)保存在wantParam的自定義字段(例如data)中 const continueInput = '遷移的數(shù)據(jù)'; wantParam['data'] = continueInput; return AbilityConstant.OnContinueResult.AGREE; } }
- 保存遷移數(shù)據(jù):開發(fā)者可以將要遷移的數(shù)據(jù)通過鍵值對的方式保存在
源端設(shè)備
UIAbility
實(shí)例在冷啟動和熱啟動情況下分別會調(diào)用不同的接口來恢復(fù)數(shù)據(jù)和加載UI。 在對端設(shè)備的UIAbility
中,需要實(shí)現(xiàn)[onCreate()
]/[onNewWant()
]接口來恢復(fù)遷移數(shù)據(jù)。不同情況下的函數(shù)調(diào)用如下圖所示:- 通過在[
onCreate()
]/[onNewWant()
]回調(diào)中檢查launchReason
,可以判斷此次啟動是否有遷移觸發(fā)。 - 開發(fā)者可以從
want
中獲取之前保存的遷移數(shù)據(jù) - 數(shù)據(jù)恢復(fù)后調(diào)用
restoreWindowStage()
來觸發(fā) 頁面恢復(fù) ,包括頁面棧信息。
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ā)頁面恢復(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ā)頁面恢復(fù) this.context.restoreWindowStage(this.storage); } } }
- 通過在[
可選配置遷移能力
動態(tài)配置遷移能力
從API version 10開始,提供了支持動態(tài)配置遷移能力的功能。即應(yīng)用可以根據(jù)實(shí)際使用場景,在需要遷移時(shí)開啟應(yīng)用遷移能力;在業(yè)務(wù)不需要遷移時(shí)則可以關(guān)閉遷移能力。
開發(fā)者可以通過調(diào)用[setMissionContinueState()
]接口對遷移能力進(jìn)行設(shè)置。默認(rèn)狀態(tài)下,應(yīng)用的遷移能力為ACTIVE狀態(tà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)}`);
});
// ...
}
}
在頁面的onPageShow()
回調(diào)中調(diào)用接口,可以設(shè)置單個(gè)頁面出現(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)入該頁面時(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í),對端拉起的應(yīng)用可能執(zhí)行過自己的遷移狀態(tài)設(shè)置命令(例如,冷啟動時(shí)對端在[onCreate()
]中設(shè)置了 INACTIVE ;熱啟動時(shí)對端已打開了不可遷移的頁面,遷移狀態(tài)為 INACTIVE 等情況)。為了保證遷移過后的應(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)對冷啟動情況
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)對熱啟動情況
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īng)用動態(tài)選擇是否進(jìn)行頁面?;謴?fù)(默認(rèn)進(jìn)行頁面棧信息恢復(fù))。如果應(yīng)用不想使用系統(tǒng)默認(rèn)恢復(fù)的頁面棧,則可以設(shè)置不進(jìn)行頁面棧遷移,而需要在onWindowStageRestore()
設(shè)置遷移后進(jìn)入的頁面,參數(shù)定義見[SUPPORT_CONTINUE_PAGE_STACK_KEY]。
應(yīng)用在源端的頁面棧中存在Index和Second路由,而在對端恢復(fù)時(shí)不需要按照源端頁面棧進(jìn)行恢復(fù),需要恢復(fù)到指定頁面。
例如,UIAbility
遷移不需要自動遷移頁面棧信息。
// 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 {
// 若不需要自動遷移頁面棧信息,則需要在此處設(shè)置應(yīng)用遷移后進(jìn)入的頁面
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)用動態(tài)選擇遷移成功后是否退出遷移源端應(yīng)用(默認(rèn)遷移成功后退出遷移源端應(yīng)用)。如果應(yīng)用不想讓系統(tǒng)自動退出遷移源端應(yīng)用,則可以設(shè)置不退出,參數(shù)定義見[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ù)遷移方式,開發(fā)者可以根據(jù)實(shí)際使用需要進(jìn)行選擇。
說明:
部分ArkUI組件支持通過配置
restoreId
的方式,在遷移后將特定狀態(tài)恢復(fù)到對端設(shè)備。
如果涉及分布式對象遷移時(shí)應(yīng)注意:
- 需要申請
ohos.permission.DISTRIBUTED_DATASYNC
權(quán)限。- 同時(shí)需要在應(yīng)用首次啟動時(shí)彈窗向用戶申請授權(quán)。
使用wantParam遷移數(shù)據(jù)
在需要遷移的數(shù)據(jù)較少(100KB以下)時(shí),開發(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;
}
// 對端恢復(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ā)頁面恢復(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ā)頁面恢復(fù)
this.context.restoreWindowStage(this.storage);
}
}
}
使用分布式對象遷移數(shù)據(jù)
當(dāng)需要遷移的數(shù)據(jù)較大(100KB以上)或數(shù)據(jù)以文件形式存在時(shí),可以選擇[分布式對象]進(jìn)行數(shù)據(jù)遷移。其中,對于文件的遷移,可以使用分布式對象提供的[資產(chǎn)]遷移方式進(jìn)行。
- 在源端
onContinue()
接口中創(chuàng)建一個(gè)分布式數(shù)據(jù)對象[DataObject
],將所要遷移的數(shù)據(jù)填充到分布式對象數(shù)據(jù)中,并將生成的sessionId
通過want
傳遞到對端。 - 對端在
onCreate()/onNewWant
中進(jìn)行數(shù)據(jù)恢復(fù)時(shí),可以從want中讀取該sessionId
,通過分布式對象恢復(fù)數(shù)據(jù)。
說明: 自API 12起,為了保證更高的成功率,文件數(shù)據(jù)的遷移不建議繼續(xù)通過[跨設(shè)備文件訪問]實(shí)現(xiàn),推薦使用分布式對象攜帶資產(chǎn)的方式進(jìn)行。開發(fā)者此前通過跨設(shè)備文件訪問實(shí)現(xiàn)的文件遷移依然可以使用。
驗(yàn)證指導(dǎo)
為方便開發(fā)者驗(yàn)證已開發(fā)的可遷移應(yīng)用,系統(tǒng)提供了一個(gè)全局任務(wù)中心demo作為遷移的入口。下面介紹通過安裝全局任務(wù)中心來驗(yàn)證遷移的方式。
1. 編譯安裝全局任務(wù)中心
配置環(huán)境
public-SDK不支持開發(fā)者使用所有的系統(tǒng)API,例如:全局任務(wù)中心使用的[ @ohos.distributedDeviceManager ]不包括在public_SDK中。因此為了正確編譯安裝全局任務(wù)中心,開發(fā)者需要替換full-SDK,具體操作可參見[替換指南]。
說明 :
本文中的截圖僅為參考,具體的顯示界面請以實(shí)際使用的DevEco Studio和SDK的版本為準(zhǔn)。
下載MissionCenter_Demo[示例代碼]
編譯工程文件
?a.新建一個(gè)工程,找到對應(yīng)的文件夾替換下載文件
?b.自動簽名,編譯安裝。
?DevEco的自動簽名模板默認(rèn)簽名權(quán)限為normal級。而本應(yīng)用設(shè)計(jì)到ohos.permission.MANAGE_MISSIONS權(quán)限為system_core級別。自動生成的簽名無法獲得足夠的權(quán)限,所以需要將權(quán)限升級為system_core級別,然后簽名。
?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。
- 連接開發(fā)板運(yùn)行生成demo。
2. 設(shè)備組網(wǎng)
- 打開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è)備打開多設(shè)備協(xié)同權(quán)限的應(yīng)用,A設(shè)備打開全局任務(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文章
503瀏覽量
17786 -
SDK
+關(guān)注
關(guān)注
3文章
1020瀏覽量
45696 -
鴻蒙
+關(guān)注
關(guān)注
57文章
2302瀏覽量
42689
發(fā)布評論請先 登錄
相關(guān)推薦
評論