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