你还想“退到后台继续跑”?系统不打你就不错了——后台任务、通知、提醒代理一次讲透!

举报
bug菌 发表于 2025/12/25 11:46:30 2025/12/25
【摘要】 🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8 🧩先把话说清楚:后台“能跑多久”,不是你说了算🙃鸿蒙的后台策略很现...

🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!

环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8

🧩先把话说清楚:后台“能跑多久”,不是你说了算🙃

鸿蒙的后台策略很现实:你一退后台,过一会儿就会被挂起,除非你按规矩申请后台任务。短时任务负责“给你喘口气”,长时任务负责“我允许你长期干,但必须用户可感知”。官方把这套规则写得很明确:短时任务用于挂起前补尾巴(保存状态/发消息等),长时任务用于后台长期运行且用户可感知的业务(播放、导航、录制、下载等)。

1️⃣ 🏃后台任务申请:短时 vs 长时(别选错,不然要么卡死要么被管控)

🕐短时任务(Transient Task):给你“最多几分钟”的收尾时间

适用场景(特别像现实生活):

  • 你刚退后台,得保存草稿写本地日志上报一次埋点发最后一条消息
  • 总之:耗时不长,但必须在挂起前做完

硬性规则(不听真的会翻车):

  • 申请时机:必须在前台onBackground 回调内申请,否则会失败。
  • 数量限制:同一时刻最多 3 个短时任务。
  • 配额机制:默认单日 10 分钟,单次最多 3 分钟;低电量单次默认 1 分钟;超时不取消会被系统管控(挂起/终止)。
  • 任务用完要主动 cancel,不然浪费当天配额,等于“把自己活活饿死”。

🧪ArkTS 示例:申请短时任务 + 超时回调 + 主动取消

import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { BusinessError } from '@kit.BasicServicesKit';

let requestId: number | undefined;

export function startTransientTask() {
  try {
    const info = backgroundTaskManager.requestSuspendDelay('save_draft', () => {
      // ⏳系统提示“快到点了”,你得赶紧收尾并取消
      console.info('⏰ transient task is expiring, cancel now!');
      if (requestId !== undefined) {
        backgroundTaskManager.cancelSuspendDelay(requestId);
        requestId = undefined;
      }
    });

    requestId = info.requestId;
    console.info(`✅ transient task granted, requestId=${requestId}`);
  } catch (e) {
    const err = e as BusinessError;
    console.error(`❌ requestSuspendDelay failed: ${err.code}, ${err.message}`);
  }
}

export async function logRemainingTime() {
  if (requestId === undefined) return;
  const left = await backgroundTaskManager.getRemainingDelayTime(requestId);
  console.info(`🕐 remaining(ms)=${left}`);
}

export function stopTransientTask() {
  if (requestId !== undefined) {
    backgroundTaskManager.cancelSuspendDelay(requestId);
    requestId = undefined;
    console.info('🧹 transient task canceled');
  }
}

接口与约束(requestSuspendDelay / getRemainingDelayTime / cancelSuspendDelay、配额与超时行为)是官方短时任务指南的核心内容。


🕰️长时任务(Continuous Task):想长期跑?可以,但你得“让用户看得见”

适用场景(系统认可的“正经后台”):

  • 🎵 音视频播放/投播
  • 🎤 录音/录屏
  • 📍 导航定位
  • 📤 数据传输(上传下载)
  • 🔵 蓝牙交互
  • 🔗 多设备互联
  • 📞 VoIP(部分版本)
    ……这些类型与限制、校验机制,官方文档写得非常细:申请成功后通知栏会显示关联通知;用户删除通知,系统会自动停止长时任务

Stage 模型的关键点

  • 长时任务在 Stage 模型里一般由 UIAbility 申请。
  • 需要权限 ohos.permission.KEEP_BACKGROUND_RUNNING,并在 module.json5backgroundModes 里声明业务类型(比如 audioPlayback、location、dataTransfer 等)。

🧩module.json5 关键配置(示例)

{
  "module": {
    "abilities": [
      {
        "name": "EntryAbility",
        "type": "page",
        "backgroundModes": [
          "audioPlayback",
          "dataTransfer"
        ]
      }
    ],
    "requestPermissions": [
      { "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" }
    ]
  }
}

(配置项与权限要求来自官方长时任务指南。)

🧪ArkTS 示例:申请/取消长时任务(最常用的那一套)

import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import wantAgent from '@ohos.wantAgent'; // 不同工程模板导入方式可能略有差异
import { BusinessError } from '@kit.BasicServicesKit';

export async function startContinuousTask(context: any) {
  try {
    // ✅通常需要 WantAgent 来关联通知点击后的跳转
    const agentInfo: wantAgent.WantAgentInfo = {
      wants: [{
        bundleName: context.bundleName,
        abilityName: 'EntryAbility'
      }],
      operationType: wantAgent.OperationType.START_ABILITY,
      requestCode: 0
    };
    const agent = await wantAgent.getWantAgent(agentInfo);

    // 申请单个长时任务(不同 API 版本也支持“多个任务一次申请”的 request 形式)
    await backgroundTaskManager.startBackgroundRunning(
      context,
      backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK,
      agent
    );

    console.info('✅ continuous task started');
  } catch (e) {
    const err = e as BusinessError;
    console.error(`❌ startBackgroundRunning failed: ${err.code}, ${err.message}`);
  }
}

export async function stopContinuousTask(context: any) {
  try {
    await backgroundTaskManager.stopBackgroundRunning(context);
    console.info('🛑 continuous task stopped');
  } catch (e) {
    const err = e as BusinessError;
    console.error(`❌ stopBackgroundRunning failed: ${err.code}, ${err.message}`);
  }
}

长时任务的类型、通知栏行为、以及 startBackgroundRunning/stopBackgroundRunning 等接口,都在官方“长时任务(ArkTS)”指南里。

😄老司机提醒一句:
长时任务不是“免死金牌”。系统会做一致性校验:你申请了播放却没播放、申请了数据传输却不更新进度……都可能被管控。


2️⃣ 🔔Notification API:通知不是“想发就发”,先拿授权!

通知这块的基本流程是:

  1. 请求用户授权 requestEnableNotification()(没授权你发不出去)
  2. 组装 NotificationRequest
  3. notificationManager.publish() 发布(相同 id/label 会替换旧通知)

🧪ArkTS:请求通知授权 + 发一条最小通知

import { notificationManager } from '@kit.NotificationKit';
import { BusinessError } from '@kit.BasicServicesKit';

export async function ensureNotificationEnabled(): Promise<boolean> {
  try {
    await notificationManager.requestEnableNotification(); // 弹窗询问用户
    return true;
  } catch (e) {
    const err = e as BusinessError;
    console.error(`❌ requestEnableNotification failed: ${err.code}, ${err.message}`);
    return false;
  }
}

export async function publishSimpleNotification() {
  const ok = await ensureNotificationEnabled();
  if (!ok) return;

  const req: notificationManager.NotificationRequest = {
    id: 1001,
    content: {
      notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
      normal: {
        title: '🎉 任务完成啦',
        text: '我在后台把活儿干完了~'
      }
    }
  };

  await notificationManager.publish(req);
  console.info('✅ notification published');
}

授权要求来自“请求通知授权”指南;发布接口与替换规则见 Notification Kit 说明与 publish 描述。

😅小坑提前说:
requestEnableNotification() 通常只弹一次,用户拒了以后要引导去系统设置重新开(官方与社区 FAQ 都在强调这个现象)。


3️⃣ ⏰提醒代理(Reminder Agent):App 被杀了也能准点叫你起床

如果你的需求是:

  • App 退后台/甚至进程退出后
  • 还要在某个时间点提醒用户
    那就别硬扛后台常驻了,直接用 代理提醒 reminderAgentManager:系统会代替你计时,到点后通过通知中心弹出提醒。

关键限制(别踩红线):

  • 支持类型:倒计时 / 日历 / 闹钟
  • 数量限制:三方应用最多 30 个有效提醒
  • 需要通知授权 + 权限 ohos.permission.PUBLISH_AGENT_REMINDER
  • 部分设备/场景会有“管控机制”(防广告营销滥用),官方给了适配/申请说明。

🧪ArkTS:发布一个倒计时提醒(系统代发)

import { reminderAgentManager } from '@kit.BackgroundTasksKit';
import { notificationManager } from '@kit.NotificationKit';

export async function publishTimerReminder() {
  // 1) 先确保通知开关已授权(否则会报“Notification is not enabled”)
  await notificationManager.requestEnableNotification(); // 官方要求先做这步:contentReference[oaicite:21]{index=21}

  // 2) 组装 ReminderRequest(倒计时类型)
  const req: reminderAgentManager.ReminderRequestTimer = {
    reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_TIMER,
    triggerTimeInSeconds: 10,           // 10 秒后提醒
    title: '⏲️ 到点啦',
    content: '别拖了,快去喝口水~',
    ringDuration: 0                      // >0 可播放自定义铃声(按文档规则)
  };

  const reminderId = await reminderAgentManager.publishReminder(req);
  console.info(`✅ reminder published, id=${reminderId}`);
}

代理提醒的能力定义、类型、数量限制、以及 publishReminder 的权限/前置授权要求都在官方指南与 API 参考中。

🧠选型口诀(我真心希望你少走弯路)

  • 短时任务:退后台“补尾巴”,最多几分钟,做完就 cancel。
  • 长时任务:后台长期跑且用户可感知,必须配套通知与类型声明。
  • 通知:先授权再 publish,不要硬发。
  • 提醒代理:App 被杀也要准点提醒,用系统代发,别自己死扛常驻。

🧧福利赠与你🧧

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」专栏(全网一个名),bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。

  最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

  同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

✨️ Who am I?

我是bug菌(全网一个名),CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云多年度十佳博主/价值贡献奖,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。