提交 a0c860cd 编写于 作者: G Gloria

Update docs against 10031+12082

Signed-off-by: wusongqing<wusongqing@huawei.com>
上级 1eddd8d7
# Service Ability Development # Service Ability Development
## When to Use ## When to Use
A Service ability is used to run tasks in the background, such as playing music or downloading files. It does not provide a UI for user interaction. Service abilities can be started by other applications or abilities and can remain running in the background even after the user switches to another application. A Service ability is used to run tasks in the background, such as playing music or downloading files. It does not provide a UI for user interaction. Service abilities can be started by other applications or abilities and can keep running in the background even after the user switches to another application.
## Available APIs ## Lifecycle APIs
**Table 1** Service ability lifecycle APIs **Table 1** Service ability lifecycle APIs
|API|Description| |API|Description|
|:------|:------| |:------|:------|
|onStart?(): void|Called to initialize a Service ability being created. This callback is invoked only once in the entire lifecycle of a Service ability. The **Want** object passed to this callback must be null.| |onStart?(): void|Called to initialize a Service ability when the Service ability is being created. This callback is invoked only once in the entire lifecycle of a Service ability.|
|onCommand?(want: Want, startId: number): void|Called every time a Service ability is created on a client. You can collect calling statistics and perform initialization operations in this callback.| |onCommand?(want: Want, startId: number): void|Called every time a Service ability is created on the client. You can collect calling statistics and perform initialization operations in this callback.|
|onConnect?(want: Want): rpc.RemoteObject|Called when another ability is connected to the Service ability.| |onConnect?(want: Want): rpc.RemoteObject|Called when another ability is connected to the Service ability.|
|onDisconnect?(want: Want): void|Called when another ability is disconnected from the Service ability.| |onDisconnect?(want: Want): void|Called when another ability is disconnected from the Service ability.|
|onStop?(): void|Called when the Service ability is being destroyed. You should override this callback for your Service ability to clear its resources, such as threads and registered listeners.| |onStop?(): void|Called when the Service ability is being destroyed. You should override this callback for your Service ability to clear its resources, such as threads and registered listeners.|
The differences between **onCommand()** and **onConnect()** are as follows:
- The **onCommand()** callback is triggered each time the client starts the Service ability by calling **startAbility** or **startAbilityForResult**.
- The **onConnect()** callback is triggered each time the client establishes a new connection with the Service ability by calling **connectAbility**.
## How to Develop ## How to Develop
### Creating and Registering a Service Ability ### Creating and Registering a Service Ability
1. Override the Service ability-related lifecycle callbacks to implement your own logic for processing interaction requests. 1. Override the Service ability-related lifecycle callbacks to implement your own logic for processing interaction requests.
```javascript ```ts
export default { export default {
onStart() { onStart() {
console.log('ServiceAbility onStart'); console.log('ServiceAbility onStart');
...@@ -30,14 +34,15 @@ A Service ability is used to run tasks in the background, such as playing music ...@@ -30,14 +34,15 @@ A Service ability is used to run tasks in the background, such as playing music
}, },
onConnect(want) { onConnect(want) {
console.log('ServiceAbility OnConnect'); console.log('ServiceAbility OnConnect');
return new FirstServiceAbilityStub('test'); // Below lists the implementation of ServiceAbilityStub.
return new ServiceAbilityStub('test');
}, },
onDisconnect(want) { onDisconnect(want) {
console.log('ServiceAbility OnDisConnect'); console.log('ServiceAbility OnDisConnect');
}, },
onStop() { onStop() {
console.log('ServiceAbility onStop'); console.log('ServiceAbility onStop');
}, }
} }
``` ```
...@@ -45,7 +50,7 @@ A Service ability is used to run tasks in the background, such as playing music ...@@ -45,7 +50,7 @@ A Service ability is used to run tasks in the background, such as playing music
Declare the Service ability in the **config.json** file by setting its **type** attribute to **service**. Declare the Service ability in the **config.json** file by setting its **type** attribute to **service**.
```javascript ```json
{ {
"module": { "module": {
"abilities": [ "abilities": [
...@@ -68,245 +73,219 @@ A Service ability is used to run tasks in the background, such as playing music ...@@ -68,245 +73,219 @@ A Service ability is used to run tasks in the background, such as playing music
The **Ability** class provides the **startAbility()** API for you to start another Service ability by passing a **Want** object. The **Ability** class provides the **startAbility()** API for you to start another Service ability by passing a **Want** object.
To set information about the target Service ability, you can first construct a **Want** object with the **bundleName** and **abilityName** parameters specified. The meanings of the parameters are as follows: To set information about the target Service ability, you can first construct a **Want** object with the **bundleName** and **abilityName** parameters specified.
- **bundleName** indicates the name of the bundle to which the target ability belongs. - **bundleName** specifies the bundle name of the target application.
- **abilityName** indicates the target ability name. - **abilityName** specifies the target ability name.
The following code snippet shows how to start a Service ability running on the local device: The following code snippet shows how to start a Service ability running on the local device:
```javascript ```ts
import featureAbility from '@ohos.ability.featureAbility'; import featureAbility from '@ohos.ability.featureAbility'
let promise = featureAbility.startAbility(
featureAbility.startAbility(
{ {
want: want:
{ {
bundleName: "com.jstest.service", bundleName: "com.jstest.service",
abilityName: "com.jstest.service.ServiceAbility", abilityName: "com.jstest.service.ServiceAbility"
}, }
} }
); ).then((err) => {
console.log("startService success");
}).catch (err => {
console.log("startService FAILED");
});
``` ```
After the preceding code is executed, the **startAbility()** API is called to start the Service ability. In the preceding code, the **startAbility()** API is used to start the Service ability.
- If the Service ability is not running, the system calls **onStart()** to initialize the Service ability, and then calls **onCommand()** on the Service ability. - If the Service ability is not running, the system initializes the Service ability, and calls **onStart()** and **onCommand()** on the Service ability in sequence.
- If the Service ability is running, the system directly calls **onCommand()** on the Service ability. - If the Service ability is running, the system directly calls **onCommand()** on the Service ability.
The following code snippet shows how to start a Service ability running on the remote device. For details about **getRemoteDeviceId()**, see [Connecting to a Remote Service Ability](#connecting-to-a-remote-service-ability). The following code snippet shows how to start a Service ability running on the remote device. For details, see [Connecting to a Remote Service Ability](#connecting-to-a-remote-service-ability).
```javascript ```ts
import featureAbility from '@ohos.ability.featureAbility'; import featureAbility from '@ohos.ability.featureAbility'
let promise = featureAbility.startAbility(
featureAbility.startAbility(
{ {
want: want:
{ {
deviceId: getRemoteDeviceId(), // Remote device ID deviceId: remoteDeviceId, // Remote device ID.
bundleName: "com.jstest.service", bundleName: "com.jstest.service",
abilityName: "com.jstest.service.ServiceAbility", abilityName: "com.jstest.service.ServiceAbility"
}, }
} }
); ).then((err) => {
console.log("startService success");
}).catch (err => {
console.log("startService FAILED");
});
``` ```
### Stopping a Service Ability ### Stopping a Service Ability
Once created, the Service ability keeps running in the background. The system does not stop or destroy it unless memory resources must be reclaimed. In normal cases, a Service ability can be stopped by itself or by the system.
- The Service ability can call **particleAbility.terminateSelf()** to stop itself.
- If the application process where the Service ability is located exits, the Service ability is reclaimed along with the process.
- If the Service ability is only accessed through **connectAbility()** (the **onCommand()** callback has never been triggered), the system stops the Service ability when the last connection to the Service ability is disconnected.
### Connecting to a Local Service Ability ### Connecting to a Local Service Ability
If you need to connect a Service ability to a Page ability or to a Service ability in another application, you must first implement the **IAbilityConnection** API for the connection. A Service ability allows other abilities to connect to it through **connectAbility()**. If a Service ability wants to interact with a Page ability or a Service ability in another application, you must first create a connection. A Service ability allows other abilities to connect to it through **connectAbility()**.
You can use either of the following methods to connect to a Service ability: You can use either of the following methods to connect to a Service ability:
1. Using the IDL to automatically generate code 1. Using the IDL to automatically generate code
Use OpenHarmony Interface Definition Language (IDL) to automatically generate the corresponding client, server, and **IRemoteObject** code. For details, see “Development Using TS" in [OpenHarmony IDL Specifications and User Guide](../IDL/idl-guidelines.md). Use OpenHarmony Interface Definition Language (IDL) to automatically generate the corresponding client, server, and **IRemoteObject** code. For details, see [Development Using TS](../IDL/idl-guidelines.md#development-using-ts).
2. Writing code in the corresponding file 2. Writing code in the corresponding file
When calling **connectAbility()**, you should pass a **Want** object containing information about the target Service ability and an **IAbilityConnection** object to the API. **IAbilityConnection** provides the following callbacks that you should implement: **onConnect()**, **onDisconnect()**, and **onFailed()**. The **onConnect()** callback is invoked when a Service ability is connected, **onDisconnect()** is invoked when a Service ability is unexpectedly disconnected, and **onFailed()** is invoked when a connection to a Service ability fails. When using **connectAbility()**, pass the **Want** and **ConnectOptions** objects of the target Service ability, where **ConnectOptions** encapsulates the following three callbacks that need to be implemented.
- **onConnect()**: callback used for processing when the Service ability is connected.
- **onDisconnect()**: callback used for processing when the Service ability is disconnected.
- **onFailed()**: callback used for processing when the connection to the Service ability fails.
The following code snippet shows how to implement the callbacks: The following code snippet shows how to implement the callbacks:
```javascript ```ts
import prompt from '@system.prompt' import prompt from '@system.prompt'
var option = { var option = {
onConnect: function onConnectCallback(element, proxy) { onConnect: function onConnectCallback(element, proxy) {
console.log(`onConnectLocalService onConnectDone`) console.log(`onConnectLocalService onConnectDone`);
if (proxy === null) { if (proxy === null) {
prompt.showToast({ prompt.showToast({
message: "Connect service failed" message: "Connect service failed"
}) });
return return;
} }
let data = rpc.MessageParcel.create() // After obtaining the proxy of the Service ability, the calling ability can communicate with the Service ability.
let reply = rpc.MessageParcel.create() let data = rpc.MessageParcel.create();
let option = new rpc.MessageOption() let reply = rpc.MessageParcel.create();
data.writeInterfaceToken("connect.test.token") let option = new rpc.MessageOption();
proxy.sendRequest(0, data, reply, option) data.writeString("InuptString");
proxy.sendRequest(0, data, reply, option);
prompt.showToast({ prompt.showToast({
message: "Connect service success" message: "Connect service success"
}) });
}, },
onDisconnect: function onDisconnectCallback(element) { onDisconnect: function onDisconnectCallback(element) {
console.log(`onConnectLocalService onDisconnectDone element:${element}`) console.log(`onConnectLocalService onDisconnectDone element:${element}`);
prompt.showToast({ prompt.showToast({
message: "Disconnect service success" message: "Disconnect service success"
}) });
}, },
onFailed: function onFailedCallback(code) { onFailed: function onFailedCallback(code) {
console.log(`onConnectLocalService onFailed errCode:${code}`) console.log(`onConnectLocalService onFailed errCode:${code}`);
prompt.showToast({ prompt.showToast({
message: "Connect local service onFailed" message: "Connect local service onFailed"
}) });
}
} }
};
``` ```
The following code snippet shows how to connect to a local Service ability: The following code snippet shows how to connect to a local Service ability:
```javascript ```ts
import featureAbility from '@ohos.ability.featureAbility'; import featureAbility from '@ohos.ability.featureAbility'
let connId = featureAbility.connectAbility(
{ let want = {
bundleName: "com.jstest.service", bundleName: "com.jstest.service",
abilityName: "com.jstest.service.ServiceAbility", abilityName: "com.jstest.service.ServiceAbility"
}, };
{ let connectId = featureAbility.connectAbility(want, option);
onConnect: onConnectCallback,
onDisconnect: onDisconnectCallback,
onFailed: onFailedCallback,
},
);
``` ```
When a Service ability is connected, the **onConnect()** callback is invoked and returns an **IRemoteObject** defining the proxy used for communicating with the Service ability. OpenHarmony provides a default implementation of **IRemoteObject**. You can extend **rpc.RemoteObject** to implement your own class of **IRemoteObject**. When a Service ability is connected, the **onConnect()** callback is invoked and returns an **IRemoteObject** defining the proxy used for communicating with the Service ability. OpenHarmony provides the default implementation of **IRemoteObject**. You can inherit **rpc.RemoteObject** to create a custom implementation class for interaction with the Service ability. For details, see the [RPC API Reference](..\reference\apis\js-apis-rpc.md).
The following code snippet shows how the Service ability instance returns itself to the calling ability: The following code snippet shows how the Service ability returns itself to the calling ability:
```javascript ```ts
import rpc from "@ohos.rpc"; import rpc from "@ohos.rpc"
class FirstServiceAbilityStub extends rpc.RemoteObject { class ServiceAbilityStub extends rpc.RemoteObject {
constructor(des: any) { constructor(des: any) {
if (typeof des === 'string') { if (typeof des === 'string') {
super(des) super(des);
} else { } else {
return console.log("Error, the input param is not string");
return;
} }
} }
onRemoteRequest(code: number, data: any, reply: any, option: any) { onRemoteRequest(code: number, data: any, reply: any, option: any) {
console.log(printLog + ` onRemoteRequest called`) console.log("onRemoteRequest called");
// Execute the service logic.
if (code === 1) { if (code === 1) {
let string = data.readString() // Sort the input strings.
console.log(printLog + ` string=${string}`) let string = data.readString();
let result = Array.from(string).sort().join('') console.log(`Input string = ${string}`);
console.log(printLog + ` result=${result}`) let result = Array.from(string).sort().join('');
reply.writeString(result) console.log(`Output result = ${result}`);
reply.writeString(result);
} else { } else {
console.log(printLog + ` unknown request code`) console.log(`Unknown request code`);
} }
return true; return true;
} }
```
### Connecting to a Remote Service Ability
>**NOTE**
>
>This feature applies only to system applications, since the **getTrustedDeviceListSync** API of the **DeviceManager** class is open only to system applications.
If you need to connect a Service ability to a Page ability or another Service ability on a remote device, you must first implement the **IAbilityConnection** interface for the connection. A Service ability allows abilities on another device to connect to it through **connectAbility()**.
When calling **connectAbility()**, you should pass a **Want** object containing information about the target Service ability and an **IAbilityConnection** object to the API. **IAbilityConnection** provides the following callbacks that you should implement: **onConnect()**, **onDisconnect()**, and **onFailed()**. The **onConnect()** callback is invoked when a Service ability is connected, **onDisconnect()** is invoked when a Service ability is unexpectedly disconnected, and **onFailed()** is invoked when a connection to a Service ability fails.
The following code snippet shows how to implement the callbacks:
```ts
import prompt from '@system.prompt'
var option = {
onConnect: function onConnectCallback(element, proxy) {
console.log(`onConnectRemoteService onConnectDone`)
if (proxy === null) {
prompt.showToast({
message: "Connect service failed"
})
return
} }
let data = rpc.MessageParcel.create()
let reply = rpc.MessageParcel.create() export default {
let option = new rpc.MessageOption() onStart() {
data.writeInterfaceToken("connect.test.token") console.log('ServiceAbility onStart');
proxy.sendRequest(0, data, reply, option)
prompt.showToast({
message: "Connect service success"
})
}, },
onDisconnect: function onDisconnectCallback(element) { onCommand(want, startId) {
console.log(`onConnectRemoteService onDisconnectDone element:${element}`) console.log('ServiceAbility onCommand');
prompt.showToast({
message: "Disconnect service success"
})
}, },
onFailed: function onFailedCallback(code) { onConnect(want) {
console.log(`onConnectRemoteService onFailed errCode:${code}`) console.log('ServiceAbility OnConnect');
prompt.showToast({ return new ServiceAbilityStub('ServiceAbilityRemoteObject');
message: "Connect local service onFailed" },
}) onDisconnect(want) {
console.log('ServiceAbility OnDisConnect');
},
onStop() {
console.log('ServiceAbility onStop');
} }
} }
``` ```
The **Want** of the target Service ability must contain the remote **deviceId**, which can be obtained from **DeviceManager**. The sample code is as follows: ### Connecting to a Remote Service Ability
```ts This feature applies only to system applications. The method of creating a **ConnectOptions** object for connecting to a remote Service ability is similar to that for connecting to a local Service ability. The differences are as follows:
import deviceManager from '@ohos.distributedHardware.deviceManager'; - The application must apply for the data synchronization permission from the user.
- **Want** of the target Service ability must contain the remote device ID.
// For details about the implementation of dmClass, see the implementation in Distributed Demo in Samples. > **NOTE**
let dmClass; >
> The **getTrustedDeviceList** API of **DeviceManager** is open only to system applications. Currently, only system applications can connect to a remote Service ability.
>
> For details about the API definition, see [Device Management](..\reference\apis\js-apis-device-manager.md).
function getRemoteDeviceId() { The data synchronization permission is required in the cross-device scenario. Configure the permission in the **config.json** file.
if (typeof dmClass === 'object' && dmClass != null) {
let list = dmClass.getTrustedDeviceListSync(); ```json
if (typeof (list) == 'undefined' || typeof (list.length) == 'undefined') { {
console.log("MainAbility onButtonClick getRemoteDeviceId err: list is null"); ...
return; "module": {
} ...
console.log("MainAbility onButtonClick getRemoteDeviceId success:" + list[0].deviceId); "reqPermissions": [{
return list[0].deviceId; "name": "ohos.permission.DISTRIBUTED_DATASYNC"
} else { }]
console.log("MainAbility onButtonClick getRemoteDeviceId err: dmClass is null");
} }
} }
``` ```
The following code snippet shows how to connect to a remote Service ability: The **DISTRIBUTED_DATASYNC** permission is user granted. Therefore, your application, when being started, must display a dialog box to request the permission. The sample code is as follows:
```ts ```ts
import featureAbility from '@ohos.ability.featureAbility'; import abilityAccessCtrl from "@ohos.abilityAccessCtrl"
let connId = featureAbility.connectAbility( import bundle from '@ohos.bundle'
{
deviceId: getRemoteDeviceId(),
bundleName: "ohos.samples.etsDemo",
abilityName: "ohos.samples.etsDemo.ServiceAbility",
},
{
onConnect: onConnectCallback,
onDisconnect: onDisconnectCallback,
onFailed: onFailedCallback,
},
);
```
In the cross-device scenario, the application must also apply for the data synchronization permission from end users. The sample code is as follows:
```ts
import abilityAccessCtrl from "@ohos.abilityAccessCtrl";
import bundle from '@ohos.bundle';
async function RequestPermission() { async function RequestPermission() {
console.info('RequestPermission begin'); console.info('RequestPermission begin');
let array: Array<string> = ["ohos.permission.DISTRIBUTED_DATASYNC"]; let array: Array<string> = ["ohos.permission.DISTRIBUTED_DATASYNC"];
...@@ -320,8 +299,7 @@ async function RequestPermission() { ...@@ -320,8 +299,7 @@ async function RequestPermission() {
for (let i = 0;i < array.length; i++) { for (let i = 0;i < array.length; i++) {
let result = await atManager.verifyAccessToken(tokenID, array[i]); let result = await atManager.verifyAccessToken(tokenID, array[i]);
console.info("verifyAccessToken result:" + JSON.stringify(result)); console.info("verifyAccessToken result:" + JSON.stringify(result));
if (result == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { if (result != abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
} else {
requestPermissions.push(array[i]); requestPermissions.push(array[i]);
} }
} }
...@@ -337,64 +315,19 @@ async function RequestPermission() { ...@@ -337,64 +315,19 @@ async function RequestPermission() {
} }
``` ```
When a Service ability is connected, the **onConnect()** callback is invoked and returns an **IRemoteObject** defining the proxy used for communicating with the Service ability. OpenHarmony provides a default implementation of **IRemoteObject**. You can extend **rpc.RemoteObject** to implement your own class of **IRemoteObject**. To obtain the device ID, import the **@ohos.distributedHardware.deviceManager** module, which provides **getTrustedDeviceList** to obtain the remote device ID. For details about how to use the API, see [Device Management](..\reference\apis\js-apis-device-manager.md).
The following code snippet shows how the Service ability instance returns itself to the calling ability: To connect to a remote Service ability, you only need to define **deviceId** in **Want**. The sample code is as follows:
```ts ```ts
import rpc from "@ohos.rpc"; import featureAbility from '@ohos.ability.featureAbility'
class FirstServiceAbilityStub extends rpc.RemoteObject { let want = {
constructor(des: any) { deviceId: remoteDeviceId,
if (typeof des === 'string') { bundleName: "com.jstest.service",
super(des) abilityName: "com.jstest.service.ServiceAbility"
} else {
return
}
}
onRemoteRequest(code: number, data: any, reply: any, option: any) {
console.log(printLog + ` onRemoteRequest called`)
if (code === 1) {
let string = data.readString()
console.log(printLog + ` string=${string}`)
let result = Array.from(string).sort().join('')
console.log(printLog + ` result=${result}`)
reply.writeString(result)
} else {
console.log(printLog + ` unknown request code`)
}
return true;
}
}
export default {
onStart() {
console.info('ServiceAbility onStart');
},
onStop() {
console.info('ServiceAbility onStop');
},
onConnect(want) {
console.log("ServiceAbility onConnect");
try {
let value = JSON.stringify(want);
console.log("ServiceAbility want:" + value);
} catch(error) {
console.log("ServiceAbility error:" + error);
}
return new FirstServiceAbilityStub("first ts service stub");
},
onDisconnect(want) {
console.log("ServiceAbility onDisconnect");
let value = JSON.stringify(want);
console.log("ServiceAbility want:" + value);
},
onCommand(want, startId) {
console.info('ServiceAbility onCommand');
let value = JSON.stringify(want);
console.log("ServiceAbility want:" + value);
console.log("ServiceAbility startId:" + startId);
}
}; };
let connectId = featureAbility.connectAbility(want, option);
``` ```
The other implementations are the same as those for the connection to a local Service ability. For details, see the sample code provided under [Connecting to a Local Service Ability](#connecting-to-a-local-service-ability).
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册