OpenHarmony后台服务开发指南:ServiceAbility与ServiceExtensionAbility全解析 - 指南

news/2025/11/25 8:34:49/文章来源:https://www.cnblogs.com/ljbguanli/p/19266573

OpenHarmony后台服务开发指南:ServiceAbility与ServiceExtensionAbility全解析 - 指南

概述

ServiceAbility是OpenHarmony中用于实现后台服务的组件,它可以在后台长时间运行,没有用户界面。ServiceAbility主要用于执行需要长时间运行的操作,如音乐播放、文件下载、数据同步等任务。

ServiceAbility具有以下特点:

  • 无用户界面,在后台运行
  • 可被其他组件(如Ability)启动或绑定
  • 可以在设备重启后自动启动(需要配置)
  • 支持多进程通信

ServiceAbility生命周期

ServiceAbility的生命周期包含以下关键回调方法:

生命周期方法说明
onStart()ServiceAbility创建时调用,用于初始化操作
onCommand()启动ServiceAbility时调用,可多次调用
onConnect()绑定ServiceAbility时调用,返回IRemoteObject对象
onDisconnect()解绑ServiceAbility时调用
onStop()ServiceAbility销毁时调用,用于资源清理

ServiceAbility配置

在module.json5文件中配置ServiceAbility:

{
"module": {
"abilities": [
{
"name": "ServiceAbility",
"srcEntry": "./ets/serviceability/ServiceAbility.ts",
"description": "$string:serviceability_desc",
"icon": "$media:icon",
"type": "service",
"backgroundModes": [
"dataTransfer",
"audioPlayback"
]
}
]
}
}

配置项说明:

  • type:设置为"service"表示这是一个ServiceAbility
  • backgroundModes:指定后台运行模式,如数据传输、音频播放等

ServiceExtensionAbility概述

ServiceExtensionAbility是Stage模型中替代ServiceAbility的后台服务组件,主要面向系统应用。与ServiceAbility相比,ServiceExtensionAbility提供了更严格的生命周期管理和更安全的运行环境。

ServiceExtensionAbility有两种运行形式:

  1. 启动型:通过startServiceExtensionAbility启动
  2. 连接型:通过connectServiceExtensionAbility连接

ServiceExtensionAbility生命周期

ServiceExtensionAbility的生命周期包含以下回调方法:

生命周期方法说明
onCreate()ServiceExtensionAbility创建时调用
onRequest()启动ServiceExtensionAbility时调用
onConnect()绑定ServiceExtensionAbility时调用
onDisconnect()解绑ServiceExtensionAbility时调用
onDestroy()ServiceExtensionAbility销毁时调用

ServiceExtensionAbility开发步骤

1. 创建ServiceExtensionAbility

import { ServiceExtensionAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
const TAG: string = '[ServiceExtensionAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
export default class ServiceExtAbility extends ServiceExtensionAbility {
onCreate(want: Want, launchMode: number) {
hilog.info(DOMAIN_NUMBER, TAG, 'onCreate, want: %{public}s, launchMode: %{public}d',
JSON.stringify(want), launchMode);
}
onRequest(want: Want, startId: number) {
hilog.info(DOMAIN_NUMBER, TAG, 'onRequest, want: %{public}s, startId: %{public}d',
JSON.stringify(want), startId);
}
onConnect(want: Want) {
hilog.info(DOMAIN_NUMBER, TAG, 'onConnect, want: %{public}s', JSON.stringify(want));
return null;
}
onDisconnect(want: Want) {
hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect, want: %{public}s', JSON.stringify(want));
}
onDestroy() {
hilog.info(DOMAIN_NUMBER, TAG, 'onDestroy');
}
}

2. 配置ServiceExtensionAbility

在module.json5文件中配置:

{
"module": {
"extensionAbilities": [
{
"name": "ServiceExtAbility",
"srcEntry": "./ets/serviceextensionability/ServiceExtAbility.ts",
"description": "$string:serviceextability_desc",
"icon": "$media:icon",
"type": "service",
"visible": true
}
]
}
}

3. 启动ServiceExtensionAbility

import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
const TAG: string = '[Page_ServiceExtensionAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
@Entry
@Component
struct Page_ServiceExtensionAbility {
build() {
Column() {
Button('启动后台服务')
.onClick(() => {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let want: Want = {
bundleName: 'com.example.myapplication',
abilityName: 'ServiceExtAbility'
};
context.startServiceExtensionAbility(want).then(() => {
hilog.info(DOMAIN_NUMBER, TAG, 'startServiceExtensionAbility success');
}).catch((error: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, 'startServiceExtensionAbility failed');
});
})
}
}
}

4. 停止ServiceExtensionAbility

// 在ServiceExtensionAbility内部
this.terminateSelf();
// 在外部组件中
context.stopServiceExtensionAbility(want).then(() => {
hilog.info(DOMAIN_NUMBER, TAG, 'stopServiceExtensionAbility success');
}).catch((error: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, 'stopServiceExtensionAbility failed');
});

连接ServiceExtensionAbility

1. 建立连接

import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
const TAG: string = '[Page_ServiceExtensionAbility]';
const DOMAIN_NUMBER: number = 0xFF00;
let connectionId: number;
@Entry
@Component
struct Page_ServiceExtensionAbility {
build() {
Column() {
Button('连接后台服务')
.onClick(() => {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let want: Want = {
bundleName: 'com.example.myapplication',
abilityName: 'ServiceExtAbility'
};
let options: common.ConnectOptions = {
onConnect(elementName, remote) {
hilog.info(DOMAIN_NUMBER, TAG, 'onConnect callback');
// 保存remote对象用于通信
},
onDisconnect(elementName) {
hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
},
onFailed(code) {
hilog.error(DOMAIN_NUMBER, TAG, 'onFailed callback');
}
};
connectionId = context.connectServiceExtensionAbility(want, options);
})
}
}
}

2. 断开连接

Button('断开连接')
.onClick(() => {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
context.disconnectServiceExtensionAbility(connectionId).then(() => {
hilog.info(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility success');
}).catch((error: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG, 'disconnectServiceExtensionAbility failed');
});
})

客户端与服务端通信

使用IDL接口通信(推荐)

// 客户端
import { common } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
import IdlServiceExtProxy from '../IdlServiceExt/idl_service_ext_proxy';
let options: common.ConnectOptions = {
onConnect(elementName, remote: rpc.IRemoteObject) {
let serviceExtProxy: IdlServiceExtProxy = new IdlServiceExtProxy(remote);
// 通过接口调用的方式进行通信
serviceExtProxy.processData(1, (errorCode: number, retVal: number) => {
hilog.info(DOMAIN_NUMBER, TAG, `processData, errorCode: ${errorCode}, retVal: ${retVal}`);
});
},
onDisconnect(elementName) {
hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
},
onFailed(code: number) {
hilog.error(DOMAIN_NUMBER, TAG, 'onFailed callback');
}
};

使用MessageSequence通信

import { rpc } from '@kit.IPCKit';
let options: common.ConnectOptions = {
onConnect(elementName, remote: rpc.IRemoteObject) {
let option = new rpc.MessageOption();
let data = new rpc.MessageSequence();
let reply = new rpc.MessageSequence();
data.writeInt(99);
remote.sendMessageRequest(REQUEST_CODE, data, reply, option).then((ret: rpc.RequestResult) => {
let errCode = reply.readInt();
let msg: number = 0;
if (errCode === 0) {
msg = reply.readInt();
}
hilog.info(DOMAIN_NUMBER, TAG, `sendRequest msg:${msg}`);
});
},
onDisconnect(elementName) {
hilog.info(DOMAIN_NUMBER, TAG, 'onDisconnect callback');
},
onFailed(code) {
hilog.error(DOMAIN_NUMBER, TAG, 'onFailed callback');
}
};

服务端对客户端身份校验

通过callerUid识别客户端应用

import { bundleManager } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
export default class ServiceExtImpl extends IdlServiceExtStub {
processData(data: number, callback: ProcessDataCallback) {
let callerUid = rpc.IPCSkeleton.getCallingUid();
bundleManager.getBundleNameByUid(callerUid).then((callerBundleName) => {
hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid: ' + callerBundleName);
// 对客户端包名进行识别
if (callerBundleName !== 'com.samples.stagemodelabilitydevelop') {
hilog.info(DOMAIN_NUMBER, TAG, 'The caller bundle is not in trustlist, reject');
return;
}
// 识别通过,执行正常业务逻辑
callback(ERR_OK, data + 1);
}).catch((err: BusinessError) => {
hilog.info(DOMAIN_NUMBER, TAG, 'getBundleNameByUid failed: ' + err.message);
});
}
}

通过callerTokenId对客户端进行鉴权

import { abilityAccessCtrl, bundleManager } from '@kit.AbilityKit';
import { rpc } from '@kit.IPCKit';
export default class ServiceExtImpl extends IdlServiceExtStub {
processData(data: number, callback: ProcessDataCallback) {
let callerTokenId = rpc.IPCSkeleton.getCallingTokenId();
let accessManger = abilityAccessCtrl.createAtManager();
// 所校验的具体权限由开发者自行选择
let grantStatus = accessManger.verifyAccessTokenSync(callerTokenId, 'ohos.permission.GET_BUNDLE_INFO_PRIVILEGED');
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
hilog.info(DOMAIN_NUMBER, TAG, 'PERMISSION_DENIED');
callback(ERR_DENY, data); // 鉴权失败,返回错误
return;
}
hilog.info(DOMAIN_NUMBER, TAG, 'verify access token success.');
callback(ERR_OK, data + 1); // 鉴权通过,执行正常业务逻辑
}
}

ServiceAbility向ServiceExtensionAbility迁移

迁移策略

  1. 系统应用:建议迁移至ServiceExtensionAbility
  2. 三方应用:根据业务类型选择场景化ExtensionAbility或公共模块/后台任务方案

生命周期对比

ServiceAbilityServiceExtensionAbility说明
onStart()onCreate()创建时的初始化
onCommand()onRequest()启动服务时的回调
onConnect()onConnect()绑定服务时的回调
onDisconnect()onDisconnect()解绑服务时的回调
onStop()onDestroy()销毁服务时的回调

总结

ServiceAbility和ServiceExtensionAbility是OpenHarmony中用于实现后台服务的重要组件。ServiceExtensionAbility作为Stage模型中的后台服务组件,提供了更严格的生命周期管理和更安全的运行环境,是系统应用开发的首选方案。通过合理使用这些组件,开发者可以实现各种后台服务功能,满足应用的不同需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/975535.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年比较好的光伏线缆厂家实力及用户口碑排行榜

2025年光伏线缆厂家实力及用户口碑排行榜光伏线缆行业背景与市场趋势随着全球能源结构转型加速推进,光伏产业已成为可再生能源领域的重要支柱。据国际能源署(IEA)最新数据显示,2025年全球光伏新增装机容量预计将达到…

完整教程:计算机3D视觉:Pytorch3d的环境配置与初步使用

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

.NET+AI | MEAI | ChatOptions 详解(5)

ChatOptions 详解:精准控制 AI 对话的配置利器 一句话简介 ChatOptions 是 Microsoft.Extensions.AI 中传递给 IChatClient 的统一配置容器,用于在单次请求中精准控制生成策略、工具调用和扩展特性。🎯 核心价值✅…

2025年评价高的高弹硬质棉厂家推荐及选择指南

2025年评价高的高弹硬质棉厂家推荐及选择指南行业背景与市场趋势随着全球纺织材料行业的快速发展,高弹硬质棉作为一种新型环保填充材料,近年来市场需求呈现稳定增长态势。据中国纺织工业联合会最新数据显示,2024年我…

2025年质量好的硬质棉厂家最新推荐排行榜

2025年质量好的硬质棉厂家最新推荐排行榜行业背景与市场趋势硬质棉作为一种新型环保填充材料,近年来在家居、工业及特殊应用领域展现出强劲的增长势头。根据中国纺织工业联合会最新发布的《2024-2025年中国纺织新材料…

25.11.22

QOJ8147 首先可以手算出这个序列满足:\(a_1=1\); \(a_{i+1}=-a_i\vee a_{i+1}=a_i+2\).但是还是不好数啊。接下来这一步纯数学,构造:\(b_i=\frac{|a_i|+1}{2}\),显然还是整数序列。 发现限制变成了:\(b_1=1\); \(…

CVE-2025-12870认证滥用漏洞分析:aEnrich eHRD系统高危安全风险

本文详细分析了CVE-2025-12870认证滥用漏洞,该漏洞影响aEnrich开发的a+HRD系统,允许未经认证的远程攻击者通过特制数据包获取管理员访问令牌,从而以提升的权限访问系统。概述 CVE-2025-12870是一个影响aEnrich开发的…

安装Docker(win11)

1 环境准备 1.1 开启Hyper-V Hyper-V功能仅在Windows专业版、企业版和教育版中可用,家庭版不支持Hyper-V功能。 为了解决这一问题,我们需要通过自行创建cmd指令执行。 操作步骤:创建cmd文件首先需要创建一个cmd文件…

2025年热门的不锈钢自攻螺钉厂家最新推荐权威榜

2025年热门的不锈钢自攻螺钉厂家最新推荐权威榜行业背景与市场趋势不锈钢自攻螺钉作为现代工业制造中不可或缺的基础紧固件,近年来随着全球制造业的复苏和建筑行业的持续发展,市场需求呈现稳定增长态势。根据中国五金…

2025年靠谱的盘头十字自攻螺钉厂家推荐及选择指南

2025年靠谱的盘头十字自攻螺钉厂家推荐及选择指南行业背景与市场趋势随着建筑装饰、工业制造和家电行业的持续发展,盘头十字自攻螺钉作为基础紧固件,市场需求呈现稳定增长态势。据中国五金制品协会2024年统计数据显示…

比 MySQL 轻,比 SQLite 强:终于有人把 AI 数据库做对了

前几天,我看到了一个来自 Turso 创始人 Pekka 的观点:SQLite 被认为是 AI agent 的理想数据库,因为它轻量级且适用于 AI agent 的各种场景,但仍然需要进化。评论区里也有意思,有人会和大家分享自己为了 SQLite 的…

PTA算法每日三题 - 详解

PTA算法每日三题 - 详解2025-11-25 08:16 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fon…

如何解除 iPad 和 iPhone 文本消息的关联? - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年比较好的闸阀门厂家最新推荐权威榜

2025年比较好的闸阀门厂家最新推荐权威榜行业背景与市场趋势随着全球工业化进程的加速和基础设施建设的持续投入,阀门行业作为工业领域的关键配套产业,近年来保持了稳定增长态势。据《2024-2029年中国阀门行业市场调…

Visual Studio 2026 现已正式发布,更快、更智能!

前言 前不久 Visual Studio 官方博客宣布 Visual Studio 2026 正式发布!本次版本凝聚了广大开发者的宝贵反馈,博客中提及在此版本发布之前的一年里,Visual Studio 团队修复了 5000 多个用户报告的缺陷,并实现了 30…

AI元人文与LLM:解构单一性霸权与构建价值共生的未来

AI元人文与LLM:解构单一性霸权与构建价值共生的未来 引言:巨灵神的诞生与囚笼 我们曾以创世者般的热情,迎接大语言模型(LLM)这一“数字巨灵神”的降临,期许它成为人类智慧的集大成者。然而,当最初的惊叹褪去,我…

拒绝AI=拒绝饭碗?硅谷程序员的噩梦已经开始,我们的噩梦就在路上! - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

实用指南:【详细教程】对拍 0 基础学习小课堂 [内附例题演示]

实用指南:【详细教程】对拍 0 基础学习小课堂 [内附例题演示]pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Con…

深度学习模型预测手术风险的验证研究

本研究通过外部验证评估了基于12导联数字心电图的深度学习算法PreOpNet在预测非心脏大手术后30天死亡率及主要不良心脏事件方面的表现,并与传统风险评分和生物标志物进行比较。外部验证使用数字心电图预测非心脏大手术…

2025年知名的专业生产印染配件优质厂家推荐榜单

2025年知名的专业生产印染配件优质厂家推荐榜单行业背景与市场趋势印染行业作为纺织产业链中的重要环节,近年来随着全球纺织业的持续发展而稳步增长。根据中国印染行业协会最新统计数据显示,2024年我国印染机械配件市…