1# 通过数据管理服务实现数据共享静默访问 2 3 4## 场景介绍 5 6典型跨应用访问数据的用户场景下,数据提供方会存在多次被拉起的情况。 7 8为了降低数据提供方拉起次数,提高访问速度,OpenHarmony提供了一种不拉起数据提供方直接访问数据库的方式,即静默数据访问。 9 10静默数据访问通过数据管理服务进行数据的访问和修改,无需拉起数据提供方。 11 12数据管理服务仅支持数据库的基本访问或数据托管,如果有业务处理,需要将业务处理封装成接口,给数据访问方调用。 13 14如果业务过于复杂,无法放到数据访问方,建议通过[DataShareExtensionAbility](../reference/apis/js-apis-application-dataShareExtensionAbility.md)拉起数据提供方实现功能。 15 16 17## 运作机制 18 19可以通过数据管理服务进行代理访问的数据分为以下两种: 20 21- 持久化数据:归属于数据提供方的数据库,这类数据存储于数据提供方的沙箱,可以在数据提供方中通过声明的方式进行共享,按表为粒度配置为可以被其他应用访问的数据表。 22 23 24- 过程数据:托管在数据管理服务上的过程数据,这类数据存储于数据管理服务的沙箱,格式为json或byte数据,无人订阅10天后自动删除。 25 26 27| 数据类型 | 存储位置 | 数据格式 | 有效期 | 适用场景 | 28| ----- | --------- | ----------- | ------------ | --------------------------------- | 29| 持久化数据 | 数据提供方的沙箱 | 数据库中的数据表 | 永久存储 | 适用于数据格式类似关系型数据库的相关场景,如日程,会议等 | 30| 过程数据 | 数据管理服务的沙箱 | json或byte数据 | 无人订阅10天后自动删除 | 适用于数据有时效性且数据格式较简单的相关场景,如步数,天气,心率等 | 31 32 33 34图1 静默数据访问视图 35 36 37 38- 和跨应用数据共享方式不同的是,静默数据访问借助数据管理服务通过目录映射方式直接读取数据提供方的配置,按规则进行预处理后,并访问数据库。 39 40- 数据访问方如果使用静默数据访问方式,URI需严格按照如下格式: 41 datashareproxy://{bundleName}/{dataPath} 42 43 数据管理服务会读取对应bundleName作为数据提供方应用,读取配置,进行权限校验并访问对应数据。 44 45 dataPath为数据标识,可以自行定义,在同一个数据提供方应用中需要保持唯一。 46 47 48## 约束与限制 49 50- 目前持久化数据中仅关系型数据库支持静默数据访问方式。 51- 整个系统最多同时并发16路查询,有多出来的查询请求需要排队处理。 52- 持久化数据不支持代理创建数据库,如果需要创建数据库,需要拉起数据提供方。 53- 数据提供方如果是normal级别签名的应用,配置的数据读写权限必须为system_basic及以上权限。 54 55 56## 接口说明 57 58以下是静默数据访问的相关接口,大部分为异步接口。异步接口均有callback和Promise两种返回形式,下表均以callback形式为例,更多接口及使用方式请见[数据共享](../reference/apis/js-apis-data-dataShare.md)。 59 60### 通用接口 61 62| 接口名称 | 描述 | 63| ---------------------------------------- | -------------------- | 64| createDataShareHelper(context: Context, uri: string, options: DataShareHelperOptions, callback: AsyncCallback<DataShareHelper>): void | 创建DataShareHelper实例。 | 65 66### 持久化数据 67 68| 接口名称 | 描述 | 69| ---------------------------------------- | -------------------- | 70| insert(uri: string, value: ValuesBucket, callback: AsyncCallback<number>): void | 向目标表中插入一行数据。 | 71| delete(uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: AsyncCallback<number>): void | 从数据库中删除一条或多条数据记录。 | 72| query(uri: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>, callback: AsyncCallback<DataShareResultSet>): void | 查询数据库中的数据。 | 73| update(uri: string, predicates: dataSharePredicates.DataSharePredicates, value: ValuesBucket, callback: AsyncCallback<number>): void | 更新数据库中的数据记录。 | 74| addTemplate(uri: string, subscriberId: string, template: Template): void | 添加一个指定订阅者的数据模板。 | 75| on(type: 'rdbDataChange', uris: Array<string>, templateId: TemplateId, callback: AsyncCallback<RdbDataChangeNode>): Array<OperationResult | 订阅指定URI和模板对应的数据变更事件。 | 76 77### 过程数据 78 79| 接口名称 | 描述 | 80| ---------------------------------------- | ------------------ | 81| publish(data: Array<PublishedItem>, bundleName: string, version: number, callback: AsyncCallback<Array<OperationResult>>): void | 发布数据,将数据托管至数据管理服务。 | 82| on(type: 'publishedDataChange', uris: Array<string>, subscriberId: string, callback: AsyncCallback<PublishedDataChangeNode>): Array<OperationResult> | 订阅已发布数据的数据变更通知。 | 83 84 85 86## 持久化数据实现说明 87 88首先,以共享一个关系型数据库为例,说明开发步骤。 89 90### 数据提供方应用的开发 91 921. 数据提供方需要在module.json5中的proxyDatas节点定义要共享的表的标识,读写权限和基本信息。 93 94 **表1** module.json5中proxyDatas节点对应的属性字段 95 96 | 属性名称 | 备注说明 | 必填 | 97 | ----------------------- | ---------------------------------------- | ---- | 98 | uri | 数据使用的URI,是跨应用数据访问的唯一标识。 | 是 | 99 | requiredReadPermission | 标识从该数据代理读取数据时所需要的权限,不配置默认不允许其他APP访问数据。支持权限可参考[权限列表](../security/permission-list.md)。 | 否 | 100 | requiredWritePermission | 标识从该数据代理修改数据时所需要的权限,不配置默认不允许其他APP修改数据。支持权限可参考[权限列表](../security/permission-list.md)。 | 否 | 101 | metadata | 数据源的信息,包含name和resource字段。<br /> name类型固定为"dataProperties",是配置的唯一标识。 <br /> resource类型固定为"$profile:{fileName}",表示配置文件的名称为{fileName}.json。 | 是 | 102 103 **module.json5配置样例:** 104 105 ```json 106 "proxyDatas":[ 107 { 108 "uri": "datashareproxy://com.acts.ohos.data.datasharetest/test", 109 "requiredReadPermission": "ohos.permission.GET_BUNDLE_INFO", 110 "requiredWritePermission": "ohos.permission.KEEP_BACKGROUND_RUNNING", 111 "metadata": { 112 "name": "dataProperties", 113 "resource": "$profile:my_config" 114 } 115 } 116 ] 117 ``` 118 **表2** my_config.json对应属性字段 119 120 | 属性名称 | 备注说明 | 必填 | 121 | ----- | ---------------------------------------- | ---- | 122 | path | 指定数据源路径,目前支持关系型数据库,配置为库名/表名 | 是 | 123 | type | 标识数据库类型,目前支持配置为rdb,表示关系型数据库。 | 是 | 124 | scope | 数据库所在范围。<br>1.module表示数据库位于本模块下;<br>2.application表示数据库位于本应用下。 | 否 | 125 126 **my_config.json配置样例** 127 128 ```json 129 { 130 "path": "DB00/TBL00", 131 "type": "rdb", 132 "scope": "application" 133 } 134 ``` 135 136### 数据访问方应用的开发 137 138 1391. 导入基础依赖包。 140 141 ```ts 142 import dataShare from '@ohos.data.dataShare'; 143 import dataSharePredicates from '@ohos.data.dataSharePredicates'; 144 import UIAbility from '@ohos.app.ability.UIAbility' 145 import { ValuesBucket } from '@ohos.data.ValuesBucket' 146 import window from '@ohos.window' 147 import { BusinessError } from '@ohos.base' 148 ``` 149 1502. 定义与数据提供方通信的URI字符串。 151 152 ```ts 153 let dseUri = ('datashareproxy://com.acts.ohos.data.datasharetest/test'); 154 ``` 155 1563. 创建工具接口类对象。 157 158 ```ts 159 let dsHelper: dataShare.DataShareHelper | undefined = undefined; 160 let abilityContext: Context; 161 162 export default class EntryAbility extends UIAbility { 163 onWindowStageCreate(windowStage: window.WindowStage) { 164 abilityContext = this.context; 165 dataShare.createDataShareHelper(abilityContext, "", { 166 isProxy: true 167 }, (err, data) => { 168 dsHelper = data; 169 }); 170 } 171 } 172 ``` 173 1744. 获取到接口类对象后,便可利用其提供的接口访问提供方提供的服务,如进行数据的增、删、改、查等。 175 176 ```ts 177 // 构建一条数据 178 let key1 = 'name'; 179 let key2 = 'age'; 180 let key3 = 'isStudent'; 181 let key4 = 'Binary'; 182 let valueName1 = 'ZhangSan'; 183 let valueName2 = 'LiSi'; 184 let valueAge1 = 21; 185 let valueAge2 = 18; 186 let valueIsStudent1 = false; 187 let valueIsStudent2 = true; 188 let valueBinary = new Uint8Array([1, 2, 3]); 189 let valuesBucket: ValuesBucket = { key1: valueName1, key2: valueAge1, key3: valueIsStudent1, key4: valueBinary }; 190 let updateBucket: ValuesBucket = { key1: valueName2, key2: valueAge2, key3: valueIsStudent2, key4: valueBinary }; 191 let predicates = new dataSharePredicates.DataSharePredicates(); 192 let valArray = ['*']; 193 if (dsHelper != undefined) { 194 // 插入一条数据 195 (dsHelper as dataShare.DataShareHelper).insert(dseUri, valuesBucket, (err, data) => { 196 console.info(`dsHelper insert result:${data}`); 197 }); 198 // 更新数据 199 (dsHelper as dataShare.DataShareHelper).update(dseUri, predicates, updateBucket, (err, data) => { 200 console.info(`dsHelper update result:${data}`); 201 }); 202 // 查询数据 203 (dsHelper as dataShare.DataShareHelper).query(dseUri, predicates, valArray, (err, data) => { 204 console.info(`dsHelper query result:${data}`); 205 }); 206 // 删除指定的数据 207 (dsHelper as dataShare.DataShareHelper).delete(dseUri, predicates, (err, data) => { 208 console.info(`dsHelper delete result:${data}`); 209 }); 210 } 211 ``` 212 2135. 对指定的数据进行订阅。 214 215 ```ts 216 function onCallback(err: BusinessError, node: dataShare.RdbDataChangeNode) { 217 console.info("uri " + JSON.stringify(node.uri)); 218 console.info("templateId " + JSON.stringify(node.templateId)); 219 console.info("data length " + node.data.length); 220 for (let i = 0; i < node.data.length; i++) { 221 console.info("data " + node.data[i]); 222 } 223 } 224 225 let key21: string = "p1"; 226 let value21: string = "select * from TBL00"; 227 let key22: string = "p2"; 228 let value22: string = "select name from TBL00"; 229 let template: dataShare.Template = { 230 predicates: { 231 key21: value21, 232 key22: value22, 233 }, 234 scheduler: "" 235 } 236 if(dsHelper != undefined) 237 { 238 (dsHelper as dataShare.DataShareHelper).addTemplate(dseUri, "111", template); 239 } 240 let templateId: dataShare.TemplateId = { 241 subscriberId: "111", 242 bundleNameOfOwner: "com.acts.ohos.data.datasharetestclient" 243 } 244 if(dsHelper != undefined) { 245 // 使用数据管理服务修改数据时触发onCallback回调,回调内容是template中的规则查到的数据 246 let result: Array<dataShare.OperationResult> = (dsHelper as dataShare.DataShareHelper).on("rdbDataChange", [dseUri], templateId, onCallback); 247 } 248 ``` 249 250## 过程数据实现说明 251 252以托管一份过程数据为例,说明开发步骤。 253 254### 数据提供方应用的开发(可选) 255 256数据提供方需要在module.json5中的proxyDatas节点定义过程数据的标识,读写权限和基本信息。 257 258> 注意: 259> 260> - 该步骤为可选,可以不对module.json5中的proxyDatas进行配置。 261> - 不配置proxyDatas时,托管数据不允许其他应用访问。 262> - 不配置proxyDatas时,数据标识可以为简写,发布、订阅、查询数据可以使用简写的数据标识,如weather,可以不用全写为datashareproxy://com.acts.ohos.data.datasharetest/weather 263 264**表3** module.json5中proxyDatas节点对应的属性字段 265 266| 属性名称 | 备注说明 | 必填 | 267| ----------------------- | ----------------------------- | ---- | 268| uri | 数据使用的URI,是跨应用数据访问的唯一标识。 | 是 | 269| requiredReadPermission | 标识从该数据代理读取数据时所需要的权限,不配置默认不允许其他APP访问数据。支持权限可参考[权限列表](../security/permission-list.md)。 | 否 | 270| requiredWritePermission | 标识从该数据代理修改数据时所需要的权限,不配置默认不允许其他APP访问数据。支持权限可参考[权限列表](../security/permission-list.md)。 | 否 | 271 272**module.json5配置样例:** 273 274```json 275"proxyDatas": [ 276 { 277 "uri": "datashareproxy://com.acts.ohos.data.datasharetest/weather", 278 "requiredReadPermission": "ohos.permission.GET_BUNDLE_INFO", 279 "requiredWritePermission": "ohos.permission.KEEP_BACKGROUND_RUNNING" 280 } 281] 282``` 283 284### 数据访问方应用的开发 285 2861. 导入基础依赖包。 287 288 ```ts 289 import dataShare from '@ohos.data.dataShare'; 290 import UIAbility from '@ohos.app.ability.UIAbility' 291 import window from '@ohos.window' 292 import { BusinessError } from '@ohos.base' 293 ``` 294 2952. 创建工具接口类对象。 296 297 ```ts 298 let dsHelper: dataShare.DataShareHelper | undefined = undefined; 299 let abilityContext: Context; 300 301 export default class EntryAbility extends UIAbility { 302 onWindowStageCreate(windowStage: window.WindowStage) { 303 abilityContext = this.context; 304 dataShare.createDataShareHelper(abilityContext, "", {isProxy : true}, (err, data) => { 305 dsHelper = data; 306 }); 307 } 308 } 309 ``` 310 3113. 获取到接口类对象后,便可利用其提供的接口访问提供方提供的服务,如进行数据的增、删、改、查等。 312 313 ```ts 314 // 构建两条数据,第一条为免配置的数据,仅自己使用 315 let data : Array<dataShare.PublishedItem> = [ 316 {key:"city", subscriberId:"11", data:"xian"}, 317 {key:"datashareproxy://com.acts.ohos.data.datasharetest/weather", subscriberId:"11", data:JSON.stringify("Qing")}]; 318 // 发布数据 319 if (dsHelper != undefined) { 320 let result: Array<dataShare.OperationResult> = await (dsHelper as dataShare.DataShareHelper).publish(data, "com.acts.ohos.data.datasharetestclient"); 321 } 322 ``` 323 3244. 对指定的数据进行订阅。 325 326 ```ts 327 function onPublishCallback(err: BusinessError, node:dataShare.PublishedDataChangeNode) { 328 console.info("onPublishCallback"); 329 } 330 let uris:Array<string> = ["city", "datashareproxy://com.acts.ohos.data.datasharetest/weather"]; 331 if (dsHelper != undefined) { 332 let result: Array<dataShare.OperationResult> = (dsHelper as dataShare.DataShareHelper).on("publishedDataChange", uris, "11", onPublishCallback); 333 } 334 ``` 335 336 337 338