• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 应用触发数据备份/恢复(仅对系统应用开放)
2<!--Kit: Core File Kit-->
3<!--Subsystem: FileManagement-->
4<!--Owner: @lvzhenjie-->
5<!--Designer: @wang_zhangjun; @chenxi0605-->
6<!--Tester: @liuhonggang123-->
7<!--Adviser: @foryourself-->
8
9备份恢复框架是为设备上的应用、服务提供自身数据备份和恢复的解决方案。系统应用开发者可以根据需求,按下述指导开发应用,以触发备份/恢复数据。
10
11- [获取能力文件](#获取能力文件):获取当前系统用户内所有应用与备份恢复相关基础信息的能力文件。能力文件在应用备份/恢复数据时不可缺少。
12
13- [应用备份数据](#应用备份数据):根据能力文件提供的应用信息,选择需要备份的应用数据并进行备份。
14
15- [应用恢复数据](#应用恢复数据):根据能力文件提供的应用信息,选择需要恢复的应用数据并进行恢复。
16
17## 开发说明
18
19备份恢复API的使用指导请参见[API参考](../reference/apis-core-file-kit/js-apis-file-backup-sys.md)。
20
21在使用备份恢复接口之前,需要:
22
231. [申请应用权限](../security/AccessToken/determine-application-mode.md#system_basic等级应用申请权限的方式):`ohos.permission.BACKUP`
24
252. 导入依赖模块:`@ohos.file.backup`
26
27   ```js
28   import { backup } from '@kit.CoreFileKit';
29   ```
30
31## 获取能力文件
32
33获取当前系统用户内所有应用与备份恢复相关基础信息的能力文件。能力文件在应用备份恢复数据时是不可缺少的,开发者可以根据需要获取能力文件。
34
35该文件包含设备类型、设备版本、应用的基础性信息。如应用名称、应用数据大小、应用版本信息、是否支持备份恢复、是否在恢复时安装应用。
36
37调用[backup.getLocalCapabilities()](../reference/apis-core-file-kit/js-apis-file-backup-sys.md#backupgetlocalcapabilities)获取能力文件。
38
39```ts
40import { fileIo as fs, backup } from '@kit.CoreFileKit';
41import { common } from '@kit.AbilityKit';
42import { BusinessError } from '@kit.BasicServicesKit';
43
44// 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
45let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
46async function getLocalCapabilities(context: common.UIAbilityContext): Promise<void> {
47 try {
48   let filesDir = context.filesDir;
49   let fileData = await backup.getLocalCapabilities();
50   console.info('getLocalCapabilities success');
51   let fpath = filesDir + '/localCapabilities.json';
52   fs.copyFileSync(fileData.fd, fpath);
53   fs.closeSync(fileData.fd);
54 } catch (error) {
55   let err: BusinessError = error as BusinessError;
56   console.error(`getLocalCapabilities failed with err, code is ${err.code}, message is ${err.message}`);
57 }
58}
59```
60
61**返回的能力文件内容示例:**
62
63| 属性名称       | 数据类型 | 必填 | 含义                   |
64| -------------- | -------- | ---- | ---------------------- |
65| bundleInfos    | 数组     | 是   | 应用信息列表。           |
66| allToBackup    | 布尔值   | 是   | 是否允许备份恢复。true表示允许,false表示不允许。       |
67| extensionName  | 字符串   | 是   | 应用的扩展名。           |
68| name           | 字符串   | 是   | 应用的包名。             |
69| spaceOccupied  | 数值     | 是   | 应用数据占用的空间大小(单位为Byte)。 |
70| versionCode    | 数值     | 是   | 应用的版本号。           |
71| versionName    | 字符串   | 是   | 应用的版本名称。         |
72| deviceType     | 字符串   | 是   | 设备类型。               |
73| systemFullName | 字符串   | 是   | 设备版本。               |
74
75```json
76{
77"bundleInfos" :[{
78 "allToBackup" : true,
79 "extensionName" : "BackupExtensionAbility",
80 "name" : "com.example.hiworld",
81 "needToInstall" : false,
82 "spaceOccupied" : 0,
83 "versionCode" : 1000000,
84 "versionName" : "1.0.0"
85 }],
86"deviceType" : "default",
87"systemFullName" : "OpenHarmony-4.0.0.0"
88}
89```
90
91## 应用备份数据
92
93开发者可以根据能力文件提供的应用信息,选择需要备份的应用数据。
94
95备份过程中,备份恢复服务会将应用的数据打包成文件,打包后的文件会以打开的文件句柄形式,通过创建实例时所注册的回调[onFileReady](../reference/apis-core-file-kit/js-apis-file-backup-sys.md#onfileready)接口返回。
96
97开发者可以根据需要将文件内容保存到本地。
98
99**示例**
100
101  ```ts
102  import { fileIo as fs, backup } from '@kit.CoreFileKit';
103  import { common } from '@kit.AbilityKit';
104  import { BusinessError } from '@kit.BasicServicesKit';
105  let appFileDir: string = '';
106  // 请在组件内获取context,确保this.getUIContext().getHostContext()返回结果为UIAbilityContext
107  let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
108  appFileDir = context.filesDir;
109  // 创建SessionBackup类的实例用于备份数据
110  let g_session: backup.SessionBackup;
111  function createSessionBackup(fileDir: string): backup.SessionBackup {
112    let generalCallbacks: backup.GeneralCallbacks = {
113      // onFileReady为服务回调给应用侧数据完成的通知,建议开发者在该接口内不要进行过多的耗时实现,可以通过异步线程实现file.fd数据的处理
114      onFileReady: (err: BusinessError, file: backup.File) => {
115        if (err) {
116          console.error(`onFileReady err, code is ${err.code}, message is ${err.message}`);
117        }
118        try {
119          let bundlePath = appFileDir + '/' + file.bundleName;
120          if (!fs.accessSync(bundlePath)) {
121            fs.mkdirSync(bundlePath);
122          }
123          // 此处执行copyFileSync会多一次内存拷贝,开发者可以直接使用onFileReady的file.fd来进行数据出来,处理完成后close即可,这样会减少内存消耗
124          fs.copyFileSync(file.fd, bundlePath + `/${file.uri}`);
125          fs.closeSync(file.fd);
126          console.info('onFileReady success');
127        } catch (e) {
128          console.error('onFileReady failed with err: ' + e);
129        }
130      },
131      onBundleBegin: (err: BusinessError<string|void>, bundleName: string) => {
132        if (err) {
133          console.error(`onBundleBegin err, code is ${err.code}, message is ${err.message}`);
134        } else {
135          console.info('onBundleBegin bundleName: ' + bundleName);
136        }
137      },
138      onBundleEnd: (err: BusinessError<string|void>, bundleName: string) => {
139        if (err) {
140          console.error(`onBundleEnd err, code is ${err.code}, message is ${err.message}`);
141        } else {
142          console.info('onBundleEnd bundleName: ' + bundleName);
143        }
144      },
145      onAllBundlesEnd: (err: BusinessError) => {
146        if (err) {
147          console.error(`onAllBundlesEnd err, code is ${err.code}, message is ${err.message}`);
148        } else {
149          console.info('onAllBundlesEnd');
150        }
151      },
152      onBackupServiceDied: () => {
153        console.info('onBackupServiceDied');
154      },
155      onResultReport: (bundleName: string, result: string) => {
156        console.info('onResultReport  bundleName: ' + bundleName);
157        console.info('onResultReport  result: ' + result);
158      },
159      onProcess:(bundleName: string, process: string) => {
160        console.info('onPross bundleName: ' + JSON.stringify(bundleName));
161        console.info('onPross result: ' + JSON.stringify(process));
162      }
163    }
164    let sessionBackup = new backup.SessionBackup(generalCallbacks);
165    return sessionBackup;
166  }
167
168  async function sessionBackup (fileDir: string): Promise<void> {
169    g_session = createSessionBackup(fileDir);
170    // 此处可根据backup.getLocalCapabilities()提供的能力文件,选择需要备份的应用
171    // 也可直接根据应用包名称进行备份
172    const backupApps: string[] = [
173      "com.example.hiworld",
174    ]
175    await g_session.appendBundles(backupApps);
176    console.info('appendBundles success');
177  }
178  ```
179
180## 应用恢复数据
181
182开发者可以根据能力文件提供的应用信息,选择需要恢复的应用数据。
183
184恢复过程中,备份恢复服务会根据开发者调用[getFileHandle](../reference/apis-core-file-kit/js-apis-file-backup-sys.md#getfilehandle)的请求内容,将应用待恢复数据的文件句柄,通过创建实例时注册的回调[onFileReady](../reference/apis-core-file-kit/js-apis-file-backup-sys.md#onfileready)接口返回。可以根据返回的[uri](../reference/apis-core-file-kit/js-apis-file-backup-sys.md#filemeta)将应用对应的待恢复数据写入到文件句柄中。写入完成后开发者调用[publishFile](../reference/apis-core-file-kit/js-apis-file-backup-sys.md#publishfile)通知服务写入完成。
185
186待应用所有恢复数据准备就绪后,服务开始恢复应用数据。
187
188**示例**
189
190  ```ts
191  import { backup, fileIo as fs } from '@kit.CoreFileKit';
192  import { BusinessError } from '@ohos.base';
193  // 创建SessionRestore类的实例用于恢复数据
194  let g_session: backup.SessionRestore;
195  let initMap = new Map<string, number>();
196  let testFileNum = 123; // 123: 初始化文件个数
197  let testBundleName = 'com.example.myapplication'; // 测试包名
198  initMap.set(testBundleName, testFileNum);
199  let countMap = new Map<string, number>();
200  countMap.set(testBundleName, 0); // 初始化计数
201  async function publishFile(file: backup.File): Promise<void> {
202    let fileMeta: backup.FileMeta = {
203      bundleName: file.bundleName,
204      uri: ''
205    }
206    await g_session.publishFile(fileMeta);
207  }
208  function createSessionRestore(): backup.SessionRestore {
209    let generalCallbacks: backup.GeneralCallbacks = {
210      onFileReady: (err: BusinessError, file: backup.File) => {
211        if (err) {
212          console.error(`onFileReady err, code is ${err.code}, message is ${err.message}`);
213        }
214        // 此处开发者请根据实际场景待恢复文件存放位置进行调整 bundlePath
215        let bundlePath: string = '';
216        if (!fs.accessSync(bundlePath)) {
217          console.info('onFileReady bundlePath err : ' + bundlePath);
218        }
219        fs.copyFileSync(bundlePath, file.fd);
220        fs.closeSync(file.fd);
221        // 恢复数据传输完成后,会通知服务端文件准备就绪
222        let cnt = countMap.get(file.bundleName) || 0;
223        countMap.set(file.bundleName, cnt + 1);
224        if (countMap.get(file.bundleName) == initMap.get(file.bundleName)) { // 每个包的所有文件收到后触发publishFile
225          publishFile(file);
226        }
227        console.info('onFileReady success');
228      },
229      onBundleBegin: (err: BusinessError<string|void>, bundleName: string) => {
230        if (err) {
231          console.error(`onBundleBegin failed with err, code is ${err.code}, message is ${err.message}`);
232        }
233        console.info('onBundleBegin success');
234      },
235      onBundleEnd: (err: BusinessError<string|void>, bundleName: string) => {
236        if (err) {
237          console.error(`onBundleEnd failed with err, code is ${err.code}, message is ${err.message}`);
238        }
239        console.info('onBundleEnd success');
240      },
241      onAllBundlesEnd: (err: BusinessError) => {
242        if (err) {
243          console.error(`onAllBundlesEnd failed with err, code is ${err.code}, message is ${err.message}`);
244        }
245        console.info('onAllBundlesEnd success');
246      },
247      onBackupServiceDied: () => {
248        console.info('service died');
249      },
250      onResultReport: (bundleName: string, result: string) => {
251        console.info('onResultReport  bundleName: ' + bundleName);
252        console.info('onResultReport  result: ' + result);
253      },
254      onProcess:(bundleName: string, process: string) => {
255        console.info('onProcess bundleName: ' + bundleName);
256        console.info('onProcess result: ' + process);
257      }
258    }
259    let sessionRestore = new backup.SessionRestore(generalCallbacks);
260    return sessionRestore;
261  }
262
263  async function restore01 (): Promise<void> {
264    g_session = createSessionRestore();
265    const restoreApps: string[] = [
266      "com.example.hiworld",
267    ]
268    // 能力文件的获取方式可以根据开发者实际场景进行调整。此处仅为请求示例
269    // 开发者也可以根据能力文件内容的结构示例,自行构造能力文件内容
270    let fileData = await backup.getLocalCapabilities();
271    await g_session.appendBundles(fileData.fd, restoreApps);
272    console.info('appendBundles success');
273    // 添加需要恢复的应用成功后,请根据需要恢复的应用名称,调用getFileHandle接口获取待恢复应用数文件的文件句柄
274    // 应用待恢复数据文件数请依据实际备份文件个数为准,此处仅为请求示例
275    let handle: backup.FileMeta = {
276      bundleName: restoreApps[0],
277      uri: "manage.json"
278    }
279    await g_session.getFileHandle(handle);
280    handle.uri = "1.tar";
281    await g_session.getFileHandle(handle);
282    console.info('getFileHandle success');
283  }
284  ```
285