Data Ability Development

When to Use

A Data ability helps applications manage access to data stored by themselves and other applications. It also provides APIs for sharing data with other applications either on the same device or across devices.

Data ability providers can customize data access-related APIs such as data inserting, deleting, updating, and querying, as well as file opening, and share data with other applications through these open APIs.

URI Introduction

A Uniform Resource Identifier (URI) is used to identify a specific data item, such as a table in the database or a file on the disk. URIs used in OpenHarmony comply with the commonly used URI standard. A URI consists of the components:

fa-dataability-uri

  • scheme: name of the scheme used by the Data ability. The value is fixed at dataability.
  • authority: device ID. To access data on a remote device, set this component to the ID of the remote device. To access data on the local device, leave this component empty.
  • path: location of the specific resource to access.
  • query: query parameters.
  • fragment: subordinate resources to access.

Example URIs:

  • Cross-device communication: **dataability://device_id/com.domainname.dataability.persondata/person/**10
  • Local-device communication: **dataability:///com.domainname.dataability.persondata/person/**10

NOTE

In the case of local-device communication, device_id is empty, and therefore, there are three slashes (/) after dataability:.

Available APIs

Table 1 Data ability lifecycle APIs

API Description
onInitialized(info: AbilityInfo): void Called during ability initialization to initialize the relational database (RDB).
update(uri: string, valueBucket: rdb.ValuesBucket, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void Updates data in the database.
query(uri: string, columns: Array<string>, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<ResultSet>): void Queries data in the database.
delete(uri: string, predicates: dataAbility.DataAbilityPredicates, callback: AsyncCallback<number>): void Deletes one or more data records from the database.
normalizeUri(uri: string, callback: AsyncCallback<string>): void Normalizes the URI. A normalized URI applies to cross-device use, persistence, backup, and restore. When the context changes, it ensures that the same data item can be referenced.
batchInsert(uri: string, valueBuckets: Array<rdb.ValuesBucket>, callback: AsyncCallback<number>): void Inserts multiple data records into the database.
denormalizeUri(uri: string, callback: AsyncCallback<string>): void Converts a normalized URI generated by normalizeUri into a denormalized URI.
insert(uri: string, valueBucket: rdb.ValuesBucket, callback: AsyncCallback<number>): void Inserts a data record into the database.
openFile(uri: string, mode: string, callback: AsyncCallback<number>): void Opens a file.
getFileTypes(uri: string, mimeTypeFilter: string, callback: AsyncCallback<Array<string>>): void Obtains the MIME type of a file.
getType(uri: string, callback: AsyncCallback<string>): void Obtains the MIME type matching the data specified by the URI.
executeBatch(ops: Array<DataAbilityOperation>, callback: AsyncCallback<Array<DataAbilityResult>>): void Operates data in the database in batches.
call(method: string, arg: string, extras: PacMap, callback: AsyncCallback<PacMap>): void Calls a custom API.

How to Develop

Creating a Data Ability

  1. To meet the basic requirements of the database storage service, implement the Insert, Query, Update, and Delete APIs in the Data class. The BatchInsert and ExecuteBatch APIs have already implemented the traversal logic, but not batch data processing.

    The following code snippet shows how to create a Data ability:

     import featureAbility from '@ohos.ability.featureAbility'
     import dataAbility from '@ohos.data.dataAbility'
     import dataRdb from '@ohos.data.rdb'
    
     const TABLE_NAME = 'book'
     const STORE_CONFIG = { name: 'book.db' }
     const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS book(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, introduction TEXT NOT NULL)'
     let rdbStore: dataRdb.RdbStore = undefined
    
     export default {
     onInitialized(abilityInfo) {
         console.info('DataAbility onInitialized, abilityInfo:' + abilityInfo.bundleName)
         let context = featureAbility.getContext()
         dataRdb.getRdbStore(context, STORE_CONFIG, 1, (err, store) => {
             console.info('DataAbility getRdbStore callback')
             store.executeSql(SQL_CREATE_TABLE, [])
             rdbStore = store
         });
     },
     insert(uri, valueBucket, callback) {
         console.info('DataAbility insert start')
         rdbStore.insert(TABLE_NAME, valueBucket, callback)
     },
     batchInsert(uri, valueBuckets, callback) {
         console.info('DataAbility batch insert start')
         for (let i = 0;i < valueBuckets.length; i++) {
             console.info('DataAbility batch insert i=' + i)
             if (i < valueBuckets.length - 1) {
                 rdbStore.insert(TABLE_NAME, valueBuckets[i], (err: any, num: number) => {
                     console.info('DataAbility batch insert ret=' + num)
                 })
             } else {
                 rdbStore.insert(TABLE_NAME, valueBuckets[i], callback)
             }
         }
     },
     query(uri, columns, predicates, callback) {
         console.info('DataAbility query start')
         let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates)
         rdbStore.query(rdbPredicates, columns, callback)
     },
     update(uri, valueBucket, predicates, callback) {
         console.info('DataAbilityupdate start')
         let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates)
         rdbStore.update(valueBucket, rdbPredicates, callback)
     },
     delete(uri, predicates, callback) {
         console.info('DataAbilitydelete start')
         let rdbPredicates = dataAbility.createRdbPredicates(TABLE_NAME, predicates)
         rdbStore.delete(rdbPredicates, callback)
     }
     };
    
  2. Configure the submodule.

JSON Field Description
"name" Ability name, corresponding to the Data class name derived from Ability.
"type" Ability type, which is Data for a Data ability.
"uri" URI used for communication.
"exported" Whether the Data ability is visible to other applications. When this parameter is set to true, the Data ability can communicate with other applications.

config.json configuration example

"abilities":[{
    "srcPath": "DataAbility",
    "name": ".DataAbility",
    "icon": "$media:icon",
    "srcLanguage": "ets",
    "description": "$string:description_dataability",
    "type": "data",
    "exported": true,
    "uri": "dataability://ohos.samples.etsdataability.DataAbility"
 }]

Accessing a Data ability

Development Preparations

Import the basic dependency packages and obtain the URI string for communicating with the Data submodule.

The basic dependency packages include:

  • @ohos.ability.featureAbility
  • @ohos.data.dataAbility
  • @ohos.data.rdb

Data Ability API Development

  1. Create a Data ability helper.

    For details about the APIs provided by DataAbilityHelper, see DataAbilityHelper Module.

    // Different from the URI defined in the config.json file, the URI passed in the parameter has an extra slash (/), because there is a DeviceID parameter between the second and the third slash (/).
    import featureAbility from '@ohos.ability.featureAbility'
    import ohos_data_ability from '@ohos.data.dataAbility'
    import ohos_data_rdb from '@ohos.data.rdb'
    
    var urivar = "dataability:///com.ix.DataAbility"
    var DAHelper = featureAbility.acquireDataAbilityHelper(
     urivar
    );
    
  2. Construct RDB data.

    var valuesBucket = {"name": "gaolu"}
    var da = new ohos_data_ability.DataAbilityPredicates()
    var valArray =new Array("value1");
    var cars = new Array({"batchInsert1" : "value1",});
    
  3. Use insert to insert data to the Data submodule.

    // Callback mode:
    DAHelper.insert(
     urivar,
     valuesBucket,
     (error, data) => {
         console.log("DAHelper insert result: " + data)
     }
    );
    
    // Promise mode:
    var datainsert = await DAHelper.insert(
     urivar,
     valuesBucket
    );
    
  4. Use delete to delete data from the Data submodule.

    // Callback mode:
    DAHelper.delete(
     urivar,
     da,
     (error, data) => {
         console.log("DAHelper delete result: " + data)
     }
    );
    
    // Promise mode:
    var datadelete = await DAHelper.delete(
     urivar,
     da,
    );
    
  5. Use update to update data in the Data submodule.

    // Callback mode:
    DAHelper.update(
     urivar
     valuesBucket,
     da,
     (error, data) => {
         console.log("DAHelper update result: " + data)
     }
    );
    
    // Promise mode:
    var dataupdate = await DAHelper.update(
     urivar,
     valuesBucket,
     da,
    );
    
  6. Use query to query data in the Data submodule.

    // Callback mode:
    DAHelper.query(
     urivar,
     valArray,
     da,
     (error, data) => {
         console.log("DAHelper query result: " + data)
     }
    );
    
    // Promise mode:
    var dataquery = await DAHelper.query(
     urivar,
     valArray,
     da
    );
    
  7. Use batchInsert to insert data in batches to the Data submodule.

    // Callback mode:
    DAHelper.batchInsert(
     urivar,
     cars,
     (error, data) => {
         console.log("DAHelper batchInsert result: " + data)
     }
    );
    
    // Promise mode:
    var databatchInsert = await DAHelper.batchInsert(
     urivar,
     cars
    );
    
  8. Use executeBatch to process data in batches in the Data submodule.

    // Callback mode:
    DAHelper.executeBatch(
     urivar,
     [
         {
             uri: urivar,
             type: featureAbility.DataAbilityOperationType.TYPE_INSERT,
             valuesBucket: {"executeBatch" : "value1",},
             predicates: da,
             expectedCount:0,
             predicatesBackReferences: null,
             interrupted:true,
         }
     ],
     (error, data) => {
         console.log("DAHelper executeBatch result: " + data)
     }
    );
    
    // Promise mode:
    var dataexecuteBatch = await DAHelper.executeBatch(
     urivar,
     [
         {
             uri: urivar,
             type: featureAbility.DataAbilityOperationType.TYPE_INSERT,
             valuesBucket:
             {
                 "executeBatch" : "value1",
             },
             predicates: da,
             expectedCount:0,
             predicatesBackReferences: null,
             interrupted:true,
         }
     ]
    );