OpenHarmony应用开发-ExtensionAbility组件
版本:v3.2 Beta5
ExtensionAbility组件概述
ExtensionAbility组件是基于特定场景(例如服务卡片、输入法等)提供的应用组件,以便满足更多的使用场景。
每一个具体场景对应一个ExtensionAbilityType,各类型的ExtensionAbility组件均由相应的系统服务统一管理,例如InputMethodExtensionAbility组件由输入法管理服务统一管理。当前支持的ExtensionAbility类型有:
- FormExtensionAbility:FORM类型的ExtensionAbility组件,用于提供服务卡片场景相关能力。
- WorkSchedulerExtensionAbility:WORK_SCHEDULER类型的ExtensionAbility组件,用于提供延迟任务注册、取消、查询的能力。
- InputMethodExtensionAbility:INPUT_METHOD类型的ExtensionAbility组件,提供对输入法框架的管理,包括隐藏输入法、查询已安装的输入法列表和显示输入法选择对话框。
- ServiceExtensionAbility:SERVICE类型的ExtensionAbility组件,用于提供后台服务场景相关能力。
- AccessibilityExtensionAbility:ACCESSIBILITY类型的ExtensionAbility组件,用于提供辅助功能业务的能力。
- DataShareExtensionAbility:DATA_SHARE类型的ExtensionAbility组件,用于提供支持数据共享业务的能力。
- StaticSubscriberExtensionAbility:STATIC_SUBSCRIBER类型的ExtensionAbility组件,用于提供静态广播的能力。
- WindowExtensionAbility:WINDOW类型的ExtensionAbility组件,用于提供界面组合扩展能力,允许系统应用进行跨应用的界面拉起和嵌入。
- EnterpriseAdminExtensionAbility:ENTERPRISE_ADMIN类型的ExtensionAbility组件,用于提供企业管理时处理管理事件的能力,比如设备上应用安装事件、锁屏密码输入错误次数过多事件等。
说明:
- OpenHarmony不支持三方应用实现ServiceExtensionAbility、DataShareExtensionAbility、StaticSubscriberExtensionAbility和WindowExtensionAbility。
- 如果三方开发者想要实现后台处理相关事务的功能,无法使用ServiceExtensionAbility,可以使用后台任务,具体请参见后台任务。
- 三方应用只能使用当前系统已定义的上述类型的ExtensionAbility。
使用指定类型的ExtensionAbility组件
所有类型的ExtensionAbility组件均不能被应用直接启动,而是由相应的系统管理服务拉起,以确保其生命周期受系统管控,使用时拉起,使用完销毁。ExtensionAbility组件的调用方无需关心目标ExtensionAbility组件的生命周期。
以InputMethodExtensionAbility组件为例进行说明,如下图所示,调用方应用发起对InputMethodExtensionAbility组件的调用,此时将先调用输入法管理服务,由输入法管理服务拉起InputMethodExtensionAbility组件,返回给调用方,同时开始管理其生命周期。
图1 使用InputMethodExtensionAbility组件
实现指定类型的ExtensionAbility组件
以实现卡片FormExtensionAbility为例进行说明。卡片框架提供了FormExtensionAbility基类,开发者通过派生此基类(如MyFormExtensionAbility),实现回调(如创建卡片的onCreate()回调、更新卡片的onUpdateForm()回调等)来实现具体卡片功能,具体见开发指导见服务卡片FormExtensionAbility。
卡片FormExtensionAbility实现方不用关心使用方何时去请求添加、删除卡片,FormExtensionAbility实例及其所在的ExtensionAbility进程的整个生命周期,都是由卡片管理系统服务FormManagerService进行调度管理。
说明: 同一应用内的所有同类型的ExtensionAbility运行在同一独立进程(除ServiceExtensionAbility、DataShareExtensionAbility外),跟UIAbility组件不在同一进程,Stage模型的进程模型请参见进程模型。
例如一个应用有1个UIAbility组件、1个ServiceExtensionAbility、1个DataShareExtensionAbility、2个FormExtensionAbility、1个ImeExtensionAbility。则该应用在运行时,有三个进程:
- UIAbility、ServiceExtensionAbility、DataShareExtensionAbility运行在同一个进程。
- FormExtensionAbility运行在一个独立进程。
- ImeExtensionAbility运行在一个独立进程。
ServiceExtensionAbility
ServiceExtensionAbility是SERVICE类型的ExtensionAbility组件,提供后台服务相关扩展能力。
ServiceExtensionAbility可以被其他组件启动或连接,并根据调用者的请求信息在后台处理相关事务。ServiceExtensionAbility支持以启动和连接两种形式运行,系统应用可以调用startServiceExtensionAbility()方法启动后台服务,也可以调用connectServiceExtensionAbility()方法连接后台服务,而三方应用只能调用connectServiceExtensionAbility()方法连接后台服务。启动和连接后台服务的差别:
- 启动:AbilityA启动ServiceB,启动后AbilityA和ServiceB为弱关联,AbilityA退出后,ServiceB可以继续存在。
- 连接:AbilityA绑定ServiceB,绑定后AbilityA和ServiceB为强关联,AbilityA退出后,ServiceB也一起退出。
每个类型的ExtensionAbility都有自己的Context,ServiceExtensionAbility通过ServiceExtensionContext提供相关能力。本文描述中称被启动的ServiceExtensionAbility为服务端,称启动ServiceExtensionAbility的组件为客户端。
本章节将从如下场景来介绍ServiceExtensionAbility的基本使用。
说明:
- OpenHarmony当前不支持三方应用实现ServiceExtensionAbility。如果三方开发者想要实现后台处理相关事务的功能,可以使用后台任务,具体请参见后台任务。
- 三方应用的UIAbility组件可以通过Context连接系统提供的ServiceExtensionAbility。
- 三方应用需要在前台获焦的情况下才能连接系统提供的ServiceExtensionAbility。
实现一个后台服务(仅对系统应用开放)
ServiceExtensionAbility提供了onCreate()、onRequest()、onConnect()、onDisconnect()和onDestory()生命周期回调,根据需要重写对应的回调方法。下图展示了ServiceExtensionAbility的生命周期。
图1 ServiceExtensionAbility生命周期
- onCreate服务被首次创建时触发该回调,开发者可以在此进行一些初始化的操作,例如注册公共事件监听等。
说明:
如果服务已创建,再次启动该ServiceExtensionAbility不会触发onCreate()回调。
- onRequest当另一个组件调用startServiceExtensionAbility()方法启动该服务组件时,触发该回调。执行此方法后,服务会启动并在后台运行。
- onConnect当另一个组件调用connectServiceExtensionAbility()方法与该服务连接时,触发该回调。开发者在此方法中,返回一个远端代理对象(IRemoteObject),客户端拿到这个对象后可以通过这个对象与服务端进行RPC通信。
- onDisconnect其他组件调用disconnectServiceExtensionAbility()方法时,如果没有任何其他组件连接该服务,触发该回调。
- onDestroy当不再使用服务且准备将其销毁该实例时,触发该回调。开发者可以在该回调中清理资源,如注销监听等。
开发步骤
开发者在实现一个后台服务时,需要在DevEco Studio工程中手动新建一个ServiceExtensionAbility,具体步骤如下。
- 在工程Module对应的ets目录下,右键选择“New > Directory”,新建一个目录并命名为serviceextability。
- 在serviceextability目录,右键选择“New > ts File”,新建一个TS文件并命名为ServiceExtAbility.ts。
- 打开ServiceExtAbility.ts文件,导入RPC通信模块,重载onRemoteMessageRequest()方法,接收客户端传递过来的消息,并将处理的结果返回给客户端。REQUEST_VALUE用于校验客户端发送的服务请求码。
import rpc from '@ohos.rpc';
const REQUEST_CODE = 99;
class StubTest extends rpc.RemoteObject {
constructor(des) {
super(des);
}
// 接收客户端传递过来的消息处理,以及将处理的结果返回给客户端
onRemoteMessageRequest(code, data, reply, option) {
if (code === REQUEST_CODE) {
// 接收客户端传递过来的数据
// 客户端使用多次调用data.writeInt()写入多个数据时,服务端可以通过多次调用data.readInt()方法接收对应的数据
let optFir = data.readInt();
let optSec = data.readInt();
// 服务端将数据的处理结果返回给客户端
// 示例中为接收了两个数据,并将两个数据的求和返回给客户端
reply.writeInt(optFir + optSec);
}
return true;
}
// 以同步或异步方式向客户端发送消息
sendRequest(code, data, reply, options) {
return null;
}
}
- 在ServiceExtAbility.ts文件中,增加导入ServiceExtensionAbility的依赖包,自定义类继承ServiceExtensionAbility并加上需要的生命周期回调。
import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility';
import rpc from '@ohos.rpc';
const TAG: string = "[Example].[Entry].[ServiceExtAbility]";
const REQUEST_CODE = 99;
class StubTest extends rpc.RemoteObject {
// ...
}
export default class ServiceExtAbility extends ServiceExtensionAbility {
onCreate(want) {
console.info(TAG, `onCreate, want: ${want.abilityName}`);
}
onRequest(want, startId) {
console.info(TAG, `onRequest, want: ${want.abilityName}`);
}
onConnect(want) {
console.info(TAG, `onConnect, want: ${want.abilityName}`);
return new StubTest("test");
}
onDisconnect(want) {
console.info(TAG, `onDisconnect, want: ${want.abilityName}`);
}
onDestroy() {
console.info(TAG, `onDestroy`);
}
}
- 在工程Module对应的module.json5配置文件中注册ServiceExtensionAbility,type标签需要设置为“service”,srcEntrance标签表示当前ExtensionAbility组件所对应的代码路径。
{
"module": {
// ...
"extensionAbilities": [
{
"name": "ServiceExtAbility",
"icon": "$media:icon",
"description": "service",
"type": "service",
"visible": true,
"srcEntrance": "./ets/serviceextability/ServiceExtAbility.ts"
}
]
}
}
启动一个后台服务(仅对系统应用开放)
系统应用通过startServiceExtensionAbility()方法启动一个后台服务,服务的onRequest()回调就会被调用,并在该回调方法中接收到调用者传递过来的want对象。后台服务启动后,其生命周期独立于客户端,即使客户端已经销毁,该后台服务仍可继续运行。因此,后台服务需要在其工作完成时通过调用ServiceExtensionContext的terminateSelf()来自行停止,或者由另一个组件调用stopServiceExtensionAbility()来将其停止。
说明: ServiceExtensionContext的startServiceExtensionAbility()、stopServiceExtensionAbility()和terminateSelf()为系统接口,三方应用不支持调用。
- 在系统应用中启动一个新的ServiceExtensionAbility。示例中的context的获取方式参见获取UIAbility的Context属性。
let want = {
"deviceId": "",
"bundleName": "com.example.myapplication",
"abilityName": "ServiceExtAbility"
};
this.context.startServiceExtensionAbility(want).then(() => {
console.info('startServiceExtensionAbility success');
}).catch((error) => {
console.info('startServiceExtensionAbility failed');
})
- 在系统应用中停止一个已启动的ServiceExtensionAbility。
let want = {
"deviceId": "",
"bundleName": "com.example.myapplication",
"abilityName": "ServiceExtAbility"
};
this.context.stopServiceExtensionAbility(want).then(() => {
console.info('stopServiceExtensionAbility success');
}).catch((error) => {
console.info('stopServiceExtensionAbility failed');
})
- 已启动的ServiceExtensionAbility停止自身。
// this是当前ServiceExtensionAbility
this.context.terminateSelf().then(() => {
console.info('terminateSelf success');
}).catch((error) => {
console.info('terminateSelf failed');
})
说明: 后台服务可以在后台长期运行,为了避免资源浪费,需要对后台服务的生命周期进行管理。即一个后台服务完成了请求方的任务,需要及时销毁。销毁已启动的后台服务有两种方式:
- 后台服务自身调用terminateSelf()方法来自行停止。
- 由其他组件调用stopServiceExtensionAbility()方法来停止。
调用terminateSelf()或stopServiceExtensionAbility()方法之后,系统将销毁后台服务。
连接一个后台服务
系统应用或者三方应用可以通过connectServiceExtensionAbility()连接一个服务(在Want对象中指定启动的目标服务),服务的onConnect()就会被调用,并在该回调方法中接收到调用者传递过来的Want对象,从而建立长连接。
ServiceExtensionAbility服务组件在onConnect()中返回IRemoteObject对象,开发者通过该IRemoteObject定义通信接口,用于客户端与服务端进行RPC交互。多个客户端可以同时连接到同一个后台服务,客户端完成与服务的交互后,客户端需要通过调用disconnectServiceExtensionAbility()来断开连接。如果所有连接到某个后台服务的客户端均已断开连接,则系统会销毁该服务。
- 使用connectServiceExtensionAbility()建立与后台服务的连接。示例中的context的获取方式参见获取UIAbility的Context属性。
import rpc from '@ohos.rpc';
const REQUEST_CODE = 99;
let want = {
"deviceId": "",
"bundleName": "com.example.myapplication",
"abilityName": "ServiceExtAbility"
};
let options = {
onConnect(elementName, remote) {
console.info('onConnect callback');
if (remote === null) {
console.info(`onConnect remote is null`);
return;
}
let option = new rpc.MessageOption();
let data = new rpc.MessageParcel();
let reply = new rpc.MessageParcel();
data.writeInt(100);
data.writeInt(200);
// @param code 表示客户端发送的服务请求代码。
// @param data 表示客户端发送的{@link MessageParcel}对象。
// @param reply 表示远程服务发送的响应消息对象。
// @param options 指示操作是同步的还是异步的。
//
// @return 如果操作成功返回{@code true}; 否则返回 {@code false}。
remote.sendRequest(REQUEST_CODE, data, reply, option).then((ret) => {
let msg = reply.readInt();
console.info(`sendRequest ret:${ret} msg:${msg}`);
}).catch((error) => {
console.info('sendRequest failed');
});
},
onDisconnect(elementName) {
console.info('onDisconnect callback')
},
onFailed(code) {
console.info('onFailed callback')
}
}
// 建立连接后返回的Id需要保存下来,在解绑服务时需要作为参数传入
let connectionId = this.context.connectServiceExtensionAbility(want, options);
- 使用disconnectServiceExtensionAbility()断开与后台服务的连接。
let connectionId = 1 // 在通过connectServiceExtensionAbility绑定服务时返回的Id
this.context.disconnectServiceExtensionAbility(connectionId).then((data) => {
console.info('disconnectServiceExtensionAbility success');
}).catch((error) => {
console.error('disconnectServiceExtensionAbility failed');
})
相关示例
针对ServiceExtensionAbility开发,有以下相关示例可供参考:
DataShareExtensionAbility(仅对系统应用开放)
DataShareExtensionAbility提供了数据分享的能力,系统应用可以实现一个DataShareExtensionAbility,也可以访问系统中已有的DataShareExtensionAbility,针对三方应用仅开放访问系统中已有DataShareExtensionAbility的能力,详细介绍请参见数据共享开发指导。
EnterpriseAdminExtensionAbility开发指南
EnterpriseAdminExtensionAbility简介
企业设备管理扩展能力,是MDM应用必备组件。当开发者为企业开发MDM(Mobile Device Management)应用时,需继承EnterpriseAdminExtensionAbility,在EnterpriseAdminExtensionAbility实例中实现MDM业务逻辑,EnterpriseAdminExtensionAbility实现了系统管理状态变化通知功能,并定义了管理应用激活、去激活、应用安装、卸载事件等回调接口。
约束与限制
- 功能限制
仅支持设备管理员应用使用。
场景:监听设备管理器激活、去激活、应用安装、卸载事件
概述
onAdminEnabled:由企业管理员或者员工部署MDM应用,激活设备管理器,系统通知MDM应用已激活DeviceAdmin权限。MDM应用可在onAdminEnabled回调函数中进行初始化策略设置。
onAdminDisabled:由系统或者员工去激活设备管理器,通知去激活DeviceAdmin权限,应用可以通知企业管理员设备已脱管。
onBundleAdded: 企业应用管理场景下,企业管理员订阅应用安装卸载事件,端侧应用安装和卸载事件通知MDM应用,MDM应用可以在回调函数中进行事件上报,通知企业管理员。
onBundleRemoved: 企业应用管理场景下,企业管理员取消订阅应用安装卸载事件。
接口说明
类名 | 接口名称 | 描述 |
EnterpriseAdminExtensionAbility | onAdminDisabled(): void | 设备管理器应用去激活回调方法 |
EnterpriseAdminExtensionAbility | onBundleAdded(bundleName: string): void | 应用安装回调方法 |
EnterpriseAdminExtensionAbility | onAdminEnabled(): void | 设备管理器应用激活回调方法 |
EnterpriseAdminExtensionAbility | onBundleRemoved(bundleName: string): void | 应用卸载回调方法 |
开发步骤
开发者在实现EnterpriseAdminExtensionAbility的时候,需先激活设备管理员应用,并在设备管理员应用的代码目录下新建ExtensionAbility,具体步骤如下。
- 在工程Module对应的ets目录下,右键选择“New > Directory”,新建一个目录并命名为EnterpriseExtAbility。
- 在EnterpriseExtAbility目录,右键选择“New > TypeScript File”,新建一个TypeScript文件并命名为EnterpriseExtAbility.ts。
- 打开EnterpriseExtAbility.ts文件,导入EnterpriseAdminExtensionAbility模块,自定义类继承EnterpriseAdminExtensionAbility并加上需要的应用通知回调方法,如onAdminEnabled()、onAdminDisabled()等回调方法。当设备管理员应用被激活或者去激活时,则可以在对应回调方法中接受系统发送通知。
import EnterpriseAdminExtensionAbility from '@ohos.enterprise.EnterpriseAdminExtensionAbility';
export default class EnterpriseAdminAbility extends EnterpriseAdminExtensionAbility {
onAdminEnabled() {
console.info("onAdminEnabled");
}
onAdminDisabled() {
console.info("onAdminDisabled");
}
onBundleAdded(bundleName: string) {
console.info("EnterpriseAdminAbility onBundleAdded bundleName:" + bundleName)
}
onBundleRemoved(bundleName: string) {
console.info("EnterpriseAdminAbility onBundleRemoved bundleName" + bundleName)
}
};
4.在工程Module对应的module.json5配置文件中注册ServiceExtensionAbility,type标签需要设置为“enterpriseAdmin”,srcEntrance标签表示当前ExtensionAbility组件所对应的代码路径。
"extensionAbilities": [
{
"name": "ohos.samples.enterprise_admin_ext_ability",
"type": "enterpriseAdmin",
"visible": true,
"srcEntrance": "./ets/enterpriseextability/EnterpriseAdminAbility.ts"
}
]
使用示例
通过@ohos.enterprise.adminManager模块中的subscribeManagedEvent接口和unsubscribeManagedEvent接口进行企业设备管理事件的订阅,订阅应用安装、卸载事件。当订阅成功后,端侧应用安装和卸载事件通知MDM应用,MDM应用可以在回调函数中进行事件上报,通知企业管理员。
@State managedEvents: Array<adminManager.ManagedEvent> = [0,1]
@State subscribeManagedEventMsg: string = ""
@State unsubscribeManagedEventMsg: string = ""
async subscribeManagedEventCallback() {
await adminManager.subscribeManagedEvent(this.admin,
[adminManager.ManagedEvent.MANAGED_EVENT_BUNDLE_ADDED,
adminManager.ManagedEvent.MANAGED_EVENT_BUNDLE_REMOVED], (error) => {
if (error) {
this.subscribeManagedEventMsg = 'subscribeManagedEvent Callback::errorCode: ' + error.code + ' errorMessage: ' + error.message
} else {
this.subscribeManagedEventMsg = 'subscribeManagedEvent Callback::success'
}
})
}
async unsubscribeManagedEventPromise() {
await adminManager.unsubscribeManagedEvent(this.admin,
[adminManager.ManagedEvent.MANAGED_EVENT_BUNDLE_ADDED,
adminManager.ManagedEvent.MANAGED_EVENT_BUNDLE_REMOVED]).then(() => {
this.unsubscribeManagedEventMsg = 'unsubscribeManagedEvent Promise::success'
}).catch((error) => {
this.unsubscribeManagedEventMsg = 'unsubscribeManagedEvent Promise::errorCode: ' + error.code + ' errorMessage: ' + error.message
})
}
相关实例
针对EnterpriseAdminExtensionAbility开发,有以下相关示例可供参考:
EnterpriseAdminExtensionAbility:EnterpriseAdminExtensionAbility的创建与使用(ArkTS) (API9)