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