app-file-backup.md 14.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
# 应用触发数据备份/恢复(仅对系统应用开放)

备份恢复是为设备上应用数据、公共数据和系统服务提供的完整的数据备份和恢复解决方案。系统应用开发者可以根据需求,按下述指导开发应用,以触发备份/恢复数据。

- [获取能力文件](#获取能力文件):获取当前系统用户内所有应用与备份恢复相关基础信息的能力文件。能力文件在应用备份/恢复数据时不可缺少。

- [应用备份数据](#应用备份数据):根据能力文件提供的应用信息,选择需要备份的应用数据并进行备份。

- [应用恢复数据](#应用恢复数据):根据能力文件提供的应用信息,选择需要恢复的应用数据并进行恢复。

- [应用恢复数据时安装应用](#应用恢复数据时安装应用):应用恢复数据的拓展功能,当用于恢复数据的应用未安装时,建议使用此功能,设备将先安装应用再恢复数据。

## 开发说明

备份恢复API的使用指导请参见[API参考](../reference/apis/js-apis-file-backup.md)

在使用备份恢复接口之前,需要:

1. [申请相关权限](../security/accesstoken-guidelines.md)`ohos.permission.BACKUP`

2. 导入依赖模块:`@ohos.file.backup`
   
   ```js
   import backup from '@ohos.file.backup';
   ```

## 获取能力文件

获取当前系统用户内所有应用与备份恢复相关基础信息的能力文件。能力文件在应用备份恢复数据时是不可缺少的,开发者可以根据需要获取能力文件。

该文件包含设备类型、设备版本、应用的基础性信息,如应用名称、应用数据大小、应用版本信息、是否支持备份恢复、是否在恢复时安装应用。

调用`backup.getLocalCapabilities()`获取能力文件。

35
 ```ts
36 37
  import backup from '@ohos.file.backup';
  import common from '@ohos.app.ability.common';
38
  import fs from '@ohos.file.fs';
39 40 41 42 43

  // 获取应用文件路径
  let context = getContext(this) as common.UIAbilityContext;
  let filesDir = context.filesDir;

44 45 46 47
  async function getLocalCapabilities() {
    try {
      let fileData = await backup.getLocalCapabilities();
      console.info('getLocalCapabilities success');
48
      let fpath = filesDir + '/localCapabilities.json';
49 50
      fs.copyFileSync(fileData.fd, fpath);
      fs.closeSync(fileData.fd);
51 52 53
    } catch (error) {
      let err: BusinessError = error as BusinessError;
      console.error('getLocalCapabilities failed with err: ' + JSON.stringify(err));
54 55
    }
  }
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
 ```

 **返回的能力文件内容示例:**
 | 属性名称       | 数据类型 | 必填 | 含义                   |
 | -------------- | -------- | ---- | ---------------------- |
 | bundleInfos    | 数组     | 是   | 应用信息列表           |
 | allToBackup    | 布尔值   | 是   | 是否允许备份恢复       |
 | extensionName  | 字符串   | 是   | 应用的扩展名           |
 | name           | 字符串   | 是   | 应用的包名             |
 | needToInstall  | 布尔值   | 是   | 应用恢复时是否需要安装 |
 | spaceOccupied  | 数值     | 是   | 应用数据占用的空间大小 |
 | versionCode    | 数值     | 是   | 应用的版本号           |
 | versionName    | 字符串   | 是   | 应用的版本名称         |
 | deviceType     | 字符串   | 是   | 设备类型               |
 | systemFullName | 字符串   | 是   | 设备版本               |

 ```json
 {
  "bundleInfos" :[{
    "allToBackup" : true,
    "extensionName" : "BackupExtensionAbility",
    "name" : "com.example.hiworld",
    "needToInstall" : false,
    "spaceOccupied" : 0,
    "versionCode" : 1000000,
    "versionName" : "1.0.0"
    }],
  "deviceType" : "default",
  "systemFullName" : "OpenHarmony-4.0.0.0"
 }
 ```

## 应用备份数据

开发者可以根据能力文件提供的应用信息,选择需要备份的应用数据。

备份过程中,备份恢复服务会将应用的数据打包成文件,打包后的文件会以打开的文件句柄形式,通过创建实例时所注册的回调[onFileReady](../reference/apis/js-apis-file-backup.md#onfileready)接口返回。

开发者可以根据需要将文件内容保存到本地。

**示例**

 ```ts
99
  import backup from '@ohos.file.backup';
100
  import common from '@ohos.app.ability.common';
101
  import fs from '@ohos.file.fs';
102 103
  import { BusinessError } from '@ohos.base';

104
  // 获取沙箱路径
105 106
  let context = getContext(this) as common.UIAbilityContext;
  let filesDir = context.filesDir;
107
  // 创建SessionBackup类的实例用于备份数据
108
  let g_session: backup.SessionBackup;
109
  function createSessionBackup() {
110
    let sessionBackup = new backup.SessionBackup({
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 118 119 120 121 122 123 124 125 126
          if (!fs.accessSync(bundlePath)) {
            fs.mkdirSync(bundlePath);
          }
          fs.copyFileSync(file.fd, bundlePath + `/${file.uri}`);
          fs.closeSync(file.fd);
          console.info('onFileReady success');
        } catch (e) {
          console.error('onFileReady failed with err: ' + e);
        }
      },
127
      onBundleBegin: (err: BusinessError, bundleName: string) => {
128
        if (err) {
129
          console.info('onBundleBegin err: ' + JSON.stringify(err));
130 131 132 133
        } else {
          console.info('onBundleBegin bundleName: ' + bundleName);
        }
      },
134
      onBundleEnd: (err: BusinessError, bundleName: string) => {
135
        if (err) {
136
          console.info('onBundleEnd err: ' + JSON.stringify(err));
137 138 139 140
        } else {
          console.info('onBundleEnd bundleName: ' + bundleName);
        }
      },
141
      onAllBundlesEnd: (err: BusinessError) => {
142
        if (err) {
143
          console.info('onAllBundlesEnd err: ' + JSON.stringify(err));
144 145 146 147 148 149 150 151 152 153
        } else {
          console.info('onAllBundlesEnd');
        }
      },
      onBackupServiceDied: () => {
        console.info('onBackupServiceDied');
      },
    });
    return sessionBackup;
  }
154 155

  async function sessionBackup () {
156 157 158
    g_session = createSessionBackup();
    // 此处可根据backup.getLocalCapabilities()提供的能力文件,选择需要备份的应用
    // 也可直接根据应用包名称进行备份
159
    const backupApps: string[] = [
160 161 162 163 164
      "com.example.hiworld",
    ]
    await g_session.appendBundles(backupApps);
    console.info('appendBundles success');
  }
165 166 167 168 169 170 171 172 173 174 175 176 177
 ```

## 应用恢复数据

开发者可以根据能力文件提供的应用信息,选择需要恢复的应用数据。

恢复过程中,备份恢复服务会根据开发者调用[getFileHandle](../reference/apis/js-apis-file-backup.md#getfilehandle)的请求内容,将应用待恢复数据的文件句柄,通过创建实例时注册的回调[onFileReady](../reference/apis/js-apis-file-backup.md#onfileready)接口返回。可以根据返回的[uri](../reference/apis/js-apis-file-backup.md#filemeta)将应用对应的待恢复数据写入到文件句柄中。写入完成后开发者调用[publishFile](../reference/apis/js-apis-file-backup.md#publishfile)通知服务写入完成。

待应用所有恢复数据准备就绪后,服务开始恢复应用数据。

**示例**

 ```ts
178
  import backup from '@ohos.file.backup';
179
  import fs from '@ohos.file.fs';
180
  import { BusinessError } from '@ohos.base';
181
  // 创建SessionRestore类的实例用于恢复数据
182
  let g_session: backup.SessionRestore;
183
  async function publishFile(file: backup.File) {
184 185 186 187 188
    await g_session.publishFile({
      bundleName: file.bundleName,
      uri: file.uri
    });
  }
189
  function createSessionRestore() {
190
    let sessionRestore = new backup.SessionRestore({
191
      onFileReady: (err: BusinessError, file: backup.File) => {
192
        if (err) {
193
          console.info('onFileReady err: ' + JSON.stringify(err));
194 195
        }
        // 此处开发者请根据实际场景待恢复文件存放位置进行调整 bundlePath
196
        let bundlePath: string;
197 198 199 200 201 202
        if (!fs.accessSync(bundlePath)) {
          console.info('onFileReady bundlePath err : ' + bundlePath);
        }
        fs.copyFileSync(bundlePath, file.fd);
        fs.closeSync(file.fd);
        // 恢复数据传输完成后,会通知服务端文件准备就绪
203
        publishFile(file);
204
        console.info('onFileReady success');
205
      },
206
      onBundleBegin: (err: BusinessError, bundleName: string) => {
207
        if (err) {
208
          console.error('onBundleBegin failed with err: ' + JSON.stringify(err));
209 210 211
        }
        console.info('onBundleBegin success');
      },
212
      onBundleEnd: (err: BusinessError, bundleName: string) => {
213
        if (err) {
214
          console.error('onBundleEnd failed with err: ' + JSON.stringify(err));
215 216 217
        }
        console.info('onBundleEnd success');
      },
218
      onAllBundlesEnd: (err: BusinessError) => {
219
        if (err) {
220
          console.error('onAllBundlesEnd failed with err: ' + JSON.stringify(err));
221 222 223 224 225
        }
        console.info('onAllBundlesEnd success');
      },
      onBackupServiceDied: () => {
        console.info('service died');
226 227
      }
    });
228 229
    return sessionRestore;
  }
230 231

  async function restore01 () {
232
    g_session = createSessionRestore();
233
    const restoreApps: string[] = [
234 235 236 237 238
      "com.example.hiworld",
    ]
    // 能力文件的获取方式可以根据开发者实际场景进行调整。此处仅为请求示例
    // 开发者也可以根据能力文件内容的结构示例,自行构造能力文件内容
    let fileData = await backup.getLocalCapabilities();
239
    await g_session.appendBundles(fileData.fd, restoreApps);
240 241 242 243 244 245 246 247 248 249 250 251 252
    console.info('appendBundles success');
    // 添加需要恢复的应用成功后,请根据需要恢复的应用名称,调用getFileHandle接口获取待恢复应用数文件的文件句柄
    // 应用待恢复数据文件数请依据实际备份文件个数为准,此处仅为请求示例
    await g_session.getFileHandle({
      bundleName: restoreApps[0],
      uri: "manage.json"
    });
    await g_session.getFileHandle({
      bundleName: restoreApps[0],
      uri: "1.tar"
    });
    console.info('getFileHandle success');
  }
253 254 255 256 257 258 259 260 261 262 263 264 265
 ```

## 应用恢复数据时安装应用

开发者在恢复数据时可以选择先安装应用后再进行恢复应用数据。与[应用恢复数据](#应用恢复数据)相比需要修改[能力文件](#获取能力文件)`bundleInfos`数组内的`needToInstall`字段修改为`true`

> **说明:**
> - [应用备份数据](#应用备份数据)不支持备份应用安装包,因此开发者需要自行准备应用安装包。
> - 开发者在调用[getFileHandle](../reference/apis/js-apis-file-backup.md#getfilehandle)时,传入固定的`FileMeta.uri`=`"/data/storage/el2/restore/bundle.hap"`,用于获取应用安装包的文件句柄。与应用恢复数据时一致,应用安装包的文件句柄,通过创建实例时注册的回调onFileReady接口返回给开发者,返回的`File.uri`=`"/data/storage/el2/restore/bundle.hap"`。

**示例**

 ```ts
266 267
  import backup from '@ohos.file.backup';
  import common from '@ohos.app.ability.common';
268
  import fs from '@ohos.file.fs';
269 270 271 272 273
  import { BusinessError } from '@ohos.base';

  // 获取沙箱路径
  let context = getContext(this) as common.UIAbilityContext;
  let filesDir = context.filesDir;
274
  // 创建SessionRestore类的实例用于恢复数据
275
  let g_session: backup.SessionRestore;
276
  async function publishFile(file: backup.File) {
277 278 279 280 281
    await g_session.publishFile({
      bundleName: file.bundleName,
      uri: file.uri
    });
  }
282
  function createSessionRestore() {
283
    let sessionRestore = new backup.SessionRestore({
284
      onFileReady: (err: BusinessError, file: backup.File) => {
285 286 287
        if (err) {
          console.info('onFileReady err: ' + JSON.stringify(err));
        }
288
        let bundlePath: string;
289 290 291 292
        if( file.uri == "/data/storage/el2/restore/bundle.hap" )
        {
          // 此处开发者请根据实际场景安装包的存放位置进行调整
        } else {
293
          // 此处开发者请根据实际场景待恢复文件存放位置进行调整 bundlePath
294 295 296 297 298 299 300
        }
        if (!fs.accessSync(bundlePath)) {
          console.info('onFileReady bundlePath err : ' + bundlePath);
        }
        fs.copyFileSync(bundlePath, file.fd);
        fs.closeSync(file.fd);
        // 恢复数据传输完成后,会通知服务端文件准备就绪
301
        publishFile(file);
302
        console.info('onFileReady success');
303
      },
304
      onBundleBegin: (err: BusinessError, bundleName: string) => {
305
        if (err) {
306
          console.error('onBundleBegin failed with err: ' + JSON.stringify(err));
307 308 309
        }
        console.info('onBundleBegin success');
      },
310
      onBundleEnd: (err: BusinessError, bundleName: string) => {
311
        if (err) {
312
          console.error('onBundleEnd failed with err: ' + JSON.stringify(err));
313 314 315
        }
        console.info('onBundleEnd success');
      },
316
      onAllBundlesEnd: (err: BusinessError) => {
317
        if (err) {
318
          console.error('onAllBundlesEnd failed with err: ' + JSON.stringify(err));
319 320 321 322 323
        }
        console.info('onAllBundlesEnd success');
      },
      onBackupServiceDied: () => {
        console.info('service died');
324 325
      }
    });
326 327
    return sessionRestore;
  }
328 329

  async function restore02 () {
330
    g_session = createSessionRestore();
331
    const restoreApps: string[] = [
332 333
      "com.example.hiworld",
    ]
334 335
    let fpath = filesDir + '/localCapabilities.json';
    let file = fs.openSync(fpath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
336 337 338 339 340
    let content = "{\"bundleInfos\" :[{\"allToBackup\" : false,\"extensionName\" : \"\"," +
    "\"name\" : \"cn.openharmony.inputmethodchoosedialog\",\"needToInstall\" : true,\"spaceOccupied\" : 0," +
    "\"versionCode\" : 1000000,\"versionName\" : \"1.0.0\"}],\"deviceType\" : \"default\",\"systemFullName\"   : \"OpenHarmony-4.0.6.2(Canary1)\"}";
    fs.writeSync(file.fd, content);
    fs.fsyncSync(file.fd);
341
    await g_session.appendBundles(file.fd, restoreApps);
342
    console.info('appendBundles success');
343

344 345 346 347 348
    // 开发者需要请求安装应用的文件句柄
    await g_session.getFileHandle({
      bundleName: restoreApps[0],
      uri: "/data/storage/el2/restore/bundle.hap"
    });
349

350 351 352 353 354 355 356 357 358 359
    await g_session.getFileHandle({
      bundleName: restoreApps[0],
      uri: "manage.json"
    });
    await g_session.getFileHandle({
      bundleName: restoreApps[0],
      uri: "1.tar"
    });
    console.info('getFileHandle success');
  }
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
 ```

  **恢复数据时安装应用所需的能力文件内容示例:**
 ```json
 {
  "bundleInfos" :[{
    "allToBackup" : true,
    "extensionName" : "BackupExtensionAbility",
    "name" : "com.example.hiworld",
    "needToInstall" : true,
    "spaceOccupied" : 0,
    "versionCode" : 1000000,
    "versionName" : "1.0.0"
    }],
  "deviceType" : "default",
  "systemFullName" : "OpenHarmony-4.0.0.0"
 }
 ```