更新记录
1.0.0(2026-10-02)
- 首个版本:三端(Android / iOS / 鸿蒙)本地通知与定时提醒,uni-app 与 uni-app x 双框架可用,功能详见 readme。
平台兼容性
uni-app(5.24)
| Vue2 |
Vue3 |
Chrome |
Safari |
app-vue |
app-nvue |
Android |
iOS |
鸿蒙 |
| √ |
√ |
- |
- |
√ |
- |
√ |
√ |
√ |
| 微信小程序 |
支付宝小程序 |
抖音小程序 |
百度小程序 |
快手小程序 |
京东小程序 |
鸿蒙元服务 |
QQ小程序 |
飞书小程序 |
小红书小程序 |
快应用-华为 |
快应用-联盟 |
| - |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
- |
uni-app x(5.24)
| Chrome |
Safari |
Android |
iOS |
鸿蒙 |
微信小程序 |
| - |
- |
√ |
√ |
√ |
- |
其他
| 多语言 |
暗黑模式 |
宽屏模式 |
蒸汽模式 |
| × |
× |
× |
√ |
hans-local-notify 本地通知 / 定时提醒
三端(Android + iOS + 鸿蒙)本地通知与定时提醒 UTS 插件,uni-app 与 uni-app x 双框架可用。
定位:不做通知样式库,不做厂商推送;专做"定时不丢"。
核心能力:
- 重启不丢:调度任务持久化,设备重启后自动恢复(Android BOOT_COMPLETED 重排;鸿蒙由系统提醒代理原生托管)。
- 精准触发:Android 12+ 精确闹钟豁免处理与自动降级、iOS UNCalendar/TimeInterval 触发器、鸿蒙 reminderAgent。
- 三端 + 双框架:Android / iOS / 鸿蒙;经典 uni-app 与 uni-app x 同一套接口。
- 就绪度诊断:
getReadiness() 一次返回"能不能准时响"(授权 / 精确闹钟 / 电池优化 / OEM 自启动指引)。
快速开始
import { requestPermission, schedule, getReadiness } from '@/uni_modules/hans-local-notify'
// 1. 申请通知授权
requestPermission({
success: (res) => console.log('授权状态', res.status) // granted / denied / provisional / notDetermined
})
// 2. 排一个 5 秒后的一次性提醒
schedule({
id: 'demo-once',
title: '喝水提醒',
body: '该喝一杯水了',
delaySeconds: 5,
success: (id) => console.log('已排程', id),
fail: (err) => console.error(err.errCode, err.errMsg)
})
// 3. 诊断"能不能准时响"
getReadiness({
success: (r) => {
// r.notificationGranted 通知是否已授权
// r.exactAlarmAllowed Android 12+ 精确闹钟豁免(其他平台 null)
// r.batteryOptimizationIgnored 电池优化白名单(其他平台 null)
// r.autoStartGuideUrl 检测到 OEM 时的设置页跳转方案(intent: URI)
// r.pendingCount / r.platformLimit 待触发数与平台上限
}
})
回调统一主线程触发,uvue / vue 页面可直接更新状态。所有异步 API 均为 success / fail / complete 回调形态;fail 回调参数见 NotifyFail。
API
| 方法 |
说明 |
requestPermission(options) |
申请通知授权。Android 13+ POST_NOTIFICATIONS;iOS UNUserNotificationCenter(provisional: true 走临时授权);鸿蒙 requestEnableNotification 引导 |
checkPermission() |
同步读取授权状态,返回 NotifyPermissionResult(鸿蒙为最后一次已知状态,其状态 API 为异步) |
getReadiness(options) |
就绪度诊断,见上文 |
create(options) |
立即发一条通知,返回 id |
schedule(options) |
注册定时/周期提醒,返回 id。任务持久化,重启后由插件恢复 |
cancel(options) / cancelAll(options) |
取消单条 / 全部(含 iOS/鸿蒙系统侧注册) |
getPendingList(options) |
待触发队列,元素形状见 NotifyPendingItem |
onNotificationClick(cb) |
注册点击回调(重复注册只保留最后一个;冷启动点击在注册时补发) |
offNotificationClick(cb?) |
注销回调,不传参注销全部 |
createChannel(options) |
Android 8+ 通知渠道;iOS/鸿蒙 no-op success |
openExactAlarmSettings() |
Android 12+ 跳"闹钟和提醒"授权页,其他平台返回 false |
openBatteryOptimizationSettings() |
跳电池优化白名单列表页(无额外权限),其他平台返回 false |
schedule 参数(NotifyScheduleOptions)
{
id?: string, // 缺省自动生成;持久化与 cancel 的主键
title: string,
subtitle?: string, // iOS subtitle / Android 子文本
body: string,
badge?: number, // iOS 角标
sound?: string, // iOS 生效(已注册铃声名,缺省系统默认);Android 8+ 由渠道决定
vibrate?: boolean, // 缺省 true
vibratePattern?: number[],// Android 震动节奏(毫秒 on/off 交替)
channelId?: string, // Android 渠道,缺省插件默认渠道
extras?: Map<string, string>, // 点击回调原样带回
pagePath?: string, // 点击后要打开的应用内页面
triggerAt?: number, // 绝对触发时间(ms) —— 与 delaySeconds 二选一,都传以 triggerAt 为准
delaySeconds?: number, // 相对延迟(秒)
repeatRule?: { // 缺省一次性
kind: 'once' | 'daily' | 'weekly' | 'monthly' | 'interval',
weekdays?: number[], // weekly:1=周日 ... 7=周六(对齐 iOS)
daysOfMonth?: number[], // monthly:1~31
intervalSeconds?: number // interval:最小 60
},
maxOccurrences?: number, // 周期上限,缺省无限
success / fail / complete
}
create 参数(NotifyCreateOptions)
与 schedule 共用全部内容字段(id / title / subtitle / body / badge / sound / vibrate / vibratePattern / channelId / extras / pagePath),没有 triggerAt / delaySeconds / repeatRule / maxOccurrences。id 不传由平台自动生成,返回值即最终 id。
其他 API 参数
| 参数 |
字段 |
requestPermission |
provisional?: boolean(仅 iOS:传 true 尝试临时授权,通知静默展示且不弹窗打扰;缺省 false) |
cancel |
id: string(必填;任务不存在报 9013006) |
cancelAll |
无参数 |
getPendingList |
无参数 |
createChannel |
id: string(必填)、name: string(必填)、channelDescription?: string、importance?: NotifyChannelImportance(缺省 'default')、enableVibration?: boolean(缺省 true)、enableSound?: boolean(缺省 true) |
Android 8+ 渠道创建后 importance / 声音 / 震动 不可再编程修改(仅用户可改),重复调用同名渠道只更新 name/description。
周期语义
- 本地时间:daily/weekly/monthly 以首次触发时刻的时:分:秒为锚,跨时区/DST 保持"本地时间"语义(Android 收到时间/时区变化广播后自动重排)。
- monthly 月末兜底:不存在的日期(如 2 月 31 日)按当月最后一天触发。
类型参考
数据类型
NotifyReadinessResult(getReadiness success 回调)
| 字段 |
类型 |
说明 |
notificationGranted |
boolean |
通知是否已授权 |
exactAlarmAllowed |
boolean \| null |
Android 12+ 精确闹钟豁免;其他平台 null |
batteryOptimizationIgnored |
boolean \| null |
Android 电池优化白名单状态;其他平台 null |
autoStartGuideUrl |
string \| null |
检测到 OEM(小米/华为/OPPO/vivo 等)时的设置页跳转方案(intent: URI),无匹配为 null |
pendingCount |
number |
当前待触发任务数 |
platformLimit |
number \| null |
平台待触发上限:iOS 64 / 鸿蒙 30 / Android null |
NotifyPendingItem(getPendingList success 回调元素)
| 字段 |
类型 |
说明 |
id |
string |
任务 id |
title |
string |
标题 |
body |
string |
正文 |
nextTriggerAt |
number \| null |
下次触发时间(Unix 毫秒);无法确定时为 null |
repeatRule |
NotifyRepeatRule \| null |
周期规则,一次性为 null |
extras |
Map<string, string> \| null |
自定义键值(ES Map,取值用 .get() / .forEach) |
pagePath |
string \| null |
点击后要打开的应用内页面 |
uni-app x 侧该回调参数声明为 Array<any>(iOS 桥接兼容),元素按本表形状取字段即可。
NotifyClickEvent(onNotificationClick 回调)
| 字段 |
类型 |
说明 |
id |
string |
通知/任务 id |
pagePath |
string \| null |
注册时传入的页面路径,未传为 null |
extras |
Map<string, string> \| null |
注册时传入的自定义键值,原样带回 |
NotifyFail(所有 fail 回调参数,extends IUniError)
| 字段 |
类型 |
说明 |
errSubject |
string |
固定 'hans-local-notify' |
errCode |
number |
9013xxx,见错误码表 |
errMsg |
string |
人类可读错误信息 |
枚举
| 类型 |
取值 |
说明 |
NotifyPermissionStatus |
'granted' \| 'denied' \| 'provisional' \| 'notDetermined' |
授权状态;provisional 仅 iOS 临时授权会出现 |
NotifyRepeatKind |
'once' \| 'daily' \| 'weekly' \| 'monthly' \| 'interval' |
周期规则种类 |
NotifyChannelImportance |
'default' \| 'high' \| 'low' \| 'min' |
Android 渠道重要性,映射 IMPORTANCE_DEFAULT/HIGH/LOW/MIN;插件默认渠道为 high |
平台差异(重要)
| 能力 |
Android |
iOS |
鸿蒙 |
| 重启恢复 |
BOOT_COMPLETED 重排 |
系统通知原生存活 |
系统提醒代理原生托管 |
| 精确触发 |
精确闹钟豁免,无豁免自动降级(Doze 下 ≥9 分钟节流) |
系统调度,误差秒级 |
系统提醒代理 |
| pending 上限 |
无限制 |
64(超限报 9013007) |
30(超限报 9013007) |
| 点击回调 |
✅ 含冷启动补发 |
✅ 含冷启动补发 |
暂不触发(系统提醒点击直接打开应用,插件无点击钩子) |
| pagePath 跳转 |
由宿主在 onNotificationClick 回调中 uni.navigateTo(三端一致;点击热启动由插件 moveTaskToFront 前置任务栈) |
同左 |
不适用(无点击回调) |
| interval 首次触发 |
对齐 triggerAt / delaySeconds |
从注册时刻起 +interval(系统限制) |
按 delaySeconds 首触发 |
| maxOccurrences |
✅ 精确计数 |
不生效(系统不回调投递事件) |
interval 未传时不限制 |
| 声音/震动控制权 |
Android 8+ 由渠道决定,逐条设置仅 8 以下生效 |
逐条生效 |
由系统提醒代理决定 |
| checkPermission |
实时(33+ 运行时权限) |
最后已知(首次调用后刷新) |
最后已知(其状态 API 为异步) |
错误码(9013xxx)
| 码 |
含义 |
| 9013001 |
当前平台不支持 |
| 9013002 |
通知参数不合法(缺 title/body、过去时间等) |
| 9013003 |
通知授权未授予 |
| 9013004 |
通知创建失败 |
| 9013005 |
调度失败 |
| 9013006 |
待触发任务不存在 |
| 9013007 |
平台容量上限(iOS 64 / 鸿蒙 30) |
| 9013008 |
任务持久化失败 |
| 9013009 |
打开系统设置失败 |
| 9013010 |
通知渠道创建失败 |
| 9013011 |
鸿蒙提醒代理错误 |
| 9013012 |
周期规则不合法(weekly 缺 weekdays / interval < 60 等) |
权限与数据说明
- Android:POST_NOTIFICATIONS、SCHEDULE_EXACT_ALARM / USE_EXACT_ALARM(闹钟提醒类应用政策允许)、RECEIVE_BOOT_COMPLETED、WAKE_LOCK、REORDER_TASKS(点击通知热启动前置任务栈,normal 级)。
- iOS:系统用户通知授权(UNUserNotificationCenter)。
- 鸿蒙:通知授权 + PUBLISH_AGENT_REMINDER。
- 数据仅保存在本机(任务标题、正文、触发时间、周期规则、extras、目标页面路径),用于调度持久化与重启恢复;不上传任何数据,不含厂商推送通道,不读取通知栏内容。
常见问题(为什么不响)
- 授权没给:先
getReadiness() 看 notificationGranted;拒绝后引导去系统设置。
- Android 12+ 不准点:
exactAlarmAllowed === false 说明无精确闹钟豁免,已自动降级(Doze 下有 ≥9 分钟节流)。openExactAlarmSettings() 引导用户授权;高频提醒(<9 分钟)建议配合前台保活类插件。
- 小米/华为/OPPO/vivo 杀后台:
getReadiness().autoStartGuideUrl 会给出对应设置页 intent URI,引导用户加自启动/电池白名单。
- iOS 注册到第 65 条失败:系统 pending 上限 64,先
cancel 腾位或 getPendingList 清理。
- 鸿蒙第 31 条失败:系统提醒实例上限 30。
- 通知栏不显示但没报错:Android 8+ 检查渠道是否被用户关闭(系统设置 → 应用 → 通知渠道)。
- 重启后没响:Android 首次安装后需启动过一次应用再重启(receiver 注册随安装生效);确认未使用"强制停止"(强制停止会清除闹钟直到下次启动应用)。