!294 单实例迁移demo

Merge pull request !294 from wangdongdong/0718
This commit is contained in:
openharmony_ci
2022-07-21 08:40:52 +00:00
committed by Gitee
25 changed files with 712 additions and 0 deletions
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
"app": {
"bundleName": "com.ohos.continuationManualTestSuite.hmservice",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name",
"distributedNotificationEnabled": true
}
}
@@ -0,0 +1,8 @@
{
"string": [
{
"name": "app_name",
"value": "单实例迁移"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,29 @@
# 跨端迁移Demo
### 简介
本示例展示了在eTS中如何构建stage模型跨端迁移Ability,包含:
1、配置迁移属性字段:continuable和launchType
2、申请分布式权限:DISTRIBUTED_DATASYNC
3、实现数据保存和恢复:发起端页面输入的文本迁移到远端后能够显示
4、在迁移中使用分布式对象传输数据
效果图
![index](screenshots/device/index.png) ![](screenshots/device/work.png)
### 使用说明
1、两台设备安装此应用,并组网
2、点击进入不同的page,通过迁移入口,将当前界面迁移到远端设备
3、迁移成功后的远端界面与迁移之前本机页面一致,本机页面消失
4、也可以再次将远端页面迁移到本机
### 约束与限制
1、本示例仅支持标准系统上运行。 2、本示例为Stage模型,仅支持API version 9IDE版本3.0.1.900以上,系统版本OpenHarmony3.1 release。
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
"app": {
"signingConfigs": [],
"compileSdkVersion": 9,
"compatibleSdkVersion": 9,
"products": [
{
"name": "default",
"signingConfig": "default",
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}
@@ -0,0 +1,3 @@
/node_modules
/.preview
/build
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
"apiType": 'stageMode',
"buildOption": {
},
"targets": [
{
"name": "default",
},
{
"name": "ohosTest",
}
]
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks
@@ -0,0 +1,5 @@
{
"name": "entry",
"version": "1.0.0",
"lockfileVersion": 1
}
@@ -0,0 +1,13 @@
{
"name": "entry",
"version": "1.0.0",
"ohos": {
"org": "ohos",
"buildTool": "hvigor",
"directoryLevel": "module"
},
"description": "example description",
"repository": {},
"license": "ISC",
"dependencies": {}
}
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import AbilityStage from "@ohos.application.AbilityStage"
import Logger from '../MainAbility/Logger';
export default class MyAbilityStage extends AbilityStage {
onCreate() {
Logger.info("[Demo] MyAbilityStage onCreate")
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class Logger {
private prefix: string;
constructor(prefix: string) {
this.prefix = prefix;
}
debug(...args: any[]) {
console.debug(`[${this.prefix}] ${args.join('')}`);
}
info(...args: any[]) {
console.log(`[${this.prefix}] ${args.join('')}`);
}
error(...args: any[]) {
console.error(`[${this.prefix}] ${args.join('')}`);
}
}
export default new Logger('Continuation Demo');
@@ -0,0 +1,160 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Ability from '@ohos.application.Ability'
import AbilityConstant from '@ohos.application.AbilityConstant'
import accessControl from "@ohos.abilityAccessCtrl";
import bundle from '@ohos.bundle';
import distributedObject from '@ohos.data.distributedDataObject';
import Logger from './Logger';
const BUNDLE_NAME = "com.ohos.continuationManualTestSuite.hmservice"
const PERMISSION_REJECT = -1
class ContentStorage {
}
var g_object = distributedObject.createDistributedObject({name:undefined});
export default class MainAbility extends Ability {
contentStorage : ContentStorage
sessionId : string
handleParam(want, launchParam) {
if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
this.sessionId = want.parameters.session
Logger.info(`continuation sessionId: ${this.sessionId}`)
g_object.name = undefined;
Logger.info(`set g_object.name undefined`)
g_object.setSessionId(this.sessionId); // set session id, so it will sync data from remote device
Logger.info(`g_object_name = ${g_object.name}`);
AppStorage.SetOrCreate<string>('ContinueStudy', g_object.name)
let workInput = want.parameters.work // get user data from want params
Logger.info(`work input ${workInput}`)
AppStorage.SetOrCreate<string>('ContinueWork', workInput)
this.contentStorage = new ContentStorage();
Logger.info('ready to restore');
this.context.restoreWindowStage(this.contentStorage);
}
}
onCreate(want, launchParam) {
Logger.info("[Demo] MainAbility onCreate")
globalThis.abilityWant = want;
this.handleParam(want, launchParam)
}
onContinue(wantParam : {[key: string]: any}) {
Logger.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`)
let workInput = AppStorage.Get<string>('ContinueWork');
Logger.info(`onContinue work input = ${workInput}`);
if (g_object.__sessionId === undefined) {
this.sessionId = distributedObject.genSessionId()
Logger.info(`onContinue generate new sessionId`)
}
else {
this.sessionId = g_object.__sessionId;
}
wantParam["session"] = this.sessionId
g_object.name = AppStorage.Get<string>('ContinueStudy');
Logger.info(`onContinue sessionId = ${this.sessionId}, name = ${g_object.name}`)
g_object.setSessionId(this.sessionId);
g_object.save(wantParam.targetDevice, (result, data)=>{
Logger.info("save callback");
Logger.info("save sessionId " + data.sessionId);
Logger.info("save version " + data.version);
Logger.info("save deviceId " + data.deviceId);
});
wantParam["work"] = workInput // set user input data into want params
return 0;
}
onNewWant(want, launchParam) {
Logger.info("MainAbility onNewWant")
this.handleParam(want, launchParam)
}
requestPermissions = async () => {
let permissions: Array<string> = [
"ohos.permission.DISTRIBUTED_DATASYNC"
];
let needGrantPermission = false
let accessManger = accessControl.createAtManager()
Logger.info("app permission get bundle info")
let bundleInfo = await bundle.getApplicationInfo(BUNDLE_NAME, 0, 100)
Logger.info(`app permission query permission ${bundleInfo.accessTokenId.toString()}`)
for (const permission of permissions) {
Logger.info(`app permission query grant status ${permission}`)
try {
let grantStatus = await accessManger.verifyAccessToken(bundleInfo.accessTokenId, permission)
if (grantStatus === PERMISSION_REJECT) {
needGrantPermission = true
break;
}
} catch (err) {
Logger.error(`app permission query grant status error ${permission} ${JSON.stringify(err)}`)
needGrantPermission = true
break;
}
}
if (needGrantPermission) {
Logger.info("app permission needGrantPermission")
try {
await this.context.requestPermissionsFromUser(permissions)
} catch (err) {
Logger.error(`app permission ${JSON.stringify(err)}`)
}
} else {
Logger.info("app permission already granted")
}
}
onDestroy() {
Logger.info("MainAbility onDestroy")
}
onWindowStageCreate(windowStage) {
// Main window is created, set main page for this ability
Logger.info("MainAbility onWindowStageCreate")
this.requestPermissions()
windowStage.setUIContent(this.context, "pages/index", null)
}
onWindowStageRestore(windowStage) {
Logger.info("MainAbility onWindowStageRestore")
this.requestPermissions()
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
Logger.info("MainAbility onWindowStageDestroy")
}
onForeground() {
// Ability has brought to foreground
Logger.info("MainAbility onForeground")
}
onBackground() {
// Ability has back to background
Logger.info("MainAbility onBackground")
}
};
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export default class pageName {
static page1 = "工作"
static page2 = "学习"
static backKey = "返回首页"
}
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import router from '@system.router';
import pageName from '../MainAbility/stringConst';
import Logger from '../MainAbility/Logger';
async function routePage(pageIndex) {
Logger.info("routePage");
let options = {
uri: pageIndex
}
try {
await router.push(options)
} catch (err) {
Logger.error(`fail callback, code: ${err.code}, msg: ${err.msg}`)
}
}
@Entry
@Component
struct Index {
@State message: string = '记事本(免安装)'
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button() {
Text(pageName.page1)
.fontSize(35)
.fontWeight(FontWeight.Bold)
}
.type(ButtonType.Normal)
.margin({
top: 30
})
.backgroundColor('#2cb3cb')
.onClick(() => routePage('pages/work'))
Button() {
Text(pageName.page2)
.fontSize(35)
.fontWeight(FontWeight.Bold)
}
.type(ButtonType.Normal)
.margin({
top: 60
})
.backgroundColor('#2cb3cb')
.onClick(() => routePage('pages/study'))
}
.width('100%')
.height('100%')
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import router from '@system.router';
import pageName from '../MainAbility/stringConst';
import Logger from '../MainAbility/Logger';
@Entry
@Component
struct Study {
private content: string = pageName.page2
@StorageLink('ContinueStudy') inputTxt2: string = '';
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text(`${this.content}`)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Column() {
TextArea({ placeholder: 'please input', text: this.inputTxt2 }) // restore user input data on ui
.textAlign(TextAlign.Start)
.onChange((value) => {
Logger.info(`TextInput onChange: ${value}`);
this.inputTxt2 = value;
AppStorage.Set('ContinueStudy', value);
})
.width('50%')
.height(50)
}
Button() {
Text(pageName.backKey)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.type(ButtonType.Capsule)
.margin({
top: 20
})
.backgroundColor('#0D9FFB')
.onClick(() => {
router.back()
})
}
.width('100%')
.height('100%')
}
}
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import router from '@system.router';
import pageName from '../MainAbility/stringConst';
import Logger from '../MainAbility/Logger';
@Entry
@Component
struct Work {
private content: string = pageName.page1;
@StorageLink('ContinueWork') inputTxt: string = '';
controller: CustomDialogController
cancel: () => void
confirm: () => void
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text(`${this.content}`)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Column() {
TextArea({placeholder:'please input', text:this.inputTxt}) // restore user input data on ui
.textAlign(TextAlign.Start)
.onChange((value) => {
Logger.info(`TextInput onChange: ${value}`);
this.inputTxt = value;
AppStorage.Set('ContinueWork', value);
})
.width('50%')
.height(50)
}
Button() {
Text(pageName.backKey)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
.type(ButtonType.Capsule)
.margin({
top: 60
})
.backgroundColor('#0D9FFB')
.onClick(() => {
router.back()
})
}
.width('100%')
.height('100%')
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
{
"module": {
"name": "entry",
"type": "entry",
"srcEntrance": "./ets/Application/AbilityStage.ts",
"description": "$string:entry_desc",
"mainElement": "MainAbility",
"deviceTypes": [
"phone",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": true,
"pages": "$profile:main_pages",
"uiSyntax": "ets",
"abilities": [
{
"name": "MainAbility",
"srcEntrance": "./ets/MainAbility/MainAbility.ts",
"description": "$string:MainAbility_desc",
"icon": "$media:icon",
"label": "$string:MainAbility_label",
"visible": true,
"continuable": true,
"launchType": "singleton",
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
],
"requestPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC"
},
]
}
}
@@ -0,0 +1,16 @@
{
"string": [
{
"name": "entry_desc",
"value": "description"
},
{
"name": "MainAbility_desc",
"value": "description"
},
{
"name": "MainAbility_label",
"value": "单实例迁移"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,7 @@
{
"src": [
"pages/index",
"pages/work",
"pages/study"
]
}
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
module.exports = require('@ohos/hvigor-ohos-plugin').appTasks
@@ -0,0 +1,17 @@
{
"name": "myapplication",
"version": "1.0.0",
"ohos": {
"org": "ohos",
"buildTool": "hvigor",
"directoryLevel": "project"
},
"description": "example description",
"repository": {},
"license": "ISC",
"dependencies": {
"hypium": "^1.0.0",
"@ohos/hvigor": "1.0.6",
"@ohos/hvigor-ohos-plugin": "1.0.6"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB