鸿蒙HarmonyOS应用开发——跨端迁移

在用户使用设备的过程中,当使用情境发生变化时(例如从室内走到户外或者周围有更适合的设备等),之前使用的设备可能已经不适合继续当前的任务,此时,用户可以选择新的设备来继续当前的任务,原设备可按需决定是否退出任务,这个就是跨端迁移的场景。常见的跨端迁移场景实例:在平板上播放的视频,迁移到智慧屏继续播放,从而获得更佳的观看体验;平板上的视频应用退出。在应用开发层面,跨端迁移指在A端运行的UIAbility迁移到B端上,完成迁移后,B端UIAbility继续任务,而A端UIAbility可按需决定是否退出。

跨端迁移的核心任务是将应用的当前状态(包括页面控件、状态变量等)无缝迁移到另一设备,从而在新设备上无缝接续应用体验。这意味着用户在一台设备上进行的操作可以在另一台设备的相同应用中快速切换并无缝衔接。

主要功能包括:

  • 支持用户自定义数据存储及恢复。

  • 支持页面路由信息和页面控件状态数据的存储及恢复。

  • 支持应用兼容性检测。

  • 支持应用根据实际使用场景动态设置迁移状态(默认迁移状态为 ACTIVE 激活状态)。例如,编辑类应用在编辑文本的页面下才需要迁移,其他页面不需要迁移,则可以通过setMissionContinueState进行控制。

  • 支持应用动态选择是否进行页面栈恢复(默认进行页面栈信息恢复)。例如,应用希望自定义迁移到其他设备后显示的页面,则可以通过SUPPORT_CONTINUE_PAGE_STACK_KEY进行控制。

  • 支持应用动态选择迁移成功后是否退出迁移源端应用(默认迁移成功后退出迁移源端应用)。可以通过SUPPORT_CONTINUE_SOURCE_EXIT_KEY进行控制。

说明:
开发者可以开发具有迁移能力的应用,迁移的触发由系统应用完成。

运作机制

  1. 在源端,通过UIAbilityonContinue()回调,开发者可以保存待接续的业务数据。例如,在浏览器应用中完成跨端迁移,开发者需要使用 onContinue()回调保存页面URL等业务内容,而系统将自动保存页面状态,如当前浏览进度。
  2. 分布式框架提供了跨设备应用界面、页面栈以及业务数据的保存和恢复机制,它负责将数据从源端发送到对端。
  3. 在对端,同一UIAbility可以通过 onCreate()/onNewWant()接口来恢复业务数据。

约束限制

  • 跨端迁移要求在同一UIAbility之间进行,也就是需要相同的bundleNameabilityName和签名信息。
  • 为了获得最佳体验,使用wantParam传输的数据需要控制在100KB以下。
  • 当前部分ArkUI组件支持迁移后,将特定状态恢复到对端设备。

开发步骤

  1. 需要申请ohos.permission.DISTRIBUTED_DATASYNC权限。

  2. 同时需要在应用首次启动时弹窗向用户申请授权,使用方式请参见 向用户申请授权 。

  3. 在 module.json5配置文件 的abilities标签中配置跨端迁移标签continuable

   {
     "module": {
       // ...
       "abilities": [
         {
           // ...
           "continuable": true, // 配置UIAbility支持迁移
         }
       ]
     }
   }

说明:
根据需要配置应用启动模式类型,配置详情请参照UIAbility组件启动模式。

  1. 在源端UIAbility中实现 onContinue() 回调。

UIAbility实例触发迁移时,onContinue() 回调在源端被调用,开发者可以在该接口中保存迁移数据,实现应用兼容性检测,决定是否支持此次迁移。

  • 保存迁移数据:开发者可以将要迁移的数据通过键值对的方式保存在wantParam参数中。
  • 应用兼容性检测:开发者可以通过从wantParam参数中获取对端应用的版本号与 源端应用版本号做兼容性校验。开发者可以在触发迁移时从onContinue()回调中wantParam.version获取到迁移对端应用的版本号与迁移源端应用版本号做兼容校验。
  • 迁移决策:开发者可以通过 onContinue() 回调的返回值决定是否支持此次迁移。
   import UIAbility from '@ohos.app.ability.UIAbility';
   import AbilityConstant from '@ohos.app.ability.AbilityConstant';

   export default class EntryAbility extends UIAbility {
     onContinue(wantParam: Record<string, Object>):AbilityConstant.OnContinueResult {
       let version = wantParam.version;
       let targetDevice = wantParam.targetDevice;
       console.info(`onContinue version = ${version}, targetDevice: ${targetDevice}`); // 准备迁移数据

       // 获取源端版本号
       let versionSrc: number = -1; // 请填充具体获取版本号的代码

       // 兼容性校验
       if (version !== versionSrc) {
         // 在兼容性校验不通过时返回MISMATCH
         return AbilityConstant.OnContinueResult.MISMATCH;
       }

       // 将要迁移的数据保存在wantParam的自定义字段(例如data)中
       const continueInput = '迁移的数据';
       wantParam['data'] = continueInput;

       return AbilityConstant.OnContinueResult.AGREE;
     }
   }
  1. 源端设备UIAbility实例在冷启动和热启动情况下分别会调用不同的接口来恢复数据和加载UI。
    在对端设备的UIAbility中,需要实现 onCreate()/onNewWant()接口来恢复迁移数据。

通过在 onCreate() / onNewWant() 回调中检查launchReason,可以判断此次启动是否有迁移触发。开发者可以从want中获取之前保存的迁移数据,并在数据恢复后调用restoreWindowStage()来触发页面恢复,包括页面栈信息。

   import UIAbility from '@ohos.app.ability.UIAbility';
   import AbilityConstant from '@ohos.app.ability.AbilityConstant';
   import Want from '@ohos.app.ability.Want';

   export default class EntryAbility extends UIAbility {
     storage : LocalStorage = new LocalStorage();

     onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
       console.info('EntryAbility onCreate')
       if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
         // 将上述的保存的数据取出恢复
         let continueInput = '';
         if (want.parameters != undefined) {
           continueInput = JSON.stringify(want.parameters.data);
           console.info(`continue input ${continueInput}`)
         }
         // 将数据显示当前页面
         this.context.restoreWindowStage(this.storage);
       }
     }

     onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        console.info('EntryAbility onNewWant')
        if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
          // get user data from want params
          let continueInput = '';
          if (want.parameters != undefined) {
            continueInput = JSON.stringify(want.parameters.data);
            console.info(`continue input ${continueInput}`);
          }
          this.context.restoreWindowStage(this.storage);
        }
      }
   }

可选配置迁移能力

动态配置迁移能力

从API version 10开始,提供了支持动态配置迁移能力的功能。即应用可以根据实际使用场景,在需要迁移时开启应用迁移能力;在业务不需要迁移时则可以关闭迁移能力。

开发者可以通过调用 setMissionContinueState() 接口对迁移能力进行设置。默认状态下,应用的迁移能力为ACTIVE状态,即迁移能力开启,可以迁移。

设置迁移能力的时机

迁移能力的改变可以根据实际业务需求和代码实现,发生在应用生命周期的绝大多数时机。本文介绍常用的几种配置方式。

UIAbilityonCreate() 回调中调用接口,可以在应用创建时设置应用的迁移状态。

// EntryAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import Want from '@ohos.app.ability.Want';

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // ...
    this.context.setMissionContinueState(AbilityConstant.ContinueState.INACTIVE, (result) => {
      console.info(`setMissionContinueState: ${JSON.stringify(result)}`);
    });
    // ...
  }
}

在页面的onPageShow()回调中调用接口,可以设置单个页面出现时应用的迁移状态。

// PageName.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import common from '@ohos.app.ability.common';
@Entry
@Component
struct PageName {
  private context = getContext(this) as common.UIAbilityContext;
  build() {
    // ...
  }
  // ...
  onPageShow(){
  // 进入该页面时,将应用设置为可迁移状态
    this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
      console.info(`setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
    });
  }
}

在某个组件的触发事件中设置应用迁移能力。

// PageName.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import common from '@ohos.app.ability.common';

@Entry
@Component
struct PageName {
  private context = getContext(this) as common.UIAbilityContext;
  build() {
    // ...
    Button() {
      // ...
    }.onClick(()=>{
    // 点击该按钮时,将应用设置为可迁移状态
      this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
        console.info(`setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
      });
    })
  }
}

保证迁移连续性

由于迁移加载时,对端拉起的应用可能执行过自己的迁移状态设置命令(例如,冷启动时对端在 onCreate() 中设置了 INACTIVE ;热启动时对端已打开了不可迁移的页面,迁移状态为 INACTIVE 等情况)。为了保证迁移过后的应用依然具有可以迁移回源端的能力,应在  onCreate()/ onNewWant() 的迁移调用判断中,将迁移状态设置为 ACTIVE 。

// EntryAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import Want from '@ohos.app.ability.Want';

export default class EntryAbility extends UIAbility {
  // ...
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // ...
    // 调用原因为迁移时,设置状态为可迁移,应对冷启动情况
    this.context.setMissionContinueState(AbilityConstant.ContinueState.INACTIVE, (result) => {
        console.info(`setMissionContinueState INACTIVE result: ${JSON.stringify(result)}`);
    });
  }

  onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    // ...
    // 调用原因为迁移时,设置状态为可迁移,应对热启动情况
    if (launchParam.launchReason == AbilityConstant.LaunchReason.CONTINUATION) {
      this.context.setMissionContinueState(AbilityConstant.ContinueState.ACTIVE, (result) => {
        console.info(`setMissionContinueState ACTIVE result: ${JSON.stringify(result)}`);
      });
    }
  }
  // ...
}

按需迁移页面栈

支持应用动态选择是否进行页面栈恢复(默认进行页面栈信息恢复)。如果应用不想使用系统默认恢复的页面栈,则可以设置不进行页面栈迁移,而需要在onWindowStageRestore()设置迁移后进入的页面,参数定义见SUPPORT_CONTINUE_PAGE_STACK_KEY。

应用在源端的页面栈中存在Index和Second路由,而在对端恢复时不需要按照源端页面栈进行恢复,需要恢复到指定页面。

例如,UIAbility迁移不需要自动迁移页面栈信息。

// EntryAbility.ets
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import wantConstant from '@ohos.app.ability.wantConstant';
import window from '@ohos.window';

export default class EntryAbility extends UIAbility {
  // ...

  onContinue(wantParam: Record<string, Object>) {
    console.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`);
    wantParam[wantConstant.Params.SUPPORT_CONTINUE_PAGE_STACK_KEY] = false;
    return AbilityConstant.OnContinueResult.AGREE;
  }

  onWindowStageRestore(windowStage: window.WindowStage) {
      // 若不需要自动迁移页面栈信息,则需要在此处设置应用迁移后进入的页面
    windowStage.loadContent('pages/Index', (err, data) => {
      if (err.code) {
        return;
      }
    });
  }
}

按需退出

支持应用动态选择迁移成功后是否退出迁移源端应用(默认迁移成功后退出迁移源端应用)。如果应用不想让系统自动退出迁移源端应用,则可以设置不退出,参数定义见SUPPORT_CONTINUE_SOURCE_EXIT_KEY。

示例:UIAbility设置迁移成功后,源端不需要退出迁移应用。

import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import wantConstant from '@ohos.app.ability.wantConstant';

export default class EntryAbility extends UIAbility {
  // ...

  onContinue(wantParam: Record<string, Object>) {
    console.info(`onContinue version = ${wantParam.version}, targetDevice: ${wantParam.targetDevice}`);
    wantParam[wantConstant.Params.SUPPORT_CONTINUE_SOURCE_EXIT_KEY] = false;
    return AbilityConstant.OnContinueResult.AGREE;
  }
}

验证指导

为方便开发者验证已开发的可迁移应用,当前OpenHarmony提供了一个全局任务中心demo作为迁移的入口。下面介绍通过安装全局任务中心来验证迁移的方式。

1. 编译安装全局任务中心

配置环境

public-SDK不支持开发者使用所有的系统API,例如:全局任务中心使用的**@ohos.distributedDeviceManager**不包括在public_SDK中。因此为了正确编译安装全局任务中心,开发者需要替换full-SDK,具体操作可参见 替换指南。

说明
本文中的截图仅为参考,具体的显示界面请以实际使用的DevEco Studio和SDK的版本为准。

编译工程文件

​ a.新建OpenHarmony 空的工程,找到对应的文件夹替换下载文件

​ b.自动签名,编译安装。

​ DevEco的自动签名模板默认签名权限为normal级。而本应用设计到ohos.permission.MANAGE_MISSIONS权限为system_core级别。自动生成的签名无法获得足够的权限,所以需要将权限升级为system_core级别,然后签名。

​ c.系统权限设置(以api10目录为例): 将Sdk目录下的openharmony\api版本(如:10)\toolchains\lib\UnsgnedReleasedProfileTemplate.json文件中的”apl”:“normal_core”改为”apl”:“system_core”。

  1. 点击file->Project Structure。

  1. 点击Signing Configs 点击OK。

  1. 连接开发板运行生成demo。

2. 设备组网

  1. 打开A,B两设备的计算器。
  2. 点击右上角箭头选择B设备。
  3. 在B设备选择信任设备,弹出PIN码。
  4. 在A设备输入PIN码。
  5. 已组网成功,验证方法:在A设备输入数字,B设备同步出现则证明组网成功。

3. 发起迁移

  1. 在B设备打开多设备协同权限的应用,A设备打开全局任务中心demo,A设备出现A设备名称(即:本机:OpenHarmony 3.2)和B设备名称(OpenHarmony 3.2)。

  1. 点击B设备名称,然后出现B设备的应用。

  1. 最后将应用拖拽到A设备名称处,A设备应用被拉起,B设备应用退出。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/491109.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【前端Vue】Vue3+Pinia小兔鲜电商项目第3篇:静态结构搭建和分类实现,1. 整体结构创建【附代码文档】

Vue3ElementPlusPinia开发小兔鲜电商项目完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;认识Vue3&#xff0c;使用create-vue搭建Vue3项目1. Vue3组合式API体验,2. Vue3更多的优势,1. 认识create-vue,2. 使用create-vue创建项目,1. setup选项的写法和执行…

v4l2采集视频

Video4Linux2&#xff08;v4l2&#xff09;是用于Linux系统的视频设备驱动框架&#xff0c;它允许用户空间应用程序直接与视频设备&#xff08;如摄像头、视频采集卡等&#xff09;进行交互。 linux系统下一切皆文件&#xff0c;对视频设备的操作就像对文件的操作一样&#xff…

标题:深入了解 JavaScript 中的字符串分割:遇到 / 和 | 都分割

在 JavaScript 中&#xff0c;处理字符串是一项常见的任务。有时候&#xff0c;我们需要将字符串按照特定的字符进行分割&#xff0c;以提取或操作其中的各个部分。在这篇博客中&#xff0c;我们将深入探讨如何使用 JavaScript 的字符串分割功能&#xff0c;特别是当遇到斜杠 /…

汽车后视镜反射率检测光纤光谱仪:安全驾驶的守护神

在汽车的日常使用中&#xff0c;后视镜扮演着至关重要的角色。它不仅帮助驾驶员观察车辆后方的情况&#xff0c;还确保了行车的安全性。然而&#xff0c;由于各种原因&#xff0c;后视镜的反射率可能会降低&#xff0c;从而影响到驾驶员的视线范围和判断能力。为了解决这一问题…

Reactor 模式全解:实现非阻塞 I/O 多路复用

Reactor网络模式是什么&#xff1f; Reactor网络模式时目前网络最常用的网络模式。如果你使用Netty&#xff0c;那么你在使用Reactor;如果你使用Twisted,那么你子啊使用Reactor;如果你使用netpoll&#xff0c;那么你在使用Reactor。 这里先给出答案&#xff1a;Reactor I/O多…

Python与供应链-2预测误差及指数平滑需求预测模型

主要介绍预测误差和指数平滑模型的相关理论,然后再通过Python的statsmodels封装的指数平滑函数预测需求。 1预测误差 预测误差是指预测结果与预测对象发展变化的真实结果之间的差距。这种误差分为绝对误差和相对误差。绝对误差是预测值与实际观测值的绝对差距,而相对误差则…

Spring学习——什么是循环依赖及其解决方式

文章目录 前言一、什么是循环依赖二、解决思路1、循环依赖分类2、对象初始化步骤及对象分类3、spring是如何解决的4、图解5、三级缓存1、区别2、ObjectFactory是什么 三、源码debug1、spring创建对象过程1、dubug第一步——找到getBean2、dubug第二步——getBean与doGetBean3、…

35.基于SpringBoot + Vue实现的前后端分离-在线考试系统(项目 + 论文)

项目介绍 本站是一个B/S模式系统&#xff0c;采用SpringBoot Vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得基于SpringBoot Vue技术的在线考试系统设计与实现管理工作系统…

Uniapp三种常用提示框

具体参数方法可参考: uniapp交互反馈 uni.showToast(OBJECT) //显示消息提示框。 uni.hideToast() //隐藏消息提示框。 //具体使用 uni.showToast({title: 新增成功,duration: 2000 }); uni.showLoading(OBJECT) //显示 loading 提示框, 需主动调用 uni.hideLoading 才能关闭提…

区块链安全之DDoS防护的重要性及其实施策略

随着区块链技术的不断发展和广泛应用&#xff0c;其安全问题也日益凸显。其中&#xff0c;分布式拒绝服务(DDoS)攻击是对区块链网络稳定性和效率构成潜在威胁的重要因素之一。本文旨在深入探讨区块链为何需要采取DDoS高防措施&#xff0c;并提出相应的防护策略。 一、区块链面…

毕马威:量子计算成未来3-5年重大挑战

毕马威&#xff08;KPMG&#xff09;是一家全球性的专业服务网络&#xff0c;其历史可追溯到19世纪末。作为“四大”会计师事务所之一&#xff0c;毕马威在审计、税务和咨询服务领域享有盛誉。公司在全球范围内拥有多个办事处&#xff0c;服务遍及各个行业&#xff0c;包括金融…

【大数据】Flink学习笔记

认识Flink Docker安装Flink version: "2.1" services:jobmanager:image: flinkexpose:- "6123"ports:- "20010:8081"command: jobmanagerenvironment:- JOB_MANAGER_RPC_ADDRESSjobmanagertaskmanager:image: flinkexpose:- "6121"- …

Visio Viewer for Mac(Visio文件查看工具)

Visio Viewer for Mac是一款专为Mac用户设计的Microsoft Visio文件查看器。它拥有直观易用的用户界面&#xff0c;使得用户可以快速加载和显示Visio文件&#xff0c;无需安装完整的Microsoft Visio软件。 软件下载&#xff1a;Visio Viewer for Mac3.1.0激活版 Visio Viewer fo…

java Web线上网游商品交易平台用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 jsp线上网游商品交易平台是一套完善的web设计系统&#xff0c;对理解JSP java SERLVET mvc编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0…

spring使用内置jetty创建提供http接口服务

1、添加pom文件依赖 <dependency><groupId>org.eclipse.jetty</groupId><artifactId>jetty-server</artifactId><version>9.4.22.v20191022</version> </dependency> <dependency><groupId>org.eclipse.jetty<…

azure服务器通过手机客户端远程连接

下载客户端 输入ip地址 输入用户名和密码 连接成功 人工智能学习网站&#xff1a; https://chat.xutongbao.top

大鱼来客实景无人直播系统源码开发部署---支持OEM贴牌-无限开户

实景无人直播系统需要包含以下几个主要功能&#xff1a; 视频采集与编码&#xff1a;使用摄像头或其他视频设备进行视频采集&#xff0c;并对视频进行编码压缩&#xff0c;以便实现实时传输。 视频传输与接收&#xff1a;将编码后的视频通过网络传输至客户端&#xff0c;客户端…

探究 HTTPS 的工作过程

目录 1. HTTPS 协议原理 1.1. 为什么要有HTTPS协议 1.2. 如何理解安全 1.3. HTTPS 协议是什么 2. HTTPS 的前置概念 2.1. 什么是加密 && 解密 2.2. 为什么要加密 2.3. 常见的加密方式 2.3.1. 对称加密 2.3.2. 非对称加密 2.4. 数据摘要 && 数据指纹…

Avalonia11.0.2+.Net6.0支持多语言,国际化

Avalonia11.0.2+.Net6.0支持多语言,国际化 操作系统项目结构最终效果具体实现安装Prism.Avalonia准备多语言文件语言资源加载类界面标记扩展类界面中使用国际化VM具体实现VM里面使用多语言方法操作系统 项目结构 最

【jenkins+cmake+svn管理c++项目】windows修改jenkins的工作目录

jenkins默认的存放源码的workspace是&#xff1a; C:\Users\用户\AppData\Local\Jenkins\.jenkins\workspace。由于jenkins会拉取大量的源代码以及编译生成一些文件&#xff0c;我希望我能自己指定目录作为它的工作空间&#xff0c;放在这里显然不太合适。 那么修改目录的方式有…