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