HarmonyOS NEXT 后台代理提醒(闹钟)开发完整教程
用于调用系统闹钟设置提醒,同时推送消息通知。
·
HarmonyOS NEXT 后台代理提醒(闹钟)开发完整教程
前言
本文详细介绍如何在 HarmonyOS NEXT 应用中使用后台代理提醒(Reminder Agent)功能,实现类似闹钟的定时提醒功能。即使应用被关闭,系统也会在指定时间弹出通知提醒用户。
本教程适用场景:
- 日程提醒
- 任务提醒
- 吃药提醒
- 定时打卡提醒
- 其他需要定时通知的场景
一、功能介绍
1.1 什么是后台代理提醒
后台代理提醒(Reminder Agent)是 HarmonyOS 提供的系统级定时提醒服务。与普通的定时器不同,它具有以下特点:
- 系统级服务:由系统管理,不受应用进程影响
- 应用关闭后仍有效:即使用户关闭应用,提醒依然会在指定时间触发
- 支持多种提醒类型:日历提醒、闹钟提醒、倒计时提醒
- 丰富的交互:支持响铃、振动、通知栏显示、按钮操作
1.2 提醒类型
| 类型 | 说明 | 适用场景 |
|---|---|---|
| REMINDER_TYPE_CALENDAR | 日历提醒,指定具体日期时间 | 日程、预约、纪念日 |
| REMINDER_TYPE_ALARM | 闹钟提醒,支持重复 | 每日闹钟、周期性提醒 |
| REMINDER_TYPE_TIMER | 倒计时提醒 | 计时器、短时间提醒 |
二、开发准备
2.1 配置权限
在 module.json5 中添加后台代理提醒权限:
entry/src/main/module.json5
{
"module": {
"name": "entry",
"type": "entry",
"requestPermissions": [
{
"name": "ohos.permission.PUBLISH_AGENT_REMINDER",
"reason": "$string:reminder_permission_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
]
}
}
2.2 添加权限说明字符串
entry/src/main/resources/base/element/string.json
{
"string": [
{
"name": "reminder_permission_reason",
"value": "用于设置定时提醒通知"
}
]
}
2.3 导入模块
import { reminderAgentManager } from '@kit.BackgroundTasksKit';
import { notificationManager } from '@kit.NotificationKit';
import { BusinessError } from '@kit.BasicServicesKit';
三、设置日历提醒
日历提醒是最常用的提醒类型,可以指定具体的年月日时分触发。
3.1 创建提醒请求
/**
* 设置日历提醒
* @param reminderId 提醒的唯一标识(用于后续取消)
* @param title 提醒标题
* @param content 提醒内容
* @param triggerTime 触发时间(毫秒时间戳)
*/
async function setCalendarReminder(
reminderId: number,
title: string,
content: string,
triggerTime: number
): Promise<number | null> {
// 1. 将时间戳转换为日期对象
const triggerDate = new Date(triggerTime);
console.info(`设置提醒: ${title}, 触发时间: ${triggerDate.toString()}`);
// 2. 检查时间是否在未来
const now = new Date();
if (triggerDate.getTime() <= now.getTime()) {
console.error('提醒时间必须在未来');
return null;
}
// 3. 创建日历提醒请求
const reminderRequest: reminderAgentManager.ReminderRequestCalendar = {
// 提醒类型:日历
reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_CALENDAR,
// 触发时间
dateTime: {
year: triggerDate.getFullYear(),
month: triggerDate.getMonth() + 1, // 月份从1开始
day: triggerDate.getDate(),
hour: triggerDate.getHours(),
minute: triggerDate.getMinutes(),
second: 0
},
// 通知内容
title: title,
content: content,
expiredContent: '提醒已过期',
snoozeContent: '点击稍后提醒',
// 通知配置
notificationId: reminderId,
slotType: notificationManager.SlotType.SOCIAL_COMMUNICATION,
// 延迟提醒配置
snoozeTimes: 2, // 最多延迟2次
timeInterval: 5 * 60, // 延迟间隔5分钟(单位:秒)
// 操作按钮
actionButton: [
{
title: '关闭',
type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE
},
{
title: '稍后提醒',
type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE
}
],
// 点击通知后打开的页面
wantAgent: {
pkgName: 'com.example.myapp', // 替换为你的包名
abilityName: 'EntryAbility'
},
// 响铃时长(秒)
ringDuration: 10
};
// 4. 发布提醒
try {
const publishedId = await reminderAgentManager.publishReminder(reminderRequest);
console.info(`提醒发布成功,系统分配ID: ${publishedId}`);
return publishedId;
} catch (err) {
const error = err as BusinessError;
console.error(`发布提醒失败: ${error.code} - ${error.message}`);
return null;
}
}
3.2 使用示例
// 设置一个10分钟后的提醒
const triggerTime = Date.now() + 10 * 60 * 1000; // 10分钟后
const systemId = await setCalendarReminder(
1001, // 自定义ID
'会议提醒', // 标题
'10分钟后有一个重要会议', // 内容
triggerTime // 触发时间
);
if (systemId !== null) {
console.info(`提醒设置成功,系统ID: ${systemId}`);
// 保存 systemId,用于后续取消提醒
}
四、设置闹钟提醒(支持重复)
闹钟提醒适合需要周期性重复的场景,如每日闹钟、工作日提醒等。
4.1 创建闹钟提醒
/**
* 设置闹钟提醒(支持重复)
* @param reminderId 提醒ID
* @param title 标题
* @param content 内容
* @param hour 小时(0-23)
* @param minute 分钟(0-59)
* @param daysOfWeek 重复的星期几(1-7,1代表周一)
*/
async function setAlarmReminder(
reminderId: number,
title: string,
content: string,
hour: number,
minute: number,
daysOfWeek: number[]
): Promise<number | null> {
console.info(`设置闹钟: ${title}, 时间: ${hour}:${minute}, 重复: ${daysOfWeek}`);
// 创建闹钟提醒请求
const reminderRequest: reminderAgentManager.ReminderRequestAlarm = {
// 提醒类型:闹钟
reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM,
// 触发时间(每天的几点几分)
hour: hour,
minute: minute,
// 重复的星期几(1-7,1代表周一,7代表周日)
// 空数组表示只响一次
daysOfWeek: daysOfWeek,
// 通知内容
title: title,
content: content,
// 通知配置
notificationId: reminderId,
slotType: notificationManager.SlotType.SOCIAL_COMMUNICATION,
// 操作按钮
actionButton: [
{
title: '关闭',
type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE
},
{
title: '稍后提醒',
type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE
}
],
// 延迟配置
snoozeTimes: 3,
timeInterval: 5 * 60,
// 点击动作
wantAgent: {
pkgName: 'com.example.myapp',
abilityName: 'EntryAbility'
},
ringDuration: 30 // 响铃30秒
};
try {
const publishedId = await reminderAgentManager.publishReminder(reminderRequest);
console.info(`闹钟设置成功,系统ID: ${publishedId}`);
return publishedId;
} catch (err) {
const error = err as BusinessError;
console.error(`设置闹钟失败: ${error.code} - ${error.message}`);
return null;
}
}
4.2 使用示例
// 设置工作日早上8点的闹钟
const systemId = await setAlarmReminder(
2001, // 自定义ID
'起床闹钟', // 标题
'该起床上班了!', // 内容
8, // 8点
0, // 0分
[1, 2, 3, 4, 5] // 周一到周五
);
// 设置每天晚上10点的提醒
const systemId2 = await setAlarmReminder(
2002,
'睡眠提醒',
'该休息了,早睡早起身体好',
22,
0,
[1, 2, 3, 4, 5, 6, 7] // 每天
);
// 设置只响一次的闹钟(不重复)
const systemId3 = await setAlarmReminder(
2003,
'一次性提醒',
'这是一个只响一次的提醒',
14,
30,
[] // 空数组表示不重复
);
五、设置倒计时提醒
倒计时提醒适合短时间的计时场景,如煮饭计时、运动计时等。
5.1 创建倒计时提醒
/**
* 设置倒计时提醒
* @param reminderId 提醒ID
* @param title 标题
* @param content 内容
* @param countdownSeconds 倒计时秒数
*/
async function setTimerReminder(
reminderId: number,
title: string,
content: string,
countdownSeconds: number
): Promise<number | null> {
console.info(`设置倒计时: ${title}, ${countdownSeconds}秒后提醒`);
// 创建倒计时提醒请求
const reminderRequest: reminderAgentManager.ReminderRequestTimer = {
// 提醒类型:倒计时
reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_TIMER,
// 倒计时时长(秒)
triggerTimeInSeconds: countdownSeconds,
// 通知内容
title: title,
content: content,
// 通知配置
notificationId: reminderId,
slotType: notificationManager.SlotType.SOCIAL_COMMUNICATION,
// 操作按钮
actionButton: [
{
title: '关闭',
type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE
}
],
// 点击动作
wantAgent: {
pkgName: 'com.example.myapp',
abilityName: 'EntryAbility'
},
ringDuration: 15
};
try {
const publishedId = await reminderAgentManager.publishReminder(reminderRequest);
console.info(`倒计时设置成功,系统ID: ${publishedId}`);
return publishedId;
} catch (err) {
const error = err as BusinessError;
console.error(`设置倒计时失败: ${error.code} - ${error.message}`);
return null;
}
}
5.2 使用示例
// 设置5分钟倒计时
const systemId = await setTimerReminder(
3001,
'计时结束',
'5分钟倒计时已结束',
5 * 60 // 300秒
);
// 设置30秒倒计时
const systemId2 = await setTimerReminder(
3002,
'泡面好了',
'泡面时间到,可以开吃了!',
30
);
六、管理提醒
6.1 取消单个提醒
/**
* 取消指定的提醒
* @param reminderId 系统分配的提醒ID(publishReminder返回的ID)
*/
async function cancelReminder(reminderId: number): Promise<boolean> {
console.info(`取消提醒: ${reminderId}`);
try {
await reminderAgentManager.cancelReminder(reminderId);
console.info('取消提醒成功');
return true;
} catch (err) {
const error = err as BusinessError;
console.error(`取消提醒失败: ${error.code} - ${error.message}`);
return false;
}
}
6.2 取消所有提醒
/**
* 取消当前应用的所有提醒
*/
async function cancelAllReminders(): Promise<boolean> {
console.info('取消所有提醒');
try {
await reminderAgentManager.cancelAllReminders();
console.info('取消所有提醒成功');
return true;
} catch (err) {
const error = err as BusinessError;
console.error(`取消所有提醒失败: ${error.code} - ${error.message}`);
return false;
}
}
6.3 获取所有有效提醒
/**
* 获取当前应用的所有有效提醒
*/
async function getAllReminders(): Promise<reminderAgentManager.ReminderRequest[]> {
console.info('获取所有提醒');
try {
const reminders = await reminderAgentManager.getValidReminders();
console.info(`当前有 ${reminders.length} 个有效提醒`);
// 遍历打印提醒信息
reminders.forEach((reminder, index) => {
console.info(`提醒${index + 1}: 类型=${reminder.reminderType}, 标题=${reminder.title}`);
});
return reminders;
} catch (err) {
const error = err as BusinessError;
console.error(`获取提醒失败: ${error.code} - ${error.message}`);
return [];
}
}
七、请求通知权限
在设置提醒之前,建议先检查并请求通知权限,否则提醒可能无法正常显示。
7.1 检查并请求权限
import { notificationManager } from '@kit.NotificationKit';
import { common } from '@kit.AbilityKit';
/**
* 检查并请求通知权限
* @param context 上下文
*/
async function requestNotificationPermission(context: common.UIAbilityContext): Promise<boolean> {
try {
// 1. 检查通知是否已启用
const isEnabled = await notificationManager.isNotificationEnabled();
console.info(`通知权限状态: ${isEnabled}`);
if (isEnabled) {
return true;
}
// 2. 请求开启通知权限
console.info('请求通知权限...');
await notificationManager.requestEnableNotification(context);
console.info('用户已授权通知权限');
return true;
} catch (err) {
const error = err as BusinessError;
console.error(`请求通知权限失败: ${error.code} - ${error.message}`);
// 用户拒绝了权限请求
return false;
}
}
7.2 在设置提醒前调用
// 在 Ability 或页面中使用
async function setupReminder(context: common.UIAbilityContext) {
// 先请求权限
const hasPermission = await requestNotificationPermission(context);
if (!hasPermission) {
console.warn('用户未授权通知权限,提醒可能无法正常显示');
// 可以提示用户去设置中开启
}
// 设置提醒
const triggerTime = Date.now() + 60 * 1000; // 1分钟后
await setCalendarReminder(1001, '测试提醒', '这是一条测试提醒', triggerTime);
}
八、完整示例:提醒管理类
将上述功能封装成一个完整的提醒管理类:
import { reminderAgentManager } from '@kit.BackgroundTasksKit';
import { notificationManager } from '@kit.NotificationKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
/**
* 提醒管理器
*/
export class ReminderManager {
private context: common.UIAbilityContext;
private bundleName: string;
constructor(context: common.UIAbilityContext, bundleName: string) {
this.context = context;
this.bundleName = bundleName;
}
/**
* 请求通知权限
*/
async requestPermission(): Promise<boolean> {
try {
const isEnabled = await notificationManager.isNotificationEnabled();
if (isEnabled) {
return true;
}
await notificationManager.requestEnableNotification(this.context);
return true;
} catch (err) {
console.error('请求通知权限失败:', err);
return false;
}
}
/**
* 设置日历提醒
*/
async setCalendarReminder(
id: number,
title: string,
content: string,
triggerTime: number
): Promise<number | null> {
const triggerDate = new Date(triggerTime);
// 检查时间
if (triggerDate.getTime() <= Date.now()) {
console.error('提醒时间必须在未来');
return null;
}
const request: reminderAgentManager.ReminderRequestCalendar = {
reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_CALENDAR,
dateTime: {
year: triggerDate.getFullYear(),
month: triggerDate.getMonth() + 1,
day: triggerDate.getDate(),
hour: triggerDate.getHours(),
minute: triggerDate.getMinutes(),
second: 0
},
title: title,
content: content,
notificationId: id,
slotType: notificationManager.SlotType.SOCIAL_COMMUNICATION,
snoozeTimes: 2,
timeInterval: 5 * 60,
actionButton: [
{ title: '关闭', type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE },
{ title: '稍后提醒', type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE }
],
wantAgent: {
pkgName: this.bundleName,
abilityName: 'EntryAbility'
},
ringDuration: 10
};
try {
const publishedId = await reminderAgentManager.publishReminder(request);
console.info(`提醒设置成功: ${publishedId}`);
return publishedId;
} catch (err) {
console.error('设置提醒失败:', err);
return null;
}
}
/**
* 设置闹钟提醒
*/
async setAlarmReminder(
id: number,
title: string,
content: string,
hour: number,
minute: number,
daysOfWeek: number[] = []
): Promise<number | null> {
const request: reminderAgentManager.ReminderRequestAlarm = {
reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM,
hour: hour,
minute: minute,
daysOfWeek: daysOfWeek,
title: title,
content: content,
notificationId: id,
slotType: notificationManager.SlotType.SOCIAL_COMMUNICATION,
snoozeTimes: 3,
timeInterval: 5 * 60,
actionButton: [
{ title: '关闭', type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_CLOSE },
{ title: '稍后提醒', type: reminderAgentManager.ActionButtonType.ACTION_BUTTON_TYPE_SNOOZE }
],
wantAgent: {
pkgName: this.bundleName,
abilityName: 'EntryAbility'
},
ringDuration: 30
};
try {
const publishedId = await reminderAgentManager.publishReminder(request);
console.info(`闹钟设置成功: ${publishedId}`);
return publishedId;
} catch (err) {
console.error('设置闹钟失败:', err);
return null;
}
}
/**
* 取消提醒
*/
async cancelReminder(reminderId: number): Promise<boolean> {
try {
await reminderAgentManager.cancelReminder(reminderId);
console.info(`取消提醒成功: ${reminderId}`);
return true;
} catch (err) {
console.error('取消提醒失败:', err);
return false;
}
}
/**
* 取消所有提醒
*/
async cancelAllReminders(): Promise<boolean> {
try {
await reminderAgentManager.cancelAllReminders();
console.info('取消所有提醒成功');
return true;
} catch (err) {
console.error('取消所有提醒失败:', err);
return false;
}
}
/**
* 获取所有有效提醒
*/
async getAllReminders(): Promise<reminderAgentManager.ReminderRequest[]> {
try {
return await reminderAgentManager.getValidReminders();
} catch (err) {
console.error('获取提醒失败:', err);
return [];
}
}
}
8.1 使用提醒管理类
// 在 EntryAbility 中初始化
export default class EntryAbility extends UIAbility {
private reminderManager: ReminderManager | null = null;
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 初始化提醒管理器
this.reminderManager = new ReminderManager(
this.context,
this.context.abilityInfo.bundleName
);
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// 请求通知权限
this.reminderManager?.requestPermission();
// ... 加载页面
}
}
// 在页面中使用
@Entry
@Component
struct ReminderPage {
private reminderManager: ReminderManager = new ReminderManager(
getContext(this) as common.UIAbilityContext,
'com.example.myapp'
);
build() {
Column() {
Button('设置10分钟后提醒')
.onClick(async () => {
const triggerTime = Date.now() + 10 * 60 * 1000;
const id = await this.reminderManager.setCalendarReminder(
1001,
'测试提醒',
'10分钟到了',
triggerTime
);
if (id) {
console.info(`提醒已设置,ID: ${id}`);
}
})
Button('设置每天8点闹钟')
.onClick(async () => {
const id = await this.reminderManager.setAlarmReminder(
2001,
'起床闹钟',
'该起床了',
8,
0,
[1, 2, 3, 4, 5, 6, 7]
);
if (id) {
console.info(`闹钟已设置,ID: ${id}`);
}
})
Button('取消所有提醒')
.onClick(async () => {
await this.reminderManager.cancelAllReminders();
})
}
}
}
九、常见问题
问题 1:提醒没有触发
可能原因:
- 未配置
ohos.permission.PUBLISH_AGENT_REMINDER权限 - 通知权限未开启
- 设置的时间已经过去
解决方案:
- 检查
module.json5中的权限配置 - 调用
requestEnableNotification请求通知权限 - 确保触发时间在未来
问题 2:取消提醒失败
可能原因:
- 使用了错误的提醒 ID
- 提醒已经触发并被系统清除
解决方案:
- 使用
publishReminder返回的系统 ID,而不是自定义 ID - 保存系统返回的 ID 用于后续操作
问题 3:应用重启后提醒丢失
说明:
后台代理提醒是系统级服务,应用重启后提醒仍然有效。如果发现提醒丢失,可能是:
- 用户手动清除了通知
- 系统重启导致提醒被清除(部分设备)
建议:
- 将提醒信息保存到本地数据库
- 应用启动时检查并重新设置必要的提醒
问题 4:提醒时间不准确
可能原因:
- 系统省电模式影响
- 时区问题
解决方案:
- 使用
Date对象处理时间,避免手动计算 - 注意月份从 0 开始(
getMonth()返回 0-11)
十、总结
本文介绍了 HarmonyOS NEXT 后台代理提醒的完整使用方法:
- 日历提醒:指定具体日期时间触发,适合日程、预约等场景
- 闹钟提醒:支持每天/每周重复,适合起床闹钟、定时任务
- 倒计时提醒:指定秒数后触发,适合计时器场景
关键点:
- 必须配置
PUBLISH_AGENT_REMINDER权限 - 建议先请求通知权限再设置提醒
- 使用系统返回的 ID 来取消提醒
- 提醒是系统级服务,应用关闭后仍然有效
希望本文对你有所帮助!
更多推荐


所有评论(0)