更新记录

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 双框架可用。

定位:不做通知样式库,不做厂商推送;专做"定时不丢"。

核心能力:

  1. 重启不丢:调度任务持久化,设备重启后自动恢复(Android BOOT_COMPLETED 重排;鸿蒙由系统提醒代理原生托管)。
  2. 精准触发:Android 12+ 精确闹钟豁免处理与自动降级、iOS UNCalendar/TimeInterval 触发器、鸿蒙 reminderAgent。
  3. 三端 + 双框架:Android / iOS / 鸿蒙;经典 uni-app 与 uni-app x 同一套接口。
  4. 就绪度诊断: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、目标页面路径),用于调度持久化与重启恢复;不上传任何数据,不含厂商推送通道,不读取通知栏内容。

常见问题(为什么不响)

  1. 授权没给:先 getReadiness() 看 notificationGranted;拒绝后引导去系统设置。
  2. Android 12+ 不准点:exactAlarmAllowed === false 说明无精确闹钟豁免,已自动降级(Doze 下有 ≥9 分钟节流)。openExactAlarmSettings() 引导用户授权;高频提醒(<9 分钟)建议配合前台保活类插件。
  3. 小米/华为/OPPO/vivo 杀后台:getReadiness().autoStartGuideUrl 会给出对应设置页 intent URI,引导用户加自启动/电池白名单。
  4. iOS 注册到第 65 条失败:系统 pending 上限 64,先 cancel 腾位或 getPendingList 清理。
  5. 鸿蒙第 31 条失败:系统提醒实例上限 30。
  6. 通知栏不显示但没报错:Android 8+ 检查渠道是否被用户关闭(系统设置 → 应用 → 通知渠道)。
  7. 重启后没响:Android 首次安装后需启动过一次应用再重启(receiver 注册随安装生效);确认未使用"强制停止"(强制停止会清除闹钟直到下次启动应用)。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

Android 使用 POST_NOTIFICATIONS、SCHEDULE_EXACT_ALARM/USE_EXACT_ALARM、RECEIVE_BOOT_COMPLETED、WAKE_LOCK;iOS 使用系统用户通知授权(UNUserNotificationCenter);鸿蒙申请通知授权与 PUBLISH_AGENT_REMINDER。不包含厂商推送通道,不读取通知栏内容。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件仅在本机保存定时提醒任务(标题、正文、触发时间、周期规则、extras、目标页面路径),用于调度持久化与设备重启后的恢复;不上传任何数据,通知点击 extras 的内容由调用方决定。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。