鸿蒙 Background Tasks Kit(后台任务开发服务)

设备返回主界面、锁屏、应用切换等操作会使应用退至后台。应用退至后台后,如果继续活动,可能会造成设备耗电快、用户界面卡顿等现象。为了降低设备耗电速度、保障用户使用流畅度,系统会对退至后台的应用进行管控,包括进程挂起(Suspend,即系统不再为应用进程分配 CPU 时间片,同时对应的公共事件等不再发给应用进程)和进程终止(Terminate)。

  • 应用退至后台一小段时间(由系统定义),应用进程会被挂起;
  • 资源不足时,系统会终止部分应用进程(即回收该进程的所有资源);

同时,为了保障后台音乐播放、日历提醒等功能的正常使用,系统提供了规范内受约束的后台任务,扩展应用在后台运行时间。

提示:对于鸿蒙系统中运行的所有进程,系统会给予一定的资源配额约束,包括进程在连续一段时间内内存的使用、CPU 使用占比,以及 24 小时磁盘写的 IO 量,均有对应的配额上限。

超过配额上限时,如果进程处于前台,系统会生成 warning 日志;如果进程处于后台,系统会终止该进程

后台任务类型

应用退至后台后如果有继续运行的需求,可申请使用如下几种受系统约束的后台任务:

  1. 短时任务:适用于实时性要求高、耗时不长的任务,例如状态持久化保存。
  2. 长时任务:适用于长时间运行在后台、用户可感知的任务,例如后台播放音乐、导航、设备连接等,使用长时任务避免应用进程被挂起。
  3. 延迟任务:对于实时性要求不高、可延迟执行的任务,系统提供了延迟任务,即满足条件的应用退至后台后被放入执行队列,系统会根据内存、功耗等统一调度;例如:2 小时后自动到邮件服务器收取邮件。
  4. 代理提醒:代理提醒是指应用退后台或进程终止后,系统会代理应用做相应的提醒。适用于定时提醒类业务,例如通知用户定时抢票应用等。

说明:

1、系统仅支持规范内受约束的后台任务。应用退至后台后,若未使用规范内的后台任务或选择的后台任务类型不正确,对应的应用进程会被挂起或终止。

2、应用申请了规范内的后台任务,仅会提升应用进程被回收的优先级。当系统资源严重不足时,即使应用进程申请了规范内的后台任务,系统仍会终止部分进程,用以保障系统稳定性。

短时任务

应用退至后台一小段时间后,会被系统挂起,无法执行对应的任务。如果应用在后台仍需要执行耗时不长的任务,如状态保存等,可以通过申请短时任务,扩展应用在后台的运行时间。

短时任务使用限制:

  1. 申请时机:应用需要在前台或 onBackground 回调内,申请短时任务,否则会申请失败。
  2. 数量限制:一个应用同一时刻最多申请执行 3 个 短时任务。
  3. 配额机制:一个应用会有一定的短时任务配额(根据系统状态和用户习惯调整),单日(24 小时内)配额默认为 10 分钟,单次配额最大为 3 分钟,低电量时单次配额默认为 1 分钟,配额消耗完后不允许再申请短时任务。
  4. 配额计算:仅当应用在后台时,对应用下的短时任务计时;同一个应用下的同一个时间段的短时任务,不重复计时。
  5. 超时:短时任务即将超时时,系统会回调应用,应用需要取消短时任务。如果超时不取消,系统会终止对应的应用进程。
主要接口

下面的 API 都在 backgroundTaskManager 名称空间下

接口名 描述
requestSuspendDelay(reason: string, callback: Callback<void>): DelaySuspendInfo 申请短时任务
getRemainingDelayTime(requestId: number): Promise<number> 获取对应短时任务的剩余时间
cancelSuspendDelay(requestId: number): void 取消短时任务
例子
ts 复制代码
import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'

@Entry
@Component
struct Index {
  requestId: number = 0 //申请编号,即应用申请延迟挂起这个操作的编号,即后台短时任务编号
  timerId: number = 0 //周期性定时器编号

  shortTimeBackgroundTask() {
    let count = 0
    this.timerId = setInterval(() => {
      count++
      console.log('--' + count + ' 后台任务正在执行', Date.now())
    }, 1000)
  }

  build() {
    Column({ space: 10 }) {
      Text('后台任务之一:短时任务')
        .fontSize(30)

      Button('1.申请执行短时任务A(申请当前应用延迟一会儿再挂起)').onClick(async _ => {
        try {
          //请求系统延迟挂起当前应用,我想执行一些短时任务
          let info = backgroundTaskManager.requestSuspendDelay('申请状态持久化短时任务', () => {
            console.log('--短时任务时间配额即将到期!请立即执行一些最后的清理操作!')
            clearInterval(this.timerId) //清理当前页面正在占用的资源
            backgroundTaskManager.cancelSuspendDelay(this.requestId) //取消挂起延迟,即取消后台任务
          })
          //上述挂起延迟申请成功的话,下面的代码就是在"挂起延迟"这段时间内执行的短时后台任务:
          //获得短时任务编号
          this.requestId = info.requestId
          //查看当前短时任务剩余的时间配额(以ms为单位)
          let time = await backgroundTaskManager.getRemainingDelayTime(this.requestId)
          if (time >= 60000) {
            console.log('--剩余时间配额足够,开始执行后台任务')
            this.shortTimeBackgroundTask()
          } else {
            console.log('--剩余的时间配额不足以执行目标任务')
          }
        } catch (err) {
          console.log('--申请挂起延迟用以执行短时后台任务失败:', JSON.stringify(err))
        }
      })

      Button('取消短时任务').onClick(_ => {
        backgroundTaskManager.cancelSuspendDelay(this.requestId)
      })
    }
    .height('100%')
    .width('100%')
    .padding(10)
  }
}

长时任务

应用退至后台后,在后台需要长时间运行用户可感知的任务,如播放音乐、导航等。为防止应用进程被挂起,导致对应功能异常,可以申请长时任务,使应用在后台长时间运行。

长时任务分为如下类型

参数名 描述 配置项 场景举例
DATA_TRANSFER 数据传输 dataTransfer 后台下载大文件,如浏览器后台下载等
AUDIO_PLAYBACK 音视频播放 audioPlayback 音乐类应用在后台播放音乐
AUDIO_RECORDING 录制 audioRecording 录音机在后台录音
LOCATION 定位导航 location 导航类应用后台导航
BLUETOOTH_INTERACTION 蓝牙相关 bluetoothInteraction 通过蓝牙传输分享的文件
MULTI_DEVICE_CONNECTION 多设备互联 multiDeviceConnection 分布式业务连接(如手机与平板、电视等互联)
TASK_KEEPING 计算任务(仅对 2IN1 开放) taskKeeping 杀毒软件在后台进行病毒扫描等任务
约束与限制

1、申请限制:Stage 模型中,长时任务仅支持 UIAbility 申请;FA 模型中,长时任务仅支持 ServiceAbility 申请。

2、数量限制:一个 UIAbility 同一时刻仅支持申请一个长时 任务,即在一个长时任务结束后才可能继续申请。如果一个应用同时需要申请多个长时任务,需要创建多个 UIAbility;一个应用的一个 UIAbility 申请长时任务后,整个应用下的所有进程均不会被挂起。

3、运行限制:在手机产品上,系统会进行长时任务校验,例如:

  • 场景 ①:若应用申请了长时任务,但未真正执行申请类型的长时任务或申请类型的任务已结束,系统会对应用进行管控。例如系统检测到应用申请了 AUDIO_PLAYBACK(音视频播放),但实际未播放音乐,长时任务会被取消。
  • 场景 ②:若应用没有申请对应的长时任务类型,但执行了相关类型的长时任务,系统会对应用进行管控。例如系统检测到应用只申请了 AUDIO_PLAYBACK(音视频播放),但实际上除了播放音乐,还在进行录制(对应 AUDIO_RECORDING 类型),系统会对应用进行管控。
  • 场景 ③:若运行长时任务的进程后台负载持续高于所申请类型的典型负载,系统会对应用进行管控。
主要接口
接口名 描述
startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: WantAgent): Promise<void> 申请长时任务
stopBackgroundRunning(context: Context): Promise<void> 取消长时任务

说明:

1、长时任务需申请系统级权限 ohos.permission.KEEP_BACKGROUND_RUNNING 才能使用

2、必须在 module.json5 文件中为 UIAbility 配置相应的长时任务类型 backgroundModes

3、申请长时任务成功后,系统会在通知栏显示相关通知,点击通知可以拉起任务对应的窗口

示例

后台定位服务

当前模块配置 module.json5

json 复制代码
{
  "module": {
    "abilities": [
      {
        "name": "EntryAbility",
        //申请当前UIAbility可以哪些类型的"后台长时任务"
        "backgroundModes": ["location"]
      }
      //一个UIAbility某个时刻只能执行一个后台长时任务,但是可以先后执行多个长时任务
    ],
    "requestPermissions": [
      //当前应用申请数据和功能的访问权限
      //系统授予级权限 ------ 只需要声明name即可
      {
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
        //保持应用在后台持续运行
      },
      //用户授予级权限 ------ 必须声明name/reason/usedScene三个属性
      {
        "name": "ohos.permission.APPROXIMATELY_LOCATION",
        //模糊定位
        "reason": "$string:app_name", // 这里用户会看到的申请权限原因,我这里乱写的
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.LOCATION",
        //精确定位
        "reason": "$string:app_name",
        //当前应用需要向用户解释使用该权限的原因
        "usedScene": {
          //权限在何种场景下被使用
          "abilities": ["EntryAbility"],
          //哪些Ability/窗口中需要使用该权限
          "when": "always"
          //何时使用该权限  inuse:当前应用在前台运行时需要使用    always:总是需要该权限,即使应用没在运行
        }
      }
    ]
  }
}
ts 复制代码
import { abilityAccessCtrl, bundleManager, Permissions, wantAgent } from '@kit.AbilityKit'
import { geoLocationManager } from '@kit.LocationKit'
import { backgroundTaskManager } from '@kit.BackgroundTasksKit'

@Entry
@Component
struct Index {
  //页面显式时,先弹出"申请定位权限"授权窗口
  async onPageShow() {
    //① 声明需要用户授权的权限列表
    let list: Permissions[] = ['ohos.permission.APPROXIMATELY_LOCATION', 'ohos.permission.LOCATION']

    //② 获得当前应用的"访问令牌"
    let flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION //需要获得整个应用的信息,而不是模块的/应用组件的
    let bundleInfo = await bundleManager.getBundleInfoForSelf(flags) //得到当前资源包信息
    let tokenId = bundleInfo.appInfo.accessTokenId //当前应用的当前分身在当前用户使用场景下,系统分配的令牌编号

    let atManager = abilityAccessCtrl.createAtManager() //At: Access Token,访问令牌,即当前应用的授权列表
    let grantStatus0 = await atManager.checkAccessToken(tokenId, list[0])
    let grantStatus1 = await atManager.checkAccessToken(tokenId, list[1])

    //③ 从访问令牌中查询,用户是否授予过定位权限
    if (grantStatus0 == -1 && grantStatus1 == -1) { //0表示已经通过授权了  -1表尚未尚未授权/之前拒绝授权了
      //④ 如果尚未授权过,则弹出申请授权对话框
      let result = await atManager.requestPermissionsFromUser(getContext(), list)
      if (result.authResults[0] == 0) {
        console.log('1.模糊定位权限已经从用户处申请到')
      } else {
        console.log('2.用户拒绝授予模糊定位权限')
      }
      if (result.authResults[1] == 0) {
        console.log('3.精确定位权限已经从用户处申请到')
      } else {
        console.log('4.用户拒绝授予精确定位权限')
      }
    }
  }

  longTimeBackgroundTask() {
    try {
      if (!geoLocationManager.isLocationEnabled()) {
        console.log('--当前系统没有打开定位开关!')
        return
      }
      let count = 0
      geoLocationManager.on('locationChange', {}, (loc) => {
        count++
        console.log('--当前设备位置改变了:', count, JSON.stringify(loc))
      })
    } catch (err) {
      console.log('--持续性定位失败!', JSON.stringify(err))
    }
  }

  build() {
    Column({ space: 10 }) {
      Text('后台任务之二:长时任务')
        .fontSize(30)

      Button('1.申请执行后台长时任务:持续性定位').onClick(async _ => {

        geoLocationManager.getCurrentLocation({}, (err, loc) => {
          if (!err) console.log('单次定位成功:', loc);
        });

        try {
          let wa = await wantAgent.getWantAgent({
            //创建一个want代理,用于给系统通知被点击后跳转到哪个UIAbility
            wants: [{ bundleName: 'com.example.quanguokefei', abilityName: 'EntryAbility' }],
            requestCode: Date.now(), // 使用者定义的一个私有值,这里为了避免重复导致任务无法开启
            actionType: wantAgent.OperationType.START_ABILITY, //必需属性,指定用户点击通知消息作何处理
          })
          console.log('--Want代理创建完成')
          //开启一个长时后台任务
          backgroundTaskManager.startBackgroundRunning(
            getContext(), //参数1:上下文
            backgroundTaskManager.BackgroundMode.LOCATION, //参数2:后台任务类型
            wa                                              //参数3:Want代理对象
            //()=>{ },                                      //参数4:长时任务的内容
          ).then(() => {
            console.log('--长时任务已经开启,开始执行持续性定位操作...')
            this.longTimeBackgroundTask()
          })
        } catch (err) {
          console.log('--长时任务开启失败!', JSON.stringify(err))
        }
      })

      Button('2.关闭后台长时任务').onClick(async _ => {
        await backgroundTaskManager.stopBackgroundRunning(getContext()) //关闭当前后台任务,后续就可以继续开启其它后台任务了
        // await backgroundTaskManager.stopBackgroundRunning(getContext(), ()=>{})
        console.log('--停止后台长时任务成功')
        geoLocationManager.off('locationChange')
        console.log('--手工关闭持续性定位成功')
      })
    }
    .height('100%')
    .width('100%')
    .padding(10)
  }
}

延迟任务

应用退至后台后,需要执行实时性要求不高的任务,例如有网络时不定期主动获取邮件等,可以使用延迟任务。当应用满足设定条件(包括网络类型、充电类型、存储状态、电池状态、定时状态等)时,将任务添加到执行队列,系统会根据内存、功耗、设备温度、用户使用习惯等统一调度拉起应用

约束与限制

1、数量限制:一个应用同一时刻最多申请 10 个 延迟任务。

2、执行频率限制:系统会根据应用的活跃分组,对延迟任务做分级管控,限制延迟任务调度的执行频率。

应用活跃分组 延迟任务最小执行间隔 备注
活跃分组 2 小时 高频使用应用
经常使用分组 4 小时 中频使用应用
常用使用分组 24 小时 低频使用应用
极少使用分组 48 小时 极少唤醒应用
受限使用分组 禁止 系统限制后台任务
从未使用分组 禁止 完全冻结后台行为

3、超时:WorkSchedulerExtensionAbility 单次回调最长运行 2 分钟。如果超时不取消,系统会终止对应的 Extension 进程。

4、调度延迟:系统会根据内存、功耗、设备温度、用户使用习惯等统一调度,如当系统内存资源不足或温度达到一定挡位时,系统将延迟调度该任务。

5、WorkSchedulerExtensionAbility 接口调用限制:为实现对 WorkSchedulerExtensionAbility 能力的管控,在其中限制以下接口的调用:后台任务管理/相机管理/音频管理/媒体服务

主要接口
接口名 接口描述
startWork(work: WorkInfo): void 申请延迟任务
stopWork(work: WorkInfo, needCancel?: boolean): void 取消延迟任务
getWorkStatus(workId: number, callback: AsyncCallback<WorkInfo>): void 获取延迟任务状态(Callback 形式)
getWorkStatus(workId: number): Promise<WorkInfo> 获取延迟任务状态(Promise 形式)
obtainAllWorks(callback: AsyncCallback<Array<WorkInfo>>): void 获取所有延迟任务(Callback 形式)
obtainAllWorks(): Promise<Array<WorkInfo>> 获取所有延迟任务(Promise 形式)
stopAndClearWorks(): void 停止并清除任务
isLastWorkTimeOut(workId: number, callback: AsyncCallback<boolean>): void 获取上次任务是否超时(针对 RepeatWork,Callback 形式)
isLastWorkTimeOut(workId: number): Promise<boolean> 获取上次任务是否超时(针对 RepeatWork,Promise 形式)
示例

第一步:使用 DevEco Studio 辅助创建 WorkSchedulerExtensionAbility

比如我创建的名字是 EntryWorkSchedulerExtAbility

ts 复制代码
import {
  workScheduler,
  WorkSchedulerExtensionAbility,
} from "@kit.BackgroundTasksKit";

//扩展的延迟任务应用组件,会由系统提供的"任务调度器"来启动,运行在专有的ExtensionAbility进程中
export default class WorkSchedulerExtension extends WorkSchedulerExtensionAbility {
  timerId: number = 0;

  onWorkStart(workInfo: workScheduler.WorkInfo) {
    console.log(
      "--WorkSchedulerExtension.onWorkStart:延迟任务开始执行了...",
      JSON.stringify(workInfo)
    );
    //TODO: 发起HTTP请求,获取邮件服务器上当前用户最新的邮件...
    let count = 0;
    this.timerId = setInterval(() => {
      count++;
      console.log("--" + count + " 延迟任务执行中:", Date.now());
    }, 1000);
  }

  onWorkStop(workInfo: workScheduler.WorkInfo) {
    console.log(
      "--WorkSchedulerExtension.onWorkStop:延迟任务终止执行了",
      JSON.stringify(workInfo)
    );
    clearInterval(this.timerId);
    console.log("--已经手工清理了延迟任务相关的资源对象");
  }
}

第二步:申请开启延迟任务 和 取消延迟任务

ts 复制代码
import { workScheduler } from '@kit.BackgroundTasksKit'

@Entry
@Component
struct Index {
  build() {
    Column({ space: 10 }) {
      Text('后台任务之三:延迟任务')
        .fontSize(30)

      Button('1.申请注册一个延迟任务').onClick(_ => {
        const workId: number = Math.floor(1000 + Math.random() * 9000)
        const work: workScheduler.WorkInfo = {
          workId, //必需,延迟任务编号 ------ 注意:同编号的任务再次添加,会抛出错误:9700005
          bundleName: 'com.example.quanguokefei', //必需,延迟任务所在的应用
          abilityName: 'EntryWorkSchedulerExtAbility', //必需,延迟任务所在的ExtensionAbility

          //必需属性:当前延迟任务在何种条件下可以获得执行:
          // isCharging: true,     //只有处于充电状态下才能执行
          // chargerType: workScheduler.ChargingType.CHARGING_PLUGGED_USB,  //只有在指定的充电设备类型时才执行
          batteryStatus: workScheduler.BatteryStatus.BATTERY_STATUS_OKAY, //只有电池状态处于OK(>20%)时才执行
          // networkType: workScheduler.NetworkType.NETWORK_TYPE_WIFI,      //只有网络进入指定的状态类型时才执行
          // storageRequest: workScheduler.StorageRequest.STORAGE_LEVEL_OKAY, //只有外存剩余存储空间达到指定状态才执行
          // repeatCycleTime: 1000*60*60*2                //间隔多久执行一次当前任务
        }

        try {
          workScheduler.startWork(work) //向系统注册一个延迟任务
          console.log('--UIAbility/主进程中注册了一个延迟任务,编号为:' + workId)
        } catch (err) {
          console.log('--UIAbility/主进程中注册延迟任务失败', JSON.stringify(err))
        }
      })

    }
    .height('100%')
    .width('100%')
    .padding(10)
  }
}

效果是自动输出 2 分钟后因为超时被系统自动杀死

代理提醒

应用退到后台或进程终止后,仍然有一些提醒用户的定时类任务,例如购物类应用抢购提醒等,为满足此类功能场景,系统提供了代理提醒(reminderAgentManager)的能力。当应用退至后台或进程终止后,系统会代理应用做相应的提醒。当前支持的提醒类型包括:倒计时、日历和闹钟。

  • 倒计时类(Timer):基于倒计时的提醒功能,例如:2 小时后提醒吃药。
  • 日历类(Calendar):基于日历的提醒功能,例如:12 月 12 日凌晨提醒抢票。
  • 闹钟类(Alarm):基于时钟的提醒功能,例如:08:00 叫我起床。
约束与限制

1、个数限制:一个三方应用支持最多 30 个有效提醒(有效即发布成功),一个系统应用支持最多 2000 个有效提醒,整个系统最多支持 12000 个有效提醒。

2、跳转限制:点击提醒通知后跳转的应用必须是申请代理提醒的本应用。

3、管控限制:为了防止代理提醒被用于滥用于广告、营销类提醒,影响用户体验,代理增加了管控机制。管控后可通过日历 Calendar Kit 替代代理提醒,实现相应的提醒功能。

所以,这小节的示例代码能跑,但是被限制死了。提醒不是不可以发,得有些实力和背景
{"data":1700002,"code":1700002,"message":"The number of reminders exceeds the limit."}

主要接口
接口名 描述
publishReminder(reminderReq: ReminderRequest): Promise<number> 发布一个定时提醒类通知
cancelReminder(reminderId: number): Promise<void> 取消一个指定的提醒类通知
getValidReminders(): Promise<Array<ReminderRequest>> 获取当前应用设置的所有有效的提醒
cancelAllReminders(): Promise<void> 取消当前应用设置的所有提醒
addNotificationSlot(slot: NotificationSlot): Promise<void> 注册一个提醒类需要使用的通知通道(NotificationSlot)
removeNotificationSlot(slotType: notification.SlotType): Promise<void> 删除指定的通知通道(NotificationSlot)

说明:

1、代理提醒需申请系统级权限 ohos.permission. PUBLISH_AGENT_REMINDER 才能使用

2、应用需要获取用户授权才能发送通知。在通知发布前调用 requestEnableNotification() 方法

json 复制代码
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.PUBLISH_AGENT_REMINDER" //允许当前应用委托鸿蒙系统发起一个通知(称为代理提醒)
      }
    ]
  }
}
示例
ts 复制代码
import { notificationManager } from '@kit.NotificationKit'
import { common } from '@kit.AbilityKit'
import { reminderAgentManager } from '@kit.BackgroundTasksKit'
import { JSON } from '@kit.ArkTS'

@Entry
@Component
struct Index {
  //页面即将显示时,弹出提醒用户允许当前应用发起通知或代理通知 ------ 类似于用户级权限授权,但代码不一样
  async onPageShow() {
    if (!notificationManager.isNotificationEnabledSync()) {
      console.log('--当前应用 尚未 向用户申请过"发起通知"弹窗')
      let ctx = getContext()  as  common.UIAbilityContext
      await notificationManager.requestEnableNotification(ctx)
      console.log('--当前应用 成功 获得了用户的通知弹窗许可')
    }else {
      console.log('--当前应用 已经 向用户申请过"发起通知"弹窗,可能通过了,也可能是未通过')
    }
  }

  build() {
    Column({ space: 10 }) {
      Text('后台任务之四:代理提醒')
        .fontSize(30)

      Button('1.申请发布一个代理提醒 ------ 倒计时类型').onClick(async _ => {
        let req:reminderAgentManager.ReminderRequestTimer  = {
          reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_TIMER,  //提醒类型:倒计时
          triggerTimeInSeconds: 15,     //多少秒钟后触发提醒
          title: '温馨提示',              //通知标题
          content: '距离吃完饭已经2个小时,可以吃药了',
          wantAgent: {                  //通知被点击后,拉起哪个UIAbility
            pkgName: 'com.example.quanguokefei',
            abilityName: 'EntryAbility'
          }
        }
        try{
          let rid = await reminderAgentManager.publishReminder(req)
          console.log('--代理提醒发布完成,提醒的编号:', rid)
        }catch(err){
          console.log('--代理提醒发布失败', JSON.stringify(err))
          //提醒:2024年10月28日之后,华为把应用可发布的代理提醒数量降为:0
        }
      })

      Button('2.申请发布一个代理提醒 ------ 日历类型').onClick(async _ => {
        let req:reminderAgentManager.ReminderRequestCalendar  = {
          reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_CALENDAR,
          dateTime: {year:2025, month:12, day:12, hour:0, minute:0, second:0},  //必需是未来时间
          title: '抢券提示',
          content: '双12活动正式开始!!!',
          wantAgent: {
            pkgName: 'com.example.quanguokefei',
            abilityName: 'EntryAbility'
          },
        }
        try{
          let rid = await reminderAgentManager.publishReminder(req)
          console.log('--代理提醒发布完成,提醒的编号:', rid)
        }catch(err){
          console.log('--代理提醒发布失败', JSON.stringify(err))
          //提醒:2024年10月28日之后,华为把应用可发布的代理提醒数量降为:0
        }
      })

      Button('3.申请发布一个代理提醒 ------ 闹钟类型').onClick(async _ => {
        let req:reminderAgentManager.ReminderRequestAlarm  = {
          reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM,
          hour: 8,
          minute: 0,
          title: '温馨提示',
          content: '早上8点了,该起床了',
          wantAgent: {
            pkgName: 'com.example.quanguokefei',
            abilityName: 'EntryAbility'
          },
        }
        try{
          let rid = await reminderAgentManager.publishReminder(req)
          console.log('--代理提醒发布完成,提醒的编号:', rid)
        }catch(err){
          console.log('--代理提醒发布失败', JSON.stringify(err))
          //提醒:2024年10月28日之后,华为把应用可发布的代理提醒数量降为:0
        }
      })
    }
    .height('100%')
    .width('100%')
    .padding(10)
  }
}

四大类后台任务对比

任务类型 数量限制 时长限制 任务内容 失效性
短时任务 3 3min/单任务,10min/所有任务 无限制 立即执行
长时任务 1 无限制 七大类 立即执行
延迟任务 10 m/单任务 只有四类不允许 未来条件满足时执行
代理提醒 30(需申请) 仅能发提醒 仅能发提醒 未来条件满足时发提醒
相关推荐
lqj_本人13 分钟前
UniApp 实现的文件预览与查看功能#三方框架 #Uniapp
uni-app·harmonyos
ChinaDragonDreamer4 小时前
HarmonyOS:使用PickerController将编辑后的图片替换原图
harmonyos·鸿蒙
HMS Core4 小时前
【FAQ】HarmonyOS SDK 闭源开放能力 —Vision Kit (3)
华为·harmonyos
bestadc5 小时前
鸿蒙 Location Kit(位置服务)
harmonyos
爱笑的眼睛115 小时前
HarmonyOS Navigation组件深度解析与应用实践
harmonyos·harmonyos next
鸿蒙布道师5 小时前
鸿蒙NEXT开发动画案例9
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
Bruce_Liuxiaowei13 小时前
HarmonyOS NEXT~鸿蒙应用上架指南:HarmonyOS应用发布全流程解析
华为·harmonyos
lqj_本人13 小时前
鸿蒙OS&UniApp开发的商品详情展示页面(鸿蒙系统适配版)#三方框架 #Uniapp
华为·uni-app·harmonyos
魔术师ID14 小时前
HarmonyOS开发样式布局
华为·harmonyos