提交 4c36c690 编写于 作者: S swx1239486

Merge branch 'monthly_20230815' of https://gitee.com/playing-song/docs into monthly_20230815

......@@ -200,9 +200,9 @@ zh-cn/application-dev/reference/apis/js-apis-appmanager.md @littlejerry1 @RayShi
zh-cn/application-dev/reference/apis/js-apis-arraylist.md @gongjunsong @ge-yafang @flyingwolf @blackstone-oh
zh-cn/application-dev/reference/apis/js-apis-audio.md @liuyuehua1 @zengyawen @magekkkk @currydavids
zh-cn/application-dev/reference/apis/js-apis-backgroundTaskManager.md @chenmingJay @ningningW @nan-xiansen @iceice1001
zh-cn/application-dev/reference/apis/js-apis-battery-info.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-battery-info.md @zengyawen @alien0208
zh-cn/application-dev/reference/apis/js-apis-bluetooth.md @cheng_guohong @RayShih @cheng_guohong @quanli125
zh-cn/application-dev/reference/apis/js-apis-brightness.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-brightness.md @zengyawen @alien0208
zh-cn/application-dev/reference/apis/js-apis-buffer.md @gongjunsong @ge-yafang @flyingwolf @blackstone-oh
zh-cn/application-dev/reference/apis/js-apis-bundle-AbilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515
zh-cn/application-dev/reference/apis/js-apis-bundle-ApplicationInfo.md @shuaytao @RayShih @wangzhen107 @inter515
......@@ -322,7 +322,7 @@ zh-cn/application-dev/reference/apis/js-apis-pasteboard.md @han-zhengshi @ge-yaf
zh-cn/application-dev/reference/apis/js-apis-permissionrequestresult.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen
zh-cn/application-dev/reference/apis/js-apis-plainarray.md @gongjunsong @ge-yafang @flyingwolf @blackstone-oh
zh-cn/application-dev/reference/apis/js-apis-pointer.md @yuanxinying @ningningW @cococoler @alien0208
zh-cn/application-dev/reference/apis/js-apis-power.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-power.md @zengyawen @alien0208
zh-cn/application-dev/reference/apis/js-apis-privacyManager.md @nianCode @zengyawen @shuqinglin2 @jinhaihw
zh-cn/application-dev/reference/apis/js-apis-process.md @gongjunsong @ge-yafang @flyingwolf @blackstone-oh
zh-cn/application-dev/reference/apis/js-apis-processrunninginfo.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen
......@@ -335,7 +335,7 @@ zh-cn/application-dev/reference/apis/js-apis-request.md @feng-aiwen @ningningW @
zh-cn/application-dev/reference/apis/js-apis-resource-manager.md @Buda-Liu @ningningW @mengjingzhimo @yangqing3
zh-cn/application-dev/reference/apis/js-apis-router.md @HelloCrease @niulihua @tomatodevboy
zh-cn/application-dev/reference/apis/js-apis-rpc.md @xuepianpian @RayShih @zhaopeng_gitee @vagrant_world
zh-cn/application-dev/reference/apis/js-apis-runninglock.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-runninglock.md @zengyawen @alien0208
zh-cn/application-dev/reference/apis/js-apis-screen.md @zhangqiang183 @ge-yafang @zhouyaoying @zxg-gitee @nobuggers
zh-cn/application-dev/reference/apis/js-apis-screenshot.md @zhangqiang183 @ge-yafang @zhouyaoying @zxg-gitee @nobuggers
zh-cn/application-dev/reference/apis/js-apis-securityLabel.md @panqinxu @zengyawen @bubble_mao @jinhaihw
......@@ -350,9 +350,9 @@ zh-cn/application-dev/reference/apis/js-apis-stack.md @gongjunsong @ge-yafang @f
zh-cn/application-dev/reference/apis/js-apis-statfs.md @panqinxu @zengyawen @bubble_mao @jinhaihw
zh-cn/application-dev/reference/apis/js-apis-storage-statistics.md @panqinxu @zengyawen @bubble_mao @jinhaihw
zh-cn/application-dev/reference/apis/js-apis-system-app.md @HelloCrease @niulihua @tomatodevboy
zh-cn/application-dev/reference/apis/js-apis-system-battery.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-system-battery.md @zengyawen @alien0208
zh-cn/application-dev/reference/apis/js-apis-system-bluetooth.md @cheng_guohong @RayShih @cheng_guohong @quanli125
zh-cn/application-dev/reference/apis/js-apis-system-brightness.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-system-brightness.md @zengyawen @alien0208
zh-cn/application-dev/reference/apis/js-apis-system-cipher.md @gaoyong @zengyawen @niejiteng @jumozhanjiang
zh-cn/application-dev/reference/apis/js-apis-system-configuration.md @Buda-Liu @ningningW @budda-wang @tomatodevboy
zh-cn/application-dev/reference/apis/js-apis-system-date-time.md @feng-aiwen @ningningW @illybyy @murphy1984
......@@ -375,7 +375,7 @@ zh-cn/application-dev/reference/apis/js-apis-system-timer.md @feng-aiwen @ningni
zh-cn/application-dev/reference/apis/js-apis-system-vibrate.md @hellohyh001 @ningningW @butterls @star-wind-snow-and-rain
zh-cn/application-dev/reference/apis/js-apis-telephony-data.md @zhang-hai-feng @zengyawen @jyh926 @gaoxi785
zh-cn/application-dev/reference/apis/js-apis-testRunner.md @inter515 @littlejerry1 @RayShih @inter515 @jiyong
zh-cn/application-dev/reference/apis/js-apis-thermal.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-thermal.md @zengyawen @alien0208
zh-cn/application-dev/reference/apis/js-apis-timer.md @gongjunsong @ge-yafang @flyingwolf @blackstone-oh
zh-cn/application-dev/reference/apis/js-apis-touchevent.md @mayunteng_1 @ningningW @cococoler @alien0208
zh-cn/application-dev/reference/apis/js-apis-shortKey.md @mayunteng_1 @ningningW @cococoler @alien0208
......@@ -426,7 +426,7 @@ zh-cn/application-dev/reference/apis/js-apis-application-configuration.md @littl
zh-cn/application-dev/reference/apis/js-apis-application-configurationConstant.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen
zh-cn/application-dev/reference/apis/js-apis-application-quickFixManager.md @littlejerry1 @RayShih @gwang2008 @chengxingzhen
zh-cn/application-dev/reference/apis/js-apis-avsession.md @liuyuehua1 @zengyawen @saga2020 @currydavids
zh-cn/application-dev/reference/apis/js-apis-batteryStatistics.md @aqxyjay @zengyawen @aqxyjay @alien0208
zh-cn/application-dev/reference/apis/js-apis-batteryStatistics.md @zengyawen @alien0208
zh-cn/application-dev/reference/apis/js-apis-Bundle-BundleStatusCallback.md @shuaytao @RayShih @wangzhen107 @inter515
zh-cn/application-dev/reference/apis/js-apis-bundleManager-abilityInfo.md @shuaytao @RayShih @wangzhen107 @inter515
zh-cn/application-dev/reference/apis/js-apis-bundleManager-applicationInfo.md @shuaytao @RayShih @wangzhen107 @inter515
......
......@@ -30,23 +30,23 @@ The preference persistent file of an application is stored in the application sa
The following table lists the APIs used for persisting user preference data. For more information about the APIs, see [User Preferences](../reference/apis/js-apis-data-preferences.md).
| API | Description |
|--------------------------------------------------------------------------------------------------|------------------------------------------------------------|
| getPreferences(context: Context, name: string, callback: AsyncCallback<Preferences>): void | Obtain a **Preferences** instance. |
| putSync(key: string, value: ValueType): void | Writes data to the Preferences instance. You can use **flush()** to persist the **Preferences** instance data. An asynchronous API is also provided. |
| hasSync(key: string): void | Checks whether the **Preferences** instance contains a KV pair with the given key. The key cannot be empty. An asynchronous API is also provided. |
| getSync(key: string, defValue: ValueType): void | Obtains the value of the specified key. If the value is null or not of the default value type, **defValue** is returned. An asynchronous API is also provided. |
| deleteSync(key: string): void | Deletes the KV pair with the given key from the **Preferences** instance. An asynchronous API is also provided. |
| flush(callback: AsyncCallback<void>): void | Flushes the data of this **Preferences** instance to a file for data persistence. |
| on(type: 'change', callback: Callback<{ key : string }>): void | Subscribes to data changes of the specified key. When the value of the specified key is changed and saved by **flush()**, a callback will be invoked to return the new data. |
| off(type: 'change', callback?: Callback<{ key : string }>): void | Unsubscribes from data changes. |
| deletePreferences(context: Context, name: string, callback: AsyncCallback<void>): void | Deletes a **Preferences** instance from memory. If the **Preferences** instance has a persistent file, this API also deletes the persistent file.|
| API | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| getPreferences(context: Context, name: string, callback: AsyncCallback<Preferences>): void | Obtains a **Preferences** instance. |
| putSync(key: string, value: ValueType): void | Writes data to the Preferences instance. You can use **flush()** to persist the **Preferences** instance data. An asynchronous API is also provided. |
| hasSync(key: string): void | Checks whether the **Preferences** instance contains a KV pair with the given key. The key cannot be empty. An asynchronous API is also provided. |
| getSync(key: string, defValue: ValueType): void | Obtains the value of the specified key. If the value is null or not of the default value type, **defValue** is returned. An asynchronous API is also provided. |
| deleteSync(key: string): void | Deletes the KV pair with the given key from the **Preferences** instance. An asynchronous API is also provided. |
| flush(callback: AsyncCallback<void>): void | Flushes the data of this **Preferences** instance to a file for data persistence. |
| on(type: 'change', callback: Callback<{ key : string }>): void | Subscribes to data changes of the specified key. When the value of the specified key is changed and saved by **flush()**, a callback will be invoked to return the new data. |
| off(type: 'change', callback?: Callback<{ key : string }>): void | Unsubscribes from data changes. |
| deletePreferences(context: Context, name: string, callback: AsyncCallback<void>): void | Deletes a **Preferences** instance from memory. If the **Preferences** instance has a persistent file, this API also deletes the persistent file. |
## How to Develop
1. Import the **@ohos.data.preferences** module.
```js
import dataPreferences from '@ohos.data.preferences';
```
......@@ -55,14 +55,16 @@ The following table lists the APIs used for persisting user preference data. For
Stage model:
```js
import UIAbility from '@ohos.app.ability.UIAbility';
import { BusinessError } from '@ohos.base';
import window from '@ohos.window';
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage) {
onWindowStageCreate(windowStage: window.WindowStage) {
try {
dataPreferences.getPreferences(this.context, 'mystore', (err, preferences) => {
dataPreferences.getPreferences(this.context, 'myStore', (err: BusinessError, preferences: dataPreferences.Preferences) => {
if (err) {
console.error(`Failed to get preferences. Code:${err.code},message:${err.message}`);
return;
......@@ -79,15 +81,16 @@ The following table lists the APIs used for persisting user preference data. For
FA model:
```js
import featureAbility from '@ohos.ability.featureAbility';
import { BusinessError } from '@ohos.base';
// Obtain the context.
let context = featureAbility.getContext();
try {
dataPreferences.getPreferences(context, 'mystore', (err, preferences) => {
dataPreferences.getPreferences(this.context, 'myStore', (err: BusinessError, preferences: dataPreferences.Preferences) => {
if (err) {
console.error(`Failed to get preferences. Code:${err.code},message:${err.message}`);
return;
......@@ -102,7 +105,7 @@ The following table lists the APIs used for persisting user preference data. For
3. Write data.
Use **putSync()** to write data to the cached **Preferences** instance. After data is written, you can use **flush()** to persist the **Preferences** instance data to a file if necessary.
Use **putSync()** to save data to the cached **Preferences** instance. After data is written, you can use **flush()** to persist the **Preferences** instance data to a file if necessary.
> **NOTE**
>
......@@ -110,7 +113,7 @@ The following table lists the APIs used for persisting user preference data. For
Example:
```js
try {
if (preferences.hasSync('startup')) {
......@@ -142,7 +145,7 @@ The following table lists the APIs used for persisting user preference data. For
Use **deleteSync()** to delete a KV pair.<br>Example:
```js
try {
preferences.deleteSync('startup');
......@@ -157,7 +160,7 @@ The following table lists the APIs used for persisting user preference data. For
```js
try {
preferences.flush((err) => {
preferences.flush((err: BusinessError) => {
if (err) {
console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
return;
......@@ -174,18 +177,20 @@ The following table lists the APIs used for persisting user preference data. For
Specify an observer as the callback to return the data changes for an application. When the value of the subscribed key is changed and saved by **flush()**, the observer callback will be invoked to return the new data. Example:
```js
let observer = function (key) {
console.info('The key' + key + 'changed.');
interface observer {
key: string
}
preferences.on('change', observer);
preferences.on('change', (key: observer) => {
console.info('The key' + key + 'changed.');
});
// The data is changed from 'auto' to 'manual'.
preferences.put('startup', 'manual', (err) => {
preferences.put('startup', 'manual', (err: BusinessError) => {
if (err) {
console.error(`Failed to put the value of 'startup'. Code:${err.code},message:${err.message}`);
return;
}
console.info("Succeeded in putting the value of 'startup'.");
preferences.flush((err) => {
preferences.flush((err: BusinessError) => {
if (err) {
console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
return;
......@@ -207,10 +212,10 @@ The following table lists the APIs used for persisting user preference data. For
Example:
```js
try {
dataPreferences.deletePreferences(this.context, 'mystore', (err, val) => {
dataPreferences.deletePreferences(this.context, 'myStore', (err: BusinessError) => {
if (err) {
console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);
return;
......
......@@ -32,7 +32,7 @@ The underlying devices manage the data by device. The device KV stores support d
The **DatamgrService** provides the following synchronization types:
- Manual synchronization: The application calls **sync()** to trigger a synchronization. The list of devices to be synchronized and the synchronization mode must be specified. The synchronization mode can be **PULL_ONLY** (pulling remote data to the local end), **PUSH_ONLY** (pushing local data to the remote end), or **PUSH_PULL** (pushing local data to the remote end and pulling remote data to the local end). You can use the [**sync()** with the **query** parameter](../reference/apis/js-apis-distributedKVStore.md#sync-1) to synchronize the data that meets the specified conditions. The manual synchronization is available only for system applications.
- Manual synchronization: The application calls **sync()** to trigger a synchronization. The list of devices to be synchronized and the synchronization mode must be specified. The synchronization mode can be **PULL_ONLY** (pulling remote data to the local end), **PUSH_ONLY** (pushing local data to the remote end), or **PUSH_PULL** (pushing local data to the remote end and pulling remote data to the local end). You can use the [**sync()** with the **query** parameter](../reference/apis/js-apis-distributedKVStore.md#sync-1) to synchronize the data that meets the specified conditions.
- Automatic synchronization: The distributed database automatically pushes local data to the remote end and pulls remote data to the local end. An automatic synchronization is triggered when a device goes online or an application updates data.
......@@ -72,8 +72,6 @@ When data is added, deleted, or modified, a notification is sent to the subscrib
- Each KV store supports a maximum of eight callbacks for subscription of data change notifications.
- The manual synchronization is available only for system applications.
## Available APIs
......@@ -247,32 +245,31 @@ The following uses a single KV store as an example to describe how to implement
> **NOTE**
>
> If manual synchronization is used, **deviceIds** is obtained by using [devManager.getTrustedDeviceListSync](../reference/apis/js-apis-device-manager.md#gettrusteddevicelistsync). The APIs of the **deviceManager** module are all system interfaces and available only to system applications.
> If manual synchronization is used, **deviceIds** can be obtained by [devManager.getAvailableDeviceListSync](../reference/apis/js-apis-distributedDeviceManager.md#getavailabledevicelistsync).
```js
import deviceManager from '@ohos.distributedHardware.deviceManager';
import deviceManager from '@ohos.distributedDeviceManager';
let devManager;
// create deviceManager
deviceManager.createDeviceManager('bundleName', (err, value) => {
if (!err) {
devManager = value;
// deviceIds is obtained by devManager.getTrustedDeviceListSync.
let deviceIds = [];
if (devManager !== null) {
// The ohos.permission.ACCESS_SERVICE_DM permission is required. This permission is available only for system applications.
let devices = devManager.getTrustedDeviceListSync();
for (let i = 0; i < devices.length; i++) {
deviceIds[i] = devices[i].deviceId;
}
}
try {
// 1000 indicates the maximum delay, in ms.
kvStore.sync(deviceIds, distributedKVStore.SyncMode.PUSH_ONLY, 1000);
} catch (e) {
console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`);
try {
// create deviceManager
devManager = deviceManager.createDeviceManager(context.applicationInfo.name);
// deviceIds is obtained by devManager.getAvailableDeviceListSync.
let deviceIds = [];
if (devManager != null) {
let devices = devManager.getAvailableDeviceListSync();
for (let i = 0; i < devices.length; i++) {
deviceIds[i] = devices[i].networkId;
}
}
});
try {
// 1000 indicates the maximum delay, in ms.
kvStore.sync(deviceIds, distributedKVStore.SyncMode.PUSH_ONLY, 1000);
} catch (e) {
console.error(`An unexpected error occurred. Code:${e.code},message:${e.message}`);
}
} catch (err) {
console.error("createDeviceManager errCode:" + err.code + ",errMessage:" + err.message);
}
```
\ No newline at end of file
......@@ -10,9 +10,16 @@ You can synchronize the application data in a local RDB store on a device to oth
OpenHamony supports synchronization of the relational data of an application across multiple devices.
- Distributed table list<br>After a table is created for an application in an RDB store, you can set it as a distributed table. When querying the RDB store of a remote device, you can obtain the distributed table name of the remote device based on the local table name.
- Distributed table list
- Synchronization mode<br>Data can be synchronized between devices in either of the following ways: <br>- Pushing data from a local device to a remote device. <br>- Pulling data from a remote device to a local device.
After a table is created for an application in an RDB store, you can set it as a distributed table. When querying the RDB store of a remote device, you can obtain the distributed table name of the remote device based on the local table name.
- Synchronization mode
Data can be synchronized between devices in either of the following ways:
- Pushing data from a local device to a remote device.
- Pulling data from a remote device to a local device.
## Working Principles
......@@ -44,12 +51,10 @@ When data is added, deleted, or modified, a notification is sent to the subscrib
- Each RDB store supports a maximum of eight callbacks for subscription of data change notifications.
- Third-party applications cannot call the distributed APIs that must be specified with the device.
## Available APIs
The following table lists the APIs for cross-device data synchronization of RDB stores. Most of the APIs are executed asynchronously, using a callback or promise to return the result. The following table uses the callback-based APIs as an example. For more information about the APIs, see [RDB Store](../reference/apis/js-apis-data-relationalStore.md).
Most of the APIs for cross-device data synchronization of RDB stores are executed asynchronously in callback or promise mode. The following table uses the callback-based APIs as an example. For more information about the APIs, see [RDB Store](../reference/apis/js-apis-data-relationalStore.md).
| API| Description|
| -------- | -------- |
......@@ -73,7 +78,7 @@ The following table lists the APIs for cross-device data synchronization of RDB
import relationalStore from '@ohos.data.relationalStore';
```
2. Request permissions.
2. Apply for the required permission.
1. Request the **ohos.permission.DISTRIBUTED_DATASYNC** permission. For details, see [Declaring Permissions in the Configuration File](../security/accesstoken-guidelines.md#declaring-permissions-in-the-configuration-file).
2. Display a dialog box to ask authorization from the user when the application is started for the first time. For details, see [Requesting User Authorization](../security/accesstoken-guidelines.md#requesting-user-authorization).
......@@ -142,32 +147,33 @@ The following table lists the APIs for cross-device data synchronization of RDB
> **NOTE**
>
> **deviceIds** is obtained by using [devManager.getTrustedDeviceListSync](../reference/apis/js-apis-device-manager.md#gettrusteddevicelistsync). The APIs of the **deviceManager** module are all system interfaces and available only to system applications.
> The value of **deviceIds** can be obtained by [deviceManager.getAvailableDeviceListSync](../reference/apis/js-apis-distributedDeviceManager.md#getavailabledevicelistsync).
```js
// Obtain device IDs.
import deviceManager from '@ohos.distributedHardware.deviceManager';
deviceManager.createDeviceManager("com.example.appdatamgrverify", (err, manager) => {
if (err) {
console.info(`Failed to create device manager. Code:${err.code},message:${err.message}`);
return;
}
let devices = manager.getTrustedDeviceListSync();
let deviceId = devices[0].deviceId;
// Construct a predicate object for querying the distributed table.
let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
// Query data from the specified remote device and return the query result.
store.remoteQuery(deviceId, 'EMPLOYEE', predicates, ['ID', 'NAME', 'AGE', 'SALARY', 'CODES'],
function (err, resultSet) {
if (err) {
console.error(`Failed to remoteQuery data. Code:${err.code},message:${err.message}`);
return;
}
console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`);
import deviceManager from '@ohos.distributedDeviceManager';
let dmInstance = null;
let deviceId = null;
try {
dmInstance = deviceManager.createDeviceManager("com.example.appdatamgrverify");
let devices = dmInstance.getAvailableDeviceListSync();
deviceId = devices[0].networkId;
// Construct a predicate object for querying the distributed table.
let predicates = new relationalStore.RdbPredicates('EMPLOYEE');
// Query data from the specified remote device and return the query result.
store.remoteQuery(deviceId, 'EMPLOYEE', predicates, ['ID', 'NAME', 'AGE', 'SALARY', 'CODES'],
function (err, resultSet) {
if (err) {
console.error(`Failed to remoteQuery data. Code:${err.code},message:${err.message}`);
return;
}
)
})
```
console.info(`ResultSet column names: ${resultSet.columnNames}, column count: ${resultSet.columnCount}`);
}
)
} catch (err) {
console.error("createDeviceManager errCode:" + err.code + ",errMessage:" + err.message);
}
```
\ No newline at end of file
......@@ -57,15 +57,16 @@ Before implementing a **DataShare** service, you need to create a **DataShareExt
2. Right-click the **DataShareAbility** directory, and choose **New > TypeScript File** to create a file named **DataShareExtAbility.ts**.
3. Import **@ohos.application.DataShareExtensionAbility** and other dependencies to the **DataShareExtAbility.ts** file, and
override the service implementation as required. For example, if the data provider provides only the data insertion, deletion, and query services, you can override only these APIs.
3. Import **@ohos.application.DataShareExtensionAbility** and other dependencies to the **DataShareExtAbility.ts** file, and override the service implementation as required. For example, if the data provider provides only the data insertion, deletion, and query services, you can override only these APIs.
```js
import Extension from '@ohos.application.DataShareExtensionAbility';
import rdb from '@ohos.data.relationalStore';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
import relationalStore from '@ohos.data.relationalStore';
import Want from '@ohos.app.ability.Want';
```
4. Implement the data provider services. For example, implement data storage of the data provider by using a database, reading and writing files, or accessing the network.
```js
......@@ -75,20 +76,20 @@ override the service implementation as required. For example, if the data provid
+ TBL_NAME
+ ' (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, isStudent BOOLEAN, Binary BINARY)';
let rdbStore;
let result;
let rdbStore: relationalStore.RdbStore;
let result: string;
export default class DataShareExtAbility extends Extension {
private rdbStore_;
private rdbStore_: relationalStore.RdbStore;
// Override onCreate().
onCreate(want, callback) {
onCreate(want: Want, callback: Function) {
result = this.context.cacheDir + '/datashare.txt';
// Create an RDB store.
rdb.getRdbStore(this.context, {
name: DB_NAME,
securityLevel: rdb.SecurityLevel.S1
}, function (err, data) {
}, (err, data) => {
rdbStore = data;
rdbStore.executeSql(DDL_TBL_CREATE, [], (err) => {
console.info(`DataShareExtAbility onCreate, executeSql done err:${err}`);
......@@ -100,7 +101,7 @@ override the service implementation as required. For example, if the data provid
}
// Override query().
query(uri, predicates, columns, callback) {
query(uri: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>, callback: Function) {
if (predicates === null || predicates === undefined) {
console.info('invalid predicates');
}
......@@ -188,6 +189,8 @@ override the service implementation as required. For example, if the data provid
import UIAbility from '@ohos.app.ability.UIAbility';
import dataShare from '@ohos.data.dataShare';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
import { ValuesBucket } from '@ohos.data.ValuesBucket'
import window from '@ohos.window';
```
2. Define the URI string for communicating with the data provider.
......@@ -200,11 +203,11 @@ override the service implementation as required. For example, if the data provid
3. Create a **DataShareHelper** instance.
```js
let dsHelper;
let abilityContext;
let dsHelper: dataShare.DataShareHelper;
let abilityContext: Context;
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage) {
onWindowStageCreate(windowStage: window.WindowStage) {
abilityContext = this.context;
dataShare.createDataShareHelper(abilityContext, dseUri, (err, data) => {
dsHelper = data;
......@@ -217,8 +220,19 @@ override the service implementation as required. For example, if the data provid
```js
// Construct a piece of data.
let valuesBucket = { 'name': 'ZhangSan', 'age': 21, 'isStudent': false, 'Binary': new Uint8Array([1, 2, 3]) };
let updateBucket = { 'name': 'LiSi', 'age': 18, 'isStudent': true, 'Binary': new Uint8Array([1, 2, 3]) };
let key1 = 'name';
let key2 = 'age';
let key3 = 'isStudent';
let key4 = 'Binary';
let valueName1 = 'ZhangSan';
let valueName2 = 'LiSi';
let valueAge1 = 21;
let valueAge2 = 18;
let valueIsStudent1 = false;
let valueIsStudent2 = true;
let valueBinary = new Uint8Array([1, 2, 3]);
let valuesBucket: ValuesBucket = { key1: valueName1, key2: valueAge1, key3: valueIsStudent1, key4: valueBinary };
let updateBucket: ValuesBucket = { key1: valueName2, key2: valueAge2, key3: valueIsStudent2, key4: valueBinary };
let predicates = new dataSharePredicates.DataSharePredicates();
let valArray = ['*'];
// Insert a piece of data.
......@@ -237,5 +251,4 @@ override the service implementation as required. For example, if the data provid
dsHelper.delete(dseUri, predicates, (err, data) => {
console.info(`dsHelper delete result:${data}`);
});
```
```
\ No newline at end of file
......@@ -29,7 +29,7 @@ Currently, the UDMF provides the public data channel for cross-application data
## Available APIs
The following table lists the UDMF APIs. All of them are executed asynchronously in callback or promise mode. In the following table, callback-based APIs are used as an example. For more information about the APIs, see [UDMF](../reference/apis/js-apis-data-udmf.md).
The following table lists the UDMF APIs. All of them are executed asynchronously in callback or promise mode. In the following table, callback-based APIs are used as an example. For more information about the APIs, see [Unified Data Channel](../reference/apis/js-apis-data-unifiedDataChannel.md) and [Standard Data Definition and Description](../reference/apis/js-apis-data-uniformTypeDescriptor.md).
| API | Description |
|-----------------------------------------------------------------------------------------|---------------------------------------------|
......@@ -45,121 +45,131 @@ The following example describes how to implement many-to-many data sharing. The
### Data Provider
1. Import the **@ohos.data.UDMF** module.
1. Import the **@ohos.data.unifiedDataChannel** and **@ohos.data.uniformTypeDescriptor** modules.
```ts
import UDMF from '@ohos.data.UDMF';
import unifiedDataChannel from '@ohos.data.unifiedDataChannel';
import uniformTypeDescriptor from '@ohos.data.uniformTypeDescriptor';
```
2. Create a **UnifiedData** object and insert it into the UDMF public data channel.
```ts
let plainText = new UDMF.PlainText();
import { BusinessError } from '@ohos.base';
let plainText = new unifiedDataChannel.PlainText();
plainText.textContent = 'hello world!';
let unifiedData = new UDMF.UnifiedData(plainText);
let unifiedData = new unifiedDataChannel.UnifiedData(plainText);
// Specify the type of the data channel to which the data is to be inserted.
let options = {
intention: UDMF.Intention.DATA_HUB
let options: unifiedDataChannel.Options = {
intention: unifiedDataChannel.Intention.DATA_HUB
}
try {
UDMF.insertData(options, unifiedData, (err, data) => {
if (err === undefined) {
console.info(`Succeeded in inserting data. key = ${data}`);
} else {
console.error(`Failed to insert data. code is ${err.code},message is ${err.message} `);
}
});
} catch(e) {
console.error(`Insert data throws an exception. code is ${e.code},message is ${e.message} `);
unifiedDataChannel.insertData(options, unifiedData, (err, data) => {
if (err === undefined) {
console.info(`Succeeded in inserting data. key = ${data}`);
} else {
console.error(`Failed to insert data. code is ${err.code},message is ${err.message} `);
}
});
} catch (e) {
let error: BusinessError = e as BusinessError;
console.error(`Insert data throws an exception. code is ${error.code},message is ${error.message} `);
}
```
3. Update the **UnifiedData** object inserted.
```ts
let plainText = new UDMF.PlainText();
import { BusinessError } from '@ohos.base';
let plainText = new unifiedDataChannel.PlainText();
plainText.textContent = 'How are you!';
let unifiedData = new UDMF.UnifiedData(plainText);
let unifiedData = new unifiedDataChannel.UnifiedData(plainText);
// Specify the URI of the UnifiedData object to update.
let options = {
key: 'udmf://DataHub/com.ohos.test/0123456789'
let options: unifiedDataChannel.Options = {
key: 'udmf://DataHub/com.ohos.test/0123456789'
};
try {
UDMF.updateData(options, unifiedData, (err) => {
if (err === undefined) {
console.info('Succeeded in updating data.');
} else {
console.error(`Failed to update data. code is ${err.code},message is ${err.message} `);
}
});
} catch(e) {
console.error(`Update data throws an exception. code is ${e.code},message is ${e.message} `);
unifiedDataChannel.updateData(options, unifiedData, (err) => {
if (err === undefined) {
console.info('Succeeded in updating data.');
} else {
console.error(`Failed to update data. code is ${err.code},message is ${err.message} `);
}
});
} catch (e) {
let error: BusinessError = e as BusinessError;
console.error(`Update data throws an exception. code is ${error.code},message is ${error.message} `);
}
```
4. Delete the **UnifiedData** object from the UDMF public data channel.
```ts
import { BusinessError } from '@ohos.base';
// Specify the type of the data channel whose data is to be deleted.
let options = {
intention: UDMF.Intention.DATA_HUB
let options: unifiedDataChannel.Options = {
intention: unifiedDataChannel.Intention.DATA_HUB
};
try {
UDMF.deleteData(options, (err, data) => {
if (err === undefined) {
console.info(`Succeeded in deleting data. size = ${data.length}`);
for (let i = 0; i < data.length; i++) {
let records = data[i].getRecords();
for (let j = 0; j < records.length; j++) {
if (records[j].getType() === UDMF.UnifiedDataType.PLAIN_TEXT) {
let text = <UDMF.PlainText>(records[j]);
console.info(`${i + 1}.${text.textContent}`);
}
}
}
} else {
console.error(`Failed to delete data. code is ${err.code},message is ${err.message} `);
unifiedDataChannel.deleteData(options, (err, data) => {
if (err === undefined) {
console.info(`Succeeded in deleting data. size = ${data.length}`);
for (let i = 0; i < data.length; i++) {
let records = data[i].getRecords();
for (let j = 0; j < records.length; j++) {
if (records[j].getType() === uniformTypeDescriptor.UniformDataType.PLAIN_TEXT) {
let text = records[j] as unifiedDataChannel.PlainText;
console.info(`${i + 1}.${text.textContent}`);
}
}
});
} catch(e) {
console.error(`Delete data throws an exception. code is ${e.code},message is ${e.message} `);
}
} else {
console.error(`Failed to delete data. code is ${err.code},message is ${err.message} `);
}
});
} catch (e) {
let error: BusinessError = e as BusinessError;
console.error(`Delete data throws an exception. code is ${error.code},message is ${error.message} `);
}
```
### Data Consumer
1. Import the **@ohos.data.UDMF** module.
1. Import the **@ohos.data.unifiedDataChannel** and **@ohos.data.uniformTypeDescriptor** modules.
```ts
import UDMF from '@ohos.data.UDMF';
import unifiedDataChannel from '@ohos.data.unifiedDataChannel';
import uniformTypeDescriptor from '@ohos.data.uniformTypeDescriptor';
```
2. Query the **UnifiedData** object in the UDMF public data channel.
```ts
import { BusinessError } from '@ohos.base';
// Specify the type of the data channel whose data is to be queried.
let options = {
intention: UDMF.Intention.DATA_HUB
let options: unifiedDataChannel.Options = {
intention: unifiedDataChannel.Intention.DATA_HUB
};
try {
UDMF.queryData(options, (err, data) => {
if (err === undefined) {
console.info(`Succeeded in querying data. size = ${data.length}`);
for (let i = 0; i < data.length; i++) {
let records = data[i].getRecords();
for (let j = 0; j < records.length; j++) {
if (records[j].getType() === UDMF.UnifiedDataType.PLAIN_TEXT) {
let text = <UDMF.PlainText>(records[j]);
console.info(`${i + 1}.${text.textContent}`);
}
}
}
} else {
console.error(`Failed to query data. code is ${err.code},message is ${err.message} `);
unifiedDataChannel.queryData(options, (err, data) => {
if (err === undefined) {
console.info(`Succeeded in querying data. size = ${data.length}`);
for (let i = 0; i < data.length; i++) {
let records = data[i].getRecords();
for (let j = 0; j < records.length; j++) {
if (records[j].getType() === uniformTypeDescriptor.UniformDataType.PLAIN_TEXT) {
let text = records[j] as unifiedDataChannel.PlainText;
console.info(`${i + 1}.${text.textContent}`);
}
}
});
}
} else {
console.error(`Failed to query data. code is ${err.code},message is ${err.message} `);
}
});
} catch(e) {
console.error(`Query data throws an exception. code is ${e.code},message is ${e.message} `);
let error: BusinessError = e as BusinessError;
console.error(`Query data throws an exception. code is ${error.code},message is ${error.message} `);
}
```
......@@ -5,28 +5,35 @@
To streamline cross-application data interaction of OpenHarmony and minimize the application/service data interaction costs, the Unified Data Management Framework (UDMF) provides standard data definitions to define common data types. Applications can use the APIs provided by the UDMF to create and use these data types.
For example, in the cross-application drag scenario, the application of the drag source writes the data to be dragged to a [drag event](../reference/arkui-ts/ts-universal-events-drag-drop.md#dragevent) based on the standard data definitions. The application of the drop target reads the dragged data from the drag event and parses the data based on the standard data definitions. The data dragged between different applications complies with the same standard definitions, which avoids exhaustive data type adaptation and effectively reduces the development workload.
## Unified Data Types
The UDMF provides the following unified data types:
**Basic data types**<br>Basic data types include File and Text, which can be used for cross-application and cross-platform data interaction. Figure 1 and Figure 2 illustrate the basic data types.
**Basic data types**
Basic data types include File and Text, which can be used for cross-application and cross-platform data interaction. Figure 1 and Figure 2 illustrate the basic data types.
**Figure 1** UDMF File
![UDMF_FILE](figures/udmf_type_File.png)
Figure 2 UDMF Text
**Figure 2** UDMF Text
![UDMF_TEXT](figures/udmf_type_Text.png)
**System Defined Types (SDTs)**<br>The SDTs are specific to the platform or operating system, such as Form (UI card information), AppItem (app description information), and PixelMap (thumbnail). This type of data can be used for cross-application data interaction in a system or platform. Figure 3 illustrates the SDT data.
**System Defined Types (SDTs)**
The SDTs are specific to the platform or operating system, such as Form (UI card information), AppItem (app description information), and PixelMap (thumbnail). This type of data can be used for cross-application data interaction in a system or platform. Figure 3 illustrates the SDT data.
**Figure 3** UDMF SDT data
![UDMF_SDT](figures/udmf_type_SDT.png)
**App Defined Type (ADT)**<br>The SDT data is application-specific. This type of data can be used for across-platform data interaction for an application. As shown in Figure 4, the MyFile file format can be defined for use in an application ecosystem.
**App Defined Type (ADT)**
The SDT data is application-specific. This type of data can be used for across-platform data interaction for an application. As shown in Figure 4, the MyFile file format can be defined for use in an application ecosystem.
**Figure 4** UDMF ADT data
......@@ -39,11 +46,11 @@ Figure 2 UDMF Text
## Available APIs
The UDMF provides the unified data object **UnifiedData** to encapsulate a group of data records **UnifiedRecord**. **UnifiedRecord** is an abstract definition of data content supported by the UDMF, for example, a text record or an image record. The data content type in a data record corresponds to **UnifiedDataType**.
The UDMF provides the unified data object **UnifiedData** to encapsulate a group of data records **UnifiedRecord**. **UnifiedRecord** is an abstract definition of data content supported by the UDMF, for example, a text record or an image record. The data content type in a data record corresponds to **UniformDataType**.
The following table describes common UDMF APIs. For more information, see [UDMF](../reference/apis/js-apis-data-udmf.md).
The following table describes common UDMF APIs. For more information about the APIs, see [Unified Data Channel](../reference/apis/js-apis-data-unifiedDataChannel.md) and [Standard Data Definition and Description](../reference/apis/js-apis-data-uniformTypeDescriptor.md).
| Class | API | Description |
| Class | API | Description |
|---------------|-------------------|-----------------------------------------------------------------------------------------------|
| UnifiedRecord | getType(): string | Obtains the data type of this data record.|
| UnifiedData | constructor(record: UnifiedRecord) | A constructor used to create a **UnifiedData** object with a data record. |
......@@ -55,17 +62,19 @@ The following table describes common UDMF APIs. For more information, see [UDMF]
The following describes how to create a **UnifiedData** object containing two data records: image and plain text.
1. Import the **@ohos.data.UDMF** module.
1. Import the **@ohos.data.unifiedDataChannel** and **@ohos.data.uniformTypeDescriptor** modules.
```ts
import UDMF from '@ohos.data.UDMF';
import unifiedDataChannel from '@ohos.data.unifiedDataChannel';
import uniformTypeDescriptor from '@ohos.data.uniformTypeDescriptor';
```
2. Create an image data record and initialize the **UnifiedData** object with the image data record.
(1) Create an image data record.
```ts
let image = new UDMF.Image();
let image = new unifiedDataChannel.Image();
```
(2) Modify object attributes.
......@@ -84,12 +93,13 @@ The following describes how to create a **UnifiedData** object containing two da
(4) Create a **UnifiedData** instance.
```ts
let unifiedData = new UDMF.UnifiedData(image);
let unifiedData = new unifiedDataChannel.UnifiedData(image);
```
3. Create a plain text data record and add it to the **UnifiedData** instance created.
3. Create a plain text data record and add it to the **UnifiedData** instance created.
```ts
let plainText = new UDMF.PlainText();
let plainText = new unifiedDataChannel.PlainText();
plainText.textContent = 'this is textContent of plainText';
plainText.abstract = 'abstract of plainText';
plainText.details = {
......@@ -98,25 +108,27 @@ The following describes how to create a **UnifiedData** object containing two da
};
unifiedData.addRecord(plainText);
```
4. Obtain all data records in this **UnifiedData** instance.
```ts
let records = unifiedData.getRecords();
```
5. Traverse each record, determine the data type of the record, and convert the record into a child class object to obtain the original data record.
```ts
for (let i = 0; i < records.length; i ++) {
// Read the type of the data record.
let type = records[i].getType();
switch (type) {
case UDMF.UnifiedDataType.IMAGE:
case uniformTypeDescriptor.UniformDataType.IMAGE:
// Convert the data to obtain the original image data record.
let image = <UDMF.Image>(records[i]);
let image = records[i] as unifiedDataChannel.Image;
break;
case UDMF.UnifiedDataType.PLAIN_TEXT:
case uniformTypeDescriptor.UniformDataType.PLAIN_TEXT:
// Convert the data to obtain the original text record.
let plainText = <UDMF.PlainText>(records[i]);
let plainText = records[i] as unifiedDataChannel.PlainText;
break;
default:
break;
......
......@@ -279,7 +279,8 @@
- [@ohos.data.distributedKVStore (Distributed KV Store)](js-apis-distributedKVStore.md)
- [@ohos.data.preferences (User Preferences)](js-apis-data-preferences.md)
- [@ohos.data.relationalStore (RDB Store)](js-apis-data-relationalStore.md)
- [@ohos.data.UDMF (Unfied Data Management Framework)](js-apis-data-udmf.md)
- [@ohos.data.unifiedDataChannel (Unified Data Channel)](js-apis-data-unifiedDataChannel.md)
- [@ohos.data.uniformTypeDescriptor (Standard Data Definition)](js-apis-data-uniformTypeDescriptor.md)
- [@ohos.data.ValuesBucket (Value Bucket)](js-apis-data-valuesBucket.md)
- File Management
......
......@@ -4,11 +4,10 @@ The **DataShareExtensionAbility** module provides data share services based on t
>**NOTE**
>
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
> - The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
>
> The APIs provided by this module are system APIs.
> - The APIs provided by this module are system APIs and can be used only in the stage model.
>
> The APIs of this module can be used only in the stage model.
## Modules to Import
......@@ -21,7 +20,7 @@ import DataShareExtensionAbility from '@ohos.application.DataShareExtensionAbili
**System capability**: SystemCapability.DistributedDataManager.DataShare.Provider
| Name| Type| Readable| Writable| Description|
| Name| Type| Readable| Writable| Description|
| -------- | -------- | -------- | -------- | -------- |
| context<sup>10+</sup> | [ExtensionContext](js-apis-inner-application-extensionContext.md) | Yes| No|DataShareExtensionAbility context, inherited from [ExtensionContext](js-apis-inner-application-extensionContext.md).|
......@@ -50,17 +49,17 @@ let TBL_NAME = 'TBL00';
let DDL_TBL_CREATE = 'CREATE TABLE IF NOT EXISTS '
+ TBL_NAME
+ ' (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, phoneNumber DOUBLE, isStudent BOOLEAN, Binary BINARY)';
let rdbStore;
let rdbStore: relationalStore.RdbStore;
export default class DataShareExtAbility extends DataShareExtensionAbility {
onCreate(want, callback) {
onCreate(want: Want, callback: Function) {
rdb.getRdbStore(this.context, {
name: DB_NAME,
securityLevel: rdb.SecurityLevel.S1
}, function (err, data) {
}, (err, data) => {
console.info(`getRdbStore done, data : ${data}`);
rdbStore = data;
rdbStore.executeSql(DDL_TBL_CREATE, [], function (err) {
rdbStore.executeSql(DDL_TBL_CREATE, [], (err) => {
console.error(`executeSql done, error message : ${err}`);
});
if (callback) {
......@@ -91,21 +90,22 @@ Inserts data into the database. This API can be overridden as required.
```ts
import rdb from '@ohos.data.relationalStore';
import { ValuesBucket } from '@ohos.data.ValuesBucket'
let DB_NAME = 'DB00.db';
let TBL_NAME = 'TBL00';
let DDL_TBL_CREATE = 'CREATE TABLE IF NOT EXISTS '
+ TBL_NAME
+ ' (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, phoneNumber DOUBLE, isStudent BOOLEAN, Binary BINARY)';
let rdbStore;
let rdbStore: relationalStore.RdbStore;
export default class DataShareExtAbility extends DataShareExtensionAbility {
insert(uri, valueBucket, callback) {
insert(uri: string, valueBucket: ValuesBucket, callback: Function) {
if (valueBucket === null) {
console.error('invalid valueBuckets');
return;
}
rdbStore.insert(TBL_NAME, valueBucket, function (err, ret) {
rdbStore.insert(TBL_NAME, valueBucket, (err, ret) => {
console.info(`callback ret: ${ret}`);
if (callback !== undefined) {
callback(err, ret);
......@@ -136,20 +136,22 @@ Updates data in the database. This API can be overridden as required.
```ts
import rdb from '@ohos.data.relationalStore';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
import { ValuesBucket } from '@ohos.data.ValuesBucket'
let DB_NAME = 'DB00.db';
let TBL_NAME = 'TBL00';
let DDL_TBL_CREATE = 'CREATE TABLE IF NOT EXISTS '
+ TBL_NAME
+ ' (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, phoneNumber DOUBLE, isStudent BOOLEAN, Binary BINARY)';
let rdbStore;
let rdbStore: relationalStore.RdbStore;
export default class DataShareExtAbility extends DataShareExtensionAbility {
update(uri, predicates, valueBucket, callback) {
update(uri: string, predicates: dataSharePredicates.DataSharePredicates, valueBucket: ValuesBucket, callback: Function) {
if (predicates === null || predicates === undefined) {
return;
}
rdbStore.update(TBL_NAME, valueBucket, predicates, function (err, ret) {
rdbStore.update(TBL_NAME, valueBucket, predicates, (err, ret) => {
if (callback !== undefined) {
callback(err, ret);
}
......@@ -178,20 +180,21 @@ Deletes data from the database. This API can be overridden as required.
```ts
import rdb from '@ohos.data.relationalStore';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
let DB_NAME = 'DB00.db';
let TBL_NAME = 'TBL00';
let DDL_TBL_CREATE = 'CREATE TABLE IF NOT EXISTS '
+ TBL_NAME
+ ' (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, phoneNumber DOUBLE, isStudent BOOLEAN, Binary BINARY)';
let rdbStore;
let rdbStore: relationalStore.RdbStore;
export default class DataShareExtAbility extends DataShareExtensionAbility {
delete(uri, predicates, callback) {
delete(uri: string, predicates: dataSharePredicates.DataSharePredicates, callback: Function) {
if (predicates === null || predicates === undefined) {
return;
}
rdbStore.delete(TBL_NAME, predicates, function (err, ret) {
rdbStore.delete(TBL_NAME, predicates, (err, ret) => {
if (callback !== undefined) {
callback(err, ret);
}
......@@ -221,20 +224,21 @@ Queries data from the database. This API can be overridden as required.
```ts
import rdb from '@ohos.data.relationalStore';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
let DB_NAME = 'DB00.db';
let TBL_NAME = 'TBL00';
let DDL_TBL_CREATE = 'CREATE TABLE IF NOT EXISTS '
+ TBL_NAME
+ ' (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, phoneNumber DOUBLE, isStudent BOOLEAN, Binary BINARY)';
let rdbStore;
let rdbStore: relationalStore.RdbStore;
export default class DataShareExtAbility extends DataShareExtensionAbility {
query(uri, predicates, columns, callback) {
query(uri: string, predicates: dataSharePredicates.DataSharePredicates, columns: Array<string>, callback: Function) {
if (predicates === null || predicates === undefined) {
return;
}
rdbStore.query(TBL_NAME, predicates, columns, function (err, resultSet) {
rdbStore.query(TBL_NAME, predicates, columns, (err, resultSet) => {
if (resultSet !== undefined) {
console.info(`resultSet.rowCount: ${resultSet.rowCount}`);
}
......@@ -266,21 +270,22 @@ Batch inserts data into the database. This API is called by the server and can b
```ts
import rdb from '@ohos.data.relationalStore';
import { ValuesBucket } from '@ohos.data.ValuesBucket'
let DB_NAME = 'DB00.db';
let TBL_NAME = 'TBL00';
let DDL_TBL_CREATE = 'CREATE TABLE IF NOT EXISTS '
+ TBL_NAME
+ ' (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, phoneNumber DOUBLE, isStudent BOOLEAN, Binary BINARY)';
let rdbStore;
let rdbStore: relationalStore.RdbStore;
export default class DataShareExtAbility extends DataShareExtensionAbility {
batchInsert(uri, valueBuckets, callback) {
batchInsert(uri: string, valueBuckets: Array<ValuesBucket>, callback: Function) {
if (valueBuckets === null || valueBuckets.length === undefined) {
console.error('invalid valueBuckets');
return;
}
rdbStore.batchInsert(TBL_NAME, valueBuckets, function (err, ret) {
rdbStore.batchInsert(TBL_NAME, valueBuckets, (err, ret) => {
if (callback !== undefined) {
callback(err, ret);
}
......@@ -308,11 +313,17 @@ Normalizes a URI. This API can be overridden as required.
```ts
export default class DataShareExtAbility extends DataShareExtensionAbility {
normalizeUri(uri, callback) {
let err = {'code':0};
let ret = `normalize: ${uri}`;
callback(err, ret);
}
normalizeUri(uri: string, callback: Function) {
let key = 'code';
let value = 0;
let err: BusinessError = {
code: value,
name: key,
message: key
};
let ret: string = `normalize: ${uri}`;
callback(err, ret);
}
};
```
......@@ -335,10 +346,16 @@ Denormalizes a URI. This API can be overridden as required.
```ts
export default class DataShareExtAbility extends DataShareExtensionAbility {
denormalizeUri(uri, callback) {
let err = {'code':0};
let ret = `denormalize ${uri}`;
callback(err, ret);
}
denormalizeUri(uri: string, callback: Function) {
let key = 'code';
let value = 0;
let err: BusinessError = {
code: value,
name: key,
message: key
};
let ret = `denormalize ${uri}`;
callback(err, ret);
}
};
```
......@@ -4,9 +4,9 @@ The **DataShareResultSet** module provides APIs for accessing the result set obt
> **NOTE**
>
> The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
> - The initial APIs of this module are supported since API version 9. Newly added APIs will be marked with a superscript to indicate their earliest API version.
>
> The APIs provided by this module are system APIs.
> - The APIs provided by this module are system APIs.
## Modules to Import
......@@ -22,8 +22,9 @@ You can call [query()](js-apis-data-dataShare.md#query) to obtain the **DataShar
```ts
import dataShare from '@ohos.data.dataShare';
import dataSharePredicates from '@ohos.data.dataSharePredicates'
import { BusinessError } from '@ohos.base'
let dataShareHelper;
let dataShareHelper: dataShare.DataShareHelper;
let uri = ("datashare:///com.samples.datasharetest.DataShare");
await dataShare.createDataShareHelper(this.context, uri, (err, data) => {
if (err != undefined) {
......@@ -36,12 +37,12 @@ await dataShare.createDataShareHelper(this.context, uri, (err, data) => {
let columns = ["*"];
let da = new dataSharePredicates.DataSharePredicates();
let resultSet;
let resultSet: DataShareResultSet;
da.equalTo("name", "ZhangSan");
dataShareHelper.query(uri, da, columns).then((data) => {
dataShareHelper.query(uri, da, columns).then((data: DataShareResultSet) => {
console.info("query end, data : " + data);
resultSet = data;
}).catch((err) => {
}).catch((err: BusinessError) => {
console.error("query fail, error message : " + err);
});
```
......
......@@ -43,11 +43,11 @@ FA model:
```js
// Obtain the context.
import featureAbility from '@ohos.ability.featureAbility'
let context = featureAbility.getContext()
let context: Context;
// Call getRdbStore.
const STORE_CONFIG = { name: "RdbTest.db"}
data_rdb.getRdbStore(context, STORE_CONFIG, 1, function (err, rdbStore) {
data_rdb.getRdbStore(context, STORE_CONFIG, 1, (err, rdbStore) => {
if (err) {
console.info("Failed to get RdbStore, err: " + err)
return
......@@ -61,23 +61,26 @@ Stage model:
```ts
// Obtain the context.
import UIAbility from '@ohos.app.ability.UIAbility';
import { BusinessError } from "@ohos.base";
import window from '@ohos.window';
let context;
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage){
context = this.context
}
let context: Context;
interface storeConfig {
name: string
}
// Call getRdbStore.
const STORE_CONFIG = { name: "RdbTest.db"}
data_rdb.getRdbStore(context, STORE_CONFIG, 1, function (err, rdbStore) {
if (err) {
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage){
let STORE_CONFIG: storeConfig = { name: "RdbTest.db"};
data_rdb.getRdbStore(this.context, STORE_CONFIG, 1, (err: BusinessError, rdbStore: data_rdb.RdbStore) => {
if (err) {
console.info("Failed to get RdbStore, err: " + err)
return
}
console.log("Got RdbStore successfully.")
})
}
console.log("Got RdbStore successfully.")
})
}
}
```
## data_rdb.getRdbStore
......@@ -109,7 +112,7 @@ FA model:
```js
// Obtain the context.
import featureAbility from '@ohos.ability.featureAbility'
let context = featureAbility.getContext()
let context: Context;
// Call getRdbStore.
const STORE_CONFIG = { name: "RdbTest.db" }
......@@ -126,21 +129,26 @@ Stage model:
```ts
// Obtain the context.
import UIAbility from '@ohos.app.ability.UIAbility';
import { BusinessError } from "@ohos.base";
import window from '@ohos.window';
let context;
let context: Context;
interface storeConfig {
name: string
}
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage){
context = this.context
}
onWindowStageCreate(windowStage: window.WindowStage){
context = this.context
}
}
// Call getRdbStore.
const STORE_CONFIG = { name: "RdbTest.db" }
let STORE_CONFIG: storeConfig = { name: "RdbTest.db"};
let promise = data_rdb.getRdbStore(context, STORE_CONFIG, 1);
promise.then(async (rdbStore) => {
console.log("Got RdbStore successfully.")
}).catch((err) => {
console.log("Failed to get RdbStore, err: " + err)
promise.then(async (rdbStore: data_rdb.RdbStore) => {
console.log("Got RdbStore successfully.")
}).catch((err: BusinessError) => {
console.log("Failed to get RdbStore, err: " + err)
})
```
......@@ -167,15 +175,15 @@ FA model:
```js
// Obtain the context.
import featureAbility from '@ohos.ability.featureAbility'
let context = featureAbility.getContext()
let context: Context;
// Call deleteRdbStore.
data_rdb.deleteRdbStore(context, "RdbTest.db", function (err) {
if (err) {
console.info("Failed to delete RdbStore, err: " + err)
return
}
console.log("Deleted RdbStore successfully.")
data_rdb.deleteRdbStore(context, "RdbTest.db", (err) => {
if (err) {
console.info("Failed to delete RdbStore, err: " + err)
return
}
console.log("Deleted RdbStore successfully.")
})
```
......@@ -184,21 +192,22 @@ Stage model:
```ts
// Obtain the context.
import UIAbility from '@ohos.app.ability.UIAbility';
import window from '@ohos.window';
let context;
let context: Context;
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage){
context = this.context
}
onWindowStageCreate(windowStage: window.WindowStage){
context = this.context
}
}
// Call deleteRdbStore.
data_rdb.deleteRdbStore(context, "RdbTest.db", function (err) {
if (err) {
console.info("Failed to delete RdbStore, err: " + err)
return
}
console.log("Deleted RdbStore successfully.")
data_rdb.deleteRdbStore(context, "RdbTest.db", (err) => {
if (err) {
console.info("Failed to delete RdbStore, err: " + err)
return
}
console.log("Deleted RdbStore successfully.")
})
```
......@@ -230,7 +239,7 @@ FA model:
```js
// Obtain the context.
import featureAbility from '@ohos.ability.featureAbility'
let context = featureAbility.getContext()
let context: Context;
// Call deleteRdbStore.
let promise = data_rdb.deleteRdbStore(context, "RdbTest.db")
......@@ -246,20 +255,22 @@ Stage model:
```ts
// Obtain the context.
import UIAbility from '@ohos.app.ability.UIAbility';
import { BusinessError } from "@ohos.base";
import window from '@ohos.window';
let context;
let context: Context;
class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage){
context = this.context
}
onWindowStageCreate(windowStage: window.WindowStage){
context = this.context
}
}
// Call deleteRdbStore.
let promise = data_rdb.deleteRdbStore(context, "RdbTest.db")
promise.then(()=>{
console.log("Deleted RdbStore successfully.")
}).catch((err) => {
console.info("Failed to delete RdbStore, err: " + err)
console.log("Deleted RdbStore successfully.")
}).catch((err: BusinessError) => {
console.info("Failed to delete RdbStore, err: " + err)
})
```
......@@ -371,8 +382,8 @@ Sets an **RdbPredicates** to specify the remote devices to connect on the networ
```js
import deviceManager from '@ohos.distributedHardware.deviceManager';
let dmInstance = null;
let deviceIds = [];
let dmInstance: deviceManager.DeviceManager = null;
let deviceIds: Array<string> = [];
deviceManager.createDeviceManager("com.example.appdatamgrverify", (err, manager) => {
if (err) {
......@@ -381,7 +392,7 @@ deviceManager.createDeviceManager("com.example.appdatamgrverify", (err, manager)
}
dmInstance = manager;
let devices = dmInstance.getTrustedDeviceListSync();
for (var i = 0; i < devices.length; i++) {
for (let i = 0; i < devices.length; i++) {
deviceIds[i] = devices[i].deviceId;
}
})
......
# @ohos.data.uniformTypeDescriptor (Standard Data Definition)
The **uniformTypeDescriptor** module provides abstract definitions of OpenHarmony standardized data types.
> **NOTE**
>
> The initial APIs of this module are supported since API version 10. Newly added APIs will be marked with a superscript to indicate their earliest API version.
## Modules to Import
```js
import uniformTypeDescriptor from '@ohos.data.uniformTypeDescriptor';
```
## UniformDataType
Enumerates the types of OpenHarmony standard data.
**System capability**: SystemCapability.DistributedDataManager.UDMF.Core
| Name | Value | Description |
|----------------------------|------------------------------|-----------|
| TEXT | 'general.text' | Text. |
| PLAIN_TEXT | 'general.plain-text' | Plaintext. |
| HYPERLINK | 'general.hyperlink' | Hyperlink. |
| HTML | 'general.html' | HyperText Markup Language (HTML). |
| FILE | 'general.file' | File. |
| IMAGE | 'general.image' | Image. |
| VIDEO | 'general.video' | Video. |
| AUDIO | 'general.audio' | Audio. |
| FOLDER | 'general.folder' | Folder. |
| OPENHARMONY_FORM | 'openharmony.form' | Widget. |
| OPENHARMONY_APP_ITEM | 'openharmony.app-item' | Icon. |
| OPENHARMONY_PIXEL_MAP | 'openharmony.pixel-map' | Pixel map. |
......@@ -156,7 +156,9 @@ OpenHarmony IDL容器数据类型与Ts数据类型、C++数据类型的对应关
进入对应路径后,查看toolchains->3.x.x.x(对应版本号命名文件夹)下是否存在idl工具的可执行文件。
> **注意**:请保证使用最新版的SDK,版本老旧可能导致部分语句报错。
> **注意**:
>
> 请保证使用最新版的SDK,版本老旧可能导致部分语句报错。
若不存在,可对应版本前往[docs仓版本目录](../../release-notes)下载SDK包,以[3.2Beta3版本](../../release-notes/OpenHarmony-v3.2-beta3.md)为例,可通过镜像站点获取。
......@@ -185,7 +187,9 @@ OpenHarmony IDL容器数据类型与Ts数据类型、C++数据类型的对应关
-d后的dir为目标输出目录,以输出文件夹名为IIdlTestServiceTs为例,在idl可执行文件所在目录下执行`idl -gen-ts -d IIdlTestServiceTs -c IIdlTestServiceTs/IIdlTestService.idl`,将会在执行环境的dir目录(即IIdlTestServiceTs目录)中生成接口文件、Stub文件、Proxy文件。
> **注意**:生成的接口类文件名称和.idl文件名称保持一致,否则会生成代码时会出现错误。
> **注意**:
>
> 生成的接口类文件名称和.idl文件名称保持一致,否则会生成代码时会出现错误。
以名为`IIdlTestService.idl`的.idl文件、目标输出文件夹为IIdlTestServiceTs为例,其目录结构应类似于:
......
......@@ -20,7 +20,9 @@ singleton启动模式为单实例模式,也是默认情况下的启动模式
**图1** 单实例模式演示效果
![uiability-launch-type1](figures/uiability-launch-type1.gif)
> **说明**:应用的UIAbility实例已创建,该UIAbility配置为单实例模式,再次调用[`startAbility()`](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability)方法启动该UIAbility实例。由于启动的还是原来的UIAbility实例,并未重新创建一个新的UIAbility实例,此时只会进入该UIAbility的[`onNewWant()`](../reference/apis/js-apis-app-ability-uiAbility.md#abilityonnewwant)回调,不会进入其[`onCreate()`](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityoncreate)和[`onWindowStageCreate()`](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate)生命周期回调。
> **说明**:
>
> 应用的UIAbility实例已创建,该UIAbility配置为单实例模式,再次调用[`startAbility()`](../reference/apis/js-apis-inner-application-uiAbilityContext.md#uiabilitycontextstartability)方法启动该UIAbility实例。由于启动的还是原来的UIAbility实例,并未重新创建一个新的UIAbility实例,此时只会进入该UIAbility的[`onNewWant()`](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityonnewwant)回调,不会进入其[`onCreate()`](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityoncreate)和[`onWindowStageCreate()`](../reference/apis/js-apis-app-ability-uiAbility.md#uiabilityonwindowstagecreate)生命周期回调。
如果需要使用singleton启动模式,在[module.json5配置文件](../quick-start/module-configuration-file.md)中的`launchType`字段配置为`singleton`即可。
......
......@@ -32,7 +32,9 @@ export default class EntryAbility extends UIAbility {
}
```
> **说明**:[Want](../reference/apis/js-apis-app-ability-want.md)是对象间信息传递的载体,可以用于应用组件间的信息传递。Want的详细介绍请参见[信息传递载体Want](want-overview.md)。
> **说明**:
>
> [Want](../reference/apis/js-apis-app-ability-want.md)是对象间信息传递的载体,可以用于应用组件间的信息传递。Want的详细介绍请参见[信息传递载体Want](want-overview.md)。
### WindowStageCreate和WindowStageDestory状态
......
......@@ -166,10 +166,10 @@ IPC/RPC的主要工作是让运行在不同进程的Proxy和Stub互相通信,
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId);
sptr<ITestAbility> testAbility = iface_cast<ITestAbility>(remoteObject); // 使用iface_cast宏转换成具体类型
// 获取其他设备注册的SA的proxy
sptr<ISystemAbilityManager> samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
// networkId是组网场景下对应设备的标识符,可以通过GetLocalNodeDeviceInfo获取
sptr<IRemoteObject> remoteObject = samgr->GetSystemAbility(saId, networkId);
sptr<TestAbilityProxy> proxy(new TestAbilityProxy(remoteObject)); // 直接构造具体Proxy
......@@ -231,8 +231,10 @@ IPC/RPC的主要工作是让运行在不同进程的Proxy和Stub互相通信,
import Want from '@ohos.app.ability.Want';
import common from '@ohos.app.ability.common';
import deviceManager from '@ohos.distributedHardware.deviceManager';
import { BusinessError } from '@ohos.base';
let proxy: rpc.RemoteProxy;
let dmInstance: deviceManager.DeviceManager | undefined;
let proxy: rpc.IRemoteObject | undefined = undefined;
let connectId: number;
// 单个设备绑定Ability
......@@ -242,7 +244,7 @@ IPC/RPC的主要工作是让运行在不同进程的Proxy和Stub互相通信,
abilityName: "ohos.rpc.test.server.ServiceAbility",
};
let connect: common.ConnectOptions = {
onConnect: (elementName, remote: rpc.RemoteProxy) => {
onConnect: (elementName, remote) => {
proxy = remote;
},
onDisconnect: (elementName) => {
......@@ -259,29 +261,36 @@ IPC/RPC的主要工作是让运行在不同进程的Proxy和Stub互相通信,
// 跨设备绑定
let deviceManagerCallback = (err: BusinessError, data: deviceManager.DeviceManager) => {
if (err) {
console.error("createDeviceManager errCode:" + err.code + ",errMessage:" + err.message);
return;
console.error("createDeviceManager errCode:" + err.code + ",errMessage:" + err.message);
return;
}
console.info("createDeviceManager success");
let dmInstance = data;
dmInstance = data;
}
try{
deviceManager.createDeviceManager("ohos.rpc.test", deviceManagerCallback);
} catch(error) {
let e: BusinessError = error as BusinessError;
console.error("createDeviceManager errCode:" + err.code + ",errMessage:" + err.message);
}
// 使用deviceManager获取目标设备NetworkId
if (dmInstance != undefined) {
let deviceList: Array<deviceManager.DeviceInfo> = dmInstance.getTrustedDeviceListSync();
let networkId: string = deviceList[0].networkId;
let want: Want = {
bundleName: "ohos.rpc.test.server",
abilityName: "ohos.rpc.test.service.ServiceAbility",
deviceId: networkId,
flags: 256
};
// 建立连接后返回的Id需要保存下来,在断开连接时需要作为参数传入
// FA模型使用此方法连接服务
// connectId = featureAbility.connectAbility(want, connect);
// 第一个参数是本应用的包名,第二个参数是接收deviceManager的回调函数
connectId = this.context.connectServiceExtensionAbility(want,connect);
}
deviceManager.createDeviceManager("ohos.rpc.test", deviceManagerCallback);
// 使用deviceManager获取目标设备NetworkId
let deviceList: Array<deviceManager.DeviceInfo> = dmInstance.getTrustedDeviceListSync();
let networkId: string = deviceList[0].networkId;
let want: Want = {
bundleName: "ohos.rpc.test.server",
abilityName: "ohos.rpc.test.service.ServiceAbility",
deviceId: networkId,
flags: 256
};
// 建立连接后返回的Id需要保存下来,在断开连接时需要作为参数传入
// FA模型使用此方法连接服务
// connectId = featureAbility.connectAbility(want, connect);
// 第一个参数是本应用的包名,第二个参数是接收deviceManager的回调函数
connectId = this.context.connectServiceExtensionAbility(want,connect);
```
3. 服务端处理客户端请求
......@@ -289,11 +298,7 @@ IPC/RPC的主要工作是让运行在不同进程的Proxy和Stub互相通信,
服务端被绑定的Ability在onConnect方法里返回继承自rpc.RemoteObject的对象,该对象需要实现onRemoteMessageRequest方法,处理客户端的请求。
```ts
onConnect(want: Want) {
const robj: rpc.RemoteObject = new Stub("rpcTestAbility");
return robj;
}
class Stub extends rpc.RemoteObject {
class Stub extends rpc.RemoteObject {
constructor(descriptor: string) {
super(descriptor);
}
......@@ -301,7 +306,11 @@ IPC/RPC的主要工作是让运行在不同进程的Proxy和Stub互相通信,
// 根据code处理客户端的请求
return true;
}
}
}
onConnect(want: Want) {
const robj: rpc.RemoteObject = new Stub("rpcTestAbility");
return robj;
}
```
4. 客户端处理服务端响应
......@@ -359,6 +368,7 @@ IPC/RPC的主要工作是让运行在不同进程的Proxy和Stub互相通信,
import rpc from "@ohos.rpc";
// 仅FA模型需要导入@ohos.ability.featureAbility
// import featureAbility from "@ohos.ability.featureAbility";
function disconnectCallback() {
console.info("disconnect ability done");
}
......
......@@ -98,7 +98,6 @@ import Want from '@ohos.app.ability.Want';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import window from '@ohos.window';
export default class MainAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
console.log("[Demo] MainAbility onCreate");
......@@ -134,9 +133,9 @@ export default class MainAbility extends UIAbility {
import Want from '@ohos.app.ability.Want';
import common from '@ohos.app.ability.common';
let proxy: rpc.RemoteProxy;
let proxy: rpc.IRemoteObject | undefined = undefined;
let connect: common.ConnectOptions = {
onConnect: (elementName, remoteProxy: rpc.RemoteProxy) => {
onConnect: (elementName, remoteProxy) => {
console.log("RpcClient: js onConnect called.");
proxy = remoteProxy;
},
......
......@@ -30,6 +30,7 @@ hiTraceChain是基于云计算分布式跟踪调用链思想,在端侧业务
```ts
import hiTraceChain from '@ohos.hiTraceChain';
import hiSysEvent from '@ohos.hiSysEvent';
import { BusinessError } from '@ohos.base';
@Entry
@Component
......@@ -50,26 +51,28 @@ hiTraceChain是基于云计算分布式跟踪调用链思想,在端侧业务
// 业务开始前,开启分布式跟踪。
let traceId = hiTraceChain.begin("Write a new system event", hiTraceChain.HiTraceFlag.INCLUDE_ASYNC);
// 业务开始:完成一次系统事件打点。
hiSysEvent.write({
let customizedParams: Record<string, string | number> = {
'PID': 1,
'UID': 1,
'PACKAGE_NAME': "com.demo.hitracechain",
'PROCESS_NAME': "hitracechaindemo",
'MSG': "no msg."
}
let eventInfo: hiSysEvent.SysEventInfo = {
domain: "RELIABILITY",
name: "STACK",
eventType: hiSysEvent.EventType.FAULT,
params: {
PID: 1,
UID: 1,
PACKAGE_NAME: "com.demo.hitracechain",
PROCESS_NAME: "hitracechaindemo",
MSG: "no msg."
}
}).then((val) => {
params: customizedParams
}
hiSysEvent.write(eventInfo).then((val: number) => {
console.info(`write result is ${val}`);
// 业务结束,关闭分布式跟踪。
hiTraceChain.end(traceId);
}).catch((err) => {
}).catch((err: BusinessError) => {
console.error(`error message is ${err.message}`);
});
} catch (err) {
console.error(`error message is ${err.message}`);
console.error(`error message is ${(err as BusinessError).message}`);
}
})
}
......
# 人像模式拍照实现方案
# 使用人像模式拍照
## 开发流程
......
......@@ -60,7 +60,7 @@
```ts
@Component
struct TotalView {
@Prop @Watch('onCountUpdated') count: number;
@Prop @Watch('onCountUpdated') count: number = 0;
@State total: number = 0;
// @Watch cb
onCountUpdated(propName: string): void {
......
......@@ -1040,7 +1040,7 @@ try {
### ACCELEROMETER_UNCALIBRATED<sup>9+</sup>
once(type: SensorId.ACCELEROMETER_UNCALIBRATED, callback: Callback&lt;AccelerometerUncalibratedResponse&gt;): voidMAGNETIC_FIELD
once(type: SensorId.ACCELEROMETER_UNCALIBRATED, callback: Callback&lt;AccelerometerUncalibratedResponse&gt;): void
获取一次未校准加速度传感器数据。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册