提交 417ae4c3 编写于 作者: H HuangXW

FA_ServiceAbility文档优化

Signed-off-by: NHuangXW <huangxinwei4@huawei.com>
上级 3a1e4d85
...@@ -3,17 +3,21 @@ ...@@ -3,17 +3,21 @@
## 场景介绍 ## 场景介绍
基于Service模板的Ability(以下简称“Service”)主要用于后台运行任务(如执行音乐播放、文件下载等),但不提供用户交互界面。Service可由其他应用或Ability启动。即使用户切换到其他应用,Service仍将在后台继续运行。 基于Service模板的Ability(以下简称“Service”)主要用于后台运行任务(如执行音乐播放、文件下载等),但不提供用户交互界面。Service可由其他应用或Ability启动。即使用户切换到其他应用,Service仍将在后台继续运行。
## 接口说明 ## 生命周期
**表1** Service中相关生命周期API功能介绍 **表1** Service中相关生命周期API功能介绍
|接口名|描述| |接口名|描述|
|:------|:------| |:------|:------|
|onStart?(): void|该方法在创建Service的时候调用,用于Service的初始化。在Service的整个生命周期只会调用一次,调用时传入的Want应为空。| |onStart?(): void|该方法在创建Service的时候调用,用于Service的初始化,在Service的整个生命周期只会调用一次。|
|onCommand?(want: Want, startId: number): void|在Service创建完成之后调用,该方法在客户端每次启动该Service时都会调用,开发者可以在该方法中做一些调用统计、初始化类的操作。| |onCommand?(want: Want, startId: number): void|在Service创建完成之后调用,该方法在客户端每次启动该Service时都会调用,开发者可以在该方法中做一些调用统计、初始化类的操作。|
|onConnect?(want: Want): rpc.RemoteObject|在Ability和Service连接时调用。| |onConnect?(want: Want): rpc.RemoteObject|在Ability和Service连接时调用。|
|onDisconnect?(want: Want): void|在Ability与绑定的Service断开连接时调用。| |onDisconnect?(want: Want): void|在Ability与绑定的Service断开连接时调用。|
|onStop?(): void|在Service销毁时调用。开发者应通过实现此方法来清理资源,如关闭线程、注册的侦听器等。| |onStop?(): void|在Service销毁时调用。开发者应通过实现此方法来清理资源,如关闭线程、注册的侦听器等。|
onCommand()与onConnect()的区别在于:
- onCommand()只能被startAbility或startAbilityForResult触发,客户端每次启动Service均会触发该回调
- onConnect()只能被connectAbility触发,客户端每次与Servcie建立新的连接时会触发该回调
## 开发步骤 ## 开发步骤
### 创建注册Service ### 创建注册Service
...@@ -22,7 +26,7 @@ ...@@ -22,7 +26,7 @@
创建Service的代码示例如下: 创建Service的代码示例如下:
```javascript ```ts
export default { export default {
onStart() { onStart() {
console.log('ServiceAbility onStart'); console.log('ServiceAbility onStart');
...@@ -32,14 +36,15 @@ ...@@ -32,14 +36,15 @@
}, },
onConnect(want) { onConnect(want) {
console.log('ServiceAbility OnConnect'); console.log('ServiceAbility OnConnect');
return new FirstServiceAbilityStub('test'); // 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');
}, }
} }
``` ```
...@@ -47,7 +52,7 @@ ...@@ -47,7 +52,7 @@
Service需要在应用配置文件config.json中进行注册,注册类型type需要设置为service。 Service需要在应用配置文件config.json中进行注册,注册类型type需要设置为service。
```javascript ```json
{ {
"module": { "module": {
"abilities": [ "abilities": [
...@@ -72,50 +77,61 @@ Ability为开发者提供了startAbility()方法来启动另外一个Ability。 ...@@ -72,50 +77,61 @@ Ability为开发者提供了startAbility()方法来启动另外一个Ability。
开发者可以通过构造包含bundleName与abilityName的Want对象来设置目标Service信息。参数的含义如下: 开发者可以通过构造包含bundleName与abilityName的Want对象来设置目标Service信息。参数的含义如下:
- bundleName:表示包名称。 - bundleName:表示对端应用的包名称。
- abilityName:表示待启动的Ability名称。 - abilityName:表示待启动的Ability名称。
启动本地设备Service的代码示例如下: 启动本地设备Service的代码示例如下:
```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");
});
``` ```
执行上述代码后,Ability将通过startAbility() 方法来启动Service。 执行上述代码后,Ability将通过startAbility() 方法来启动Service。
- 如果Service尚未运行,则系统会先调用onStart()来初始化Service,再回调Service的onCommand()方法来启动Service - 如果Service尚未运行,则系统会先初始化Service,然后回调onStart()来启动Service,再回调onCommand()方法
- 如果Service正在运行,则系统会直接回调Service的onCommand()方法来启动Service - 如果Service正在运行,则系统会直接回调Service的onCommand()方法。
启动远端设备Service的代码示例如下,getRemoteDeviceId()方法详见[连接远程Service](#连接远程service当前仅对系统应用开放) 启动远端设备Service的代码示例如下,详见[连接远程Service](fa-serviceability.md#连接远程service当前仅对系统应用开放)
```javascript ```ts
import featureAbility from '@ohos.ability.featureAbility'; import featureAbility from '@ohos.ability.featureAbility'
let promise = featureAbility.startAbility(
featureAbility.startAbility(
{ {
want: want:
{ {
deviceId: getRemoteDeviceId(), //远端设备Id deviceId: remoteDeviceId, // 远端设备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");
});
``` ```
### 停止Service ### 停止Service
Service一旦创建就会一直保持在后台运行,除非必须回收内存资源,否则系统不会停止或销毁Service。 常规情况下,Service可以将自己停止,或者被系统停止,具体场景如下:
- Service调用particleAbility.terminateSelf()方法将自己停止。
- Service所在的应用进程退出,Service将随着进程被回收。
- 若Service仅仅是通过connectAbility()方法被访问的(从未执行过onCommand()回调),那么当最后一个连接被断开后,系统会将Service停止。
### 连接本地Service ### 连接本地Service
...@@ -128,189 +144,151 @@ let promise = featureAbility.startAbility( ...@@ -128,189 +144,151 @@ let promise = featureAbility.startAbility(
使用OpenHarmony IDL(OpenHarmony Interface Definition Language)来自动生成对应客户端服务端及IRemoteObject代码,具体示例代码和说明请参考: 使用OpenHarmony IDL(OpenHarmony Interface Definition Language)来自动生成对应客户端服务端及IRemoteObject代码,具体示例代码和说明请参考:
- [`OpenHarmony IDL`:TS开发步骤](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/IDL/idl-guidelines.md#ts%E5%BC%80%E5%8F%91%E6%AD%A5%E9%AA%A4) - [`OpenHarmony IDL`:TS开发步骤](../IDL/idl-guidelines.md#ts)
2. 在对应文件编写代码 2. 在对应文件编写代码
在使用connectAbility()处理回调时,需要传入目标Service的Want与IAbilityConnection的实例。IAbilityConnection提供了以下方法供开发者实现:onConnect()是用来处理连接Service成功的回调,onDisconnect()是用来处理Service异常死亡的回调,onFailed()是用来处理连接Service失败的回调。 在使用connectAbility()时,需要传入目标Service的Want与ConnectOptions的实例,其中ConnectOptions封装了三个回调,分别对应不同情况,开发者需自行实现:
- onConnect():用来处理连接Service成功的回调。
- onDisconnect():用来处理Service断连或异常死亡的回调。
- onFailed():用来处理连接Service失败的回调。
创建连接本地Service回调实例的代码示例如下: 创建连接本地Service回调实例的代码示例如下:
```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() // 得到Service的proxy对象后便可以与其进行通信
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"
}) });
}
} }
};
``` ```
连接本地Service的代码示例如下: 连接本地Service的代码示例如下:
```javascript ```ts
import featureAbility from '@ohos.ability.featureAbility'; import featureAbility from '@ohos.ability.featureAbility'
let connectId = 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,
},
);
``` ```
同时,Service侧也需要在onConnect()时返回IRemoteObject,从而定义与Service进行通信的接口。onConnect()需要返回一个IRemoteObject对象。OpenHarmony提供了IRemoteObject的默认实现,开发者可以通过继承rpc.RemoteObject来创建自定义的实现类。 同时,Service侧也需要在onConnect()时返回IRemoteObject,从而定义与Service进行通信的接口。onConnect()需要返回一个IRemoteObject对象。OpenHarmony提供了IRemoteObject的默认实现,开发者可以通过继承rpc.RemoteObject来创建自定义的实现类,从而实现与Service的通信。具体使用方法可参考[ohos.rpc API文档](..\reference\apis\js-apis-rpc.md)
Service侧把自身的实例返回给调用侧的代码示例如下: Service侧把自身的实例返回给调用侧的代码示例如下:
```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");
// 可根据code执行不同的业务逻辑
if (code === 1) { if (code === 1) {
let string = data.readString() // 将传入的字符串进行排序
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;
} }
```
### 连接远程Service(当前仅对系统应用开放)
>说明:由于DeviceManager的getTrustedDeviceListSync接口仅对系统应用开放,当前连接远程Service仅支持系统应用。
如果Service需要与Page Ability或其他应用的Service Ability进行跨设备交互,则须创建用于连接的Connection。Service支持其他Ability通过connectAbility()方法与其进行跨设备连接。
在使用connectAbility()处理回调时,需要传入目标Service的Want与IAbilityConnection的实例。IAbilityConnection提供了以下方法供开发者实现:onConnect()是用来处理连接Service成功的回调,onDisconnect()是用来处理Service异常死亡的回调,onFailed()是用来处理连接Service失败的回调。
创建连接远程Service回调实例的代码示例如下:
```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');
} }
} }
``` ```
目标Service的Want需要包含远程deviceId,该远程deviceId可通过deviceManager获取,具体示例代码如下: ### 连接远程Service(当前仅对系统应用开放)
```ts 连接远程Service,构造ConnectOptions的方法与连接本地Serivce相同,区别在于:
import deviceManager from '@ohos.distributedHardware.deviceManager'; - 应用需要向用户申请数据同步权限
- 目标Service的Want需要包含对端设备的deviceId
//dmClass具体实现请参考:相关实例 分布式Demo 章节中的实现 > 说明:
let dmClass; > (1) 由于DeviceManager的getTrustedDeviceList等接口仅对系统应用开放,当前仅系统应用支持连接远程Service。
> (2) API定义可见:[deviceManager模块](..\reference\apis\js-apis-device-manager.md)
> (3) 参考Demo可见:[分布式Demo](https://gitee.com/openharmony/applications_app_samples/tree/master/ability/DMS)
function getRemoteDeviceId() { 在跨设备场景下,需要向用户申请数据同步的权限,首先在config.json里配置权限:
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");
} }
} }
``` ```
连接远程Service的代码示例如下: DISTRIBUTED_DATASYNC权限需要用户授予,在应用启动时需要向用户弹框请求授予权限,示例代码如下:
```ts ```ts
import featureAbility from '@ohos.ability.featureAbility'; import abilityAccessCtrl from "@ohos.abilityAccessCtrl"
let connectId = featureAbility.connectAbility( import bundle from '@ohos.bundle'
{
deviceId: getRemoteDeviceId(),
bundleName: "ohos.samples.etsDemo",
abilityName: "ohos.samples.etsDemo.ServiceAbility",
},
{
onConnect: onConnectCallback,
onDisconnect: onDisconnectCallback,
onFailed: onFailedCallback,
},
);
```
在跨设备场景下,需要向用户申请数据同步的权限。具体示例代码如下:
```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"];
...@@ -324,8 +302,7 @@ async function RequestPermission() { ...@@ -324,8 +302,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]);
} }
} }
...@@ -341,68 +318,25 @@ async function RequestPermission() { ...@@ -341,68 +318,25 @@ async function RequestPermission() {
} }
``` ```
同时,Service侧也需要在onConnect()时返回IRemoteObject,从而定义与Service进行通信的接口。onConnect()需要返回一个IRemoteObject对象。OpenHarmony提供了IRemoteObject的默认实现,开发者可以通过继承rpc.RemoteObject来创建自定义的实现类。 获取deviceId需要导入`@ohos.distributedHardware.deviceManager`模块,其中提供了getTrustedDeviceList等接口用于获取远端设备的deviceId。
- 接口使用可参考[deviceManager模块](..\reference\apis\js-apis-device-manager.md)
- 具体实现可参考[分布式Demo](https://gitee.com/openharmony/applications_app_samples/tree/master/ability/DMS)
Service侧把自身的实例返回给调用侧的代码示例如下: 连接远程Service,只需要在want内定义deviceId即可,示例代码如下:
```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);
``` ```
其余实现均与本地连接Service相同,参考[连接本地Service](fa-serviceability.md#连接本地service)的示例代码即可。
## 相关实例 ## 相关实例
针对ServiceAbility开发,有以下相关实例可供参考: 针对ServiceAbility开发,有以下相关实例可供参考:
......
...@@ -17,7 +17,7 @@ ExtensionContext模块提供访问特定Extension的资源的能力,对于拓 ...@@ -17,7 +17,7 @@ ExtensionContext模块提供访问特定Extension的资源的能力,对于拓
| -------- | -------- | -------- | -------- | -------- | | -------- | -------- | -------- | -------- | -------- |
| currentHapModuleInfo | HapModuleInfo | 是 | 否 | 所属Hap包的信息。<br>(详见SDK目录下的 `api\bundle\hapModuleInfo.d.ts`) | | currentHapModuleInfo | HapModuleInfo | 是 | 否 | 所属Hap包的信息。<br>(详见SDK目录下的 `api\bundle\hapModuleInfo.d.ts`) |
| config | Configuration | 是 | 否 | 所属Module的配置信息。<br>(详见SDK目录下的 `api\@ohos.application.Configuration.d.ts`) | | config | Configuration | 是 | 否 | 所属Module的配置信息。<br>(详见SDK目录下的 `api\@ohos.application.Configuration.d.ts`) |
| extensionAbilityInfo | [ExtensionAbilityInfo](js-apis-bundle-ExtensionAbilityInfo.md) | 是 | 否 | 所属Extension的信息。<br>(详见SDK目录下的 `api\bundle\extensionAbilityInfo.d.ts`) | | extensionAbilityInfo | [ExtensionAbilityInfo](js-apis-bundleManager-extensionAbilityInfo.md) | 是 | 否 | 所属Extension的信息。<br>(详见SDK目录下的 `api\bundle\extensionAbilityInfo.d.ts`) |
## 使用场景 ## 使用场景
ExtensionContext主要用于查询所属Extension的信息、Module的配置信息以及Hap包的信息,开发者可根据自身业务需求使用对应的信息。此处以ServiceExtension为例,展示ExtensionContext的一种使用场景。 ExtensionContext主要用于查询所属Extension的信息、Module的配置信息以及Hap包的信息,开发者可根据自身业务需求使用对应的信息。此处以ServiceExtension为例,展示ExtensionContext的一种使用场景。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册