更新记录

1.0.0(2026-10-28)

首个版本。按插件市场《应用消息通知插件(多种样式,新增支持常驻通知模式)Ba-Notify》的参数表与回调字段 1:1 复刻,并把只支持 Android 的能力扩到 Android + iOS 双端,全源码交付。

  1. 七种样式 notifyType:0 普通 / 1 大图 / 2 按钮 / 3 HeadUp / 4 消息盒子 / 5 多行 / 6 进度。
  2. 常驻通知 ongoing:true 在 Android 8+ 同时下 FLAG_ONGOING_EVENT 与 FLAG_NO_CLEAR,侧滑删不掉。
  3. 渠道与 ID 分类管理:clear() 清全部、clearById({ID}) 清单条;同 ID 再次 show() 刷新同一条通知。
  4. 权限:isNotifyEnabled() 查询、goSetNotify() 跳系统设置、requestNotifyPermission() 申请 Android 13+ 的 POST_NOTIFICATIONS 与 iOS 通知授权。
  5. 点击回传字段与原插件一致:BaNotifyChannelID / BaNotifyChannelName / BaNotifyID / notifyType / extend,点按钮额外带 Notify-Click(leftBtn / rightBtn)。
  6. Android 走 plus.runtime.arguments + plus.globalEvent(newintent);iOS 走 onClick() / getLastClick() / clearLastClick(),并在 applicationDidFinishLaunching 前装好通知代理,冷启动点击不丢。
  7. iOS 差异已明确降级并写进文档:进度条转文字进度条、消息盒子转多行正文、渠道转 threadIdentifier 归组;ongoing / autoCancel / ticker / isVibrate / isLights / smallIcon 在 iOS 无对应能力。
  8. 空值容错:UTS 可选属性未赋值会序列化成 null,双端内核统一回落默认值,不会把 "null" 显示到通知上。
  9. 已实测 Android 13(API 33)、Android 16(API 36),覆盖七种样式、常驻、模糊进度、静音渠道、单条清除、全清、权限查询、跳设置、正文点击与按钮点击回传;iOS 侧完成类型检查与 51 项参数/点击回传逻辑回归。

平台兼容性

uni-app(4.25)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
√ √ × × √ - 5.0 12 ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

zeng-notify · 应用消息通知(多种样式 + 常驻通知,Android / iOS 双端)

参数、方法名、点击回传字段与「应用消息通知插件(多种样式,新增支持常驻通知模式)Ba-Notify」逐一对齐, 原来只支持 Android,这份把 iOS 也补齐了,而且是全源码交付(Java 内核 + Swift 内核 + UTS 封装层都在包里,无混淆、无加密)。

迁移时只要把这一行换掉,其余代码不用动:

// 旧
const notify = uni.requireNativePlugin('Ba-Notify')
// 新
import { notify } from '@/uni_modules/zeng-notify'

平台兼容性

平台 支持 最低版本 说明
Android ✅ API 21(Android 5.0) 七种样式全部真机实测
iOS ✅ iOS 10 用 UNUserNotificationCenter 本地通知,样式差异见「iOS 与 Android 的差异」
HarmonyOS ❌ - 未实现
H5 / 小程序 ❌ - 系统通知栏能力,Web 侧没有

已实测环境:Android 13(API 33)与 Android 16(API 36)模拟器,覆盖七种样式、常驻、模糊进度、静音渠道、clearById、clear、isNotifyEnabled、goSetNotify、按钮点击与正文点击的参数回传。

iOS 侧已完成的验证:ZengNotifyNative.swift 通过 Swift 类型检查,并有 51 项参数解析与点击回传字段的逻辑回归全部通过。作者环境没有可用来跑画面的 iOS 真机,因此 iOS 的画面效果请以你自己在 HBuilderX 自定义基座上的运行为准;若与文档不符,欢迎在插件详情页反馈,作者会跟进。

快速开始

  1. 把 uni_modules/zeng-notify 整个目录拷进你项目的 uni_modules/ 下。
  2. HBuilderX 里 运行 → 运行到手机或模拟器 → 制作自定义调试基座(UTS 插件必须自定义基座,标准基座里没有我们的原生代码)。
  3. 运行到真机后把右上角基座切成「自定义调试基座」。手机上装过旧基座先卸载,否则签名冲突。
  4. Android 13+ 需要先申请通知权限,iOS 首次 show() 会自动弹授权。
import { notify } from '@/uni_modules/zeng-notify'

// Android 13+ 申请 POST_NOTIFICATIONS;iOS 直接弹系统授权
notify.requestNotifyPermission((res) => {
  console.log('已发起授权', res)
})

notify.isNotifyEnabled((res) => {
  if (!res.isNotifyEnabled) {
    uni.showModal({
      title: '通知未开启',
      content: '请到系统设置里打开通知',
      success: (r) => { if (r.confirm) notify.goSetNotify() }
    })
  }
})

方法

方法 说明 Android iOS
show(options, callback?) 显示通知,回调 { code, ID, channelID, channelName, notifyType, message } ✅ ✅
isNotifyEnabled(callback) 查询通知权限,回调 { code, isNotifyEnabled, ... } ✅ ✅
goSetNotify() 跳系统通知设置页 ✅(直达本应用通知页) ✅(只能到本应用设置页,通知开关在该页内)
clear() 清空本应用全部通知 ✅ ✅(同时清掉待推送)
clearById({ ID }) 按通知 ID 清除单条 ✅ ✅
requestNotifyPermission(callback?) 主动申请权限 ✅(API 33+ 弹系统框) ✅(requestAuthorization)
getLastClick() 读最近一次点击参数,没有返回 null ✅ ✅
clearLastClick() 清掉缓存的点击参数 空实现(Android 参数挂在启动 Intent 上,不落地缓存) ✅
onClick(callback) 接收点击 / 按钮事件 见下方说明 ✅

Android 的点击事件和原插件一样走 plus.runtime.arguments + plus.globalEvent('newintent'), 因为 uni-app 的安卓容器就是这样把参数交给页面的;onClick() 在 Android 只保留同名方法(会打一条 warn), 方便一份页面代码在双端跑。iOS 没有 plus 的 newintent 通道,用 onClick()。

show() 参数

notifyType 决定样式:0 普通、1 大图、2 按钮、3 HeadUp、4 消息盒子、5 多行、6 进度。

字段 类型 默认 说明 Android iOS
notifyType number 0 样式类型 ✅ ✅
channelID string "1" 渠道 id,同 id 复用同一渠道 ✅ 归组用(threadIdentifier)
channelName string "默认" 渠道显示名 ✅ 仅记录在点击参数里
ID number 0 通知 id,同 id 再次 show 会刷新同一条 ✅ ✅
isSound boolean true 是否有声音 ✅ ✅
isVibrate boolean true 是否震动 ✅ ❌ 系统不支持单独控制
isLights boolean true 是否呼吸灯 ✅ ❌ 无呼吸灯
ticker string "" 状态栏滚动提示文字 ✅ ❌ iOS 无 ticker
title string "" 标题 ✅ ✅
content string "" 内容,多行可用 \n ✅ ✅
thumbUrl string "" 缩略图本地绝对路径 ✅ ✅ 作为附件
bigUrl string "" 大图本地绝对路径 ✅ ✅ 作为附件
leftBtnText string "" 左按钮文字 ✅ ✅(长按/下拉出动作)
rightBtnText string "" 右按钮文字 ✅ ✅(同上)
msgList string[] [] 消息盒子每行文字 ✅ 最多 7 行 ✅ 拼进正文,最多 5 行
maxProgress number 100 进度最大值 ✅ ✅(换算成百分比)
progress number 0 当前进度 ✅ ✅(文字进度条)
indeterminate boolean false 模糊进度(不显示百分比) ✅ ✅(显示「处理中」)
finishText string "" 进度跑满后的文案 ✅ ✅
autoCancel boolean true 点击后自动消失 ✅ ❌ iOS 点击必消失,无法保留
ongoing boolean false 常驻通知(侧滑不可删) ✅ ❌ iOS 无常驻概念
extend string "" 附加参数,原样出现在点击参数里 ✅ ✅
smallIcon string "ba_notify_icon" 通知栏小图标资源名,找不到时回落应用图标 ✅ — iOS 固定用 App 图标

图片只接受本地绝对路径,不接受网络地址(双端一致)。 想显示网络图,先用 uni.downloadFile 下来再把 tempFilePath 传进来。 iOS 侧还支持 file:// 前缀和百分号编码路径。 Android 的渠道属性(声音 / 震动 / 呼吸灯)只在渠道第一次创建时生效,之后改参数不会动已建渠道——这是系统限制,和原插件一致。

七种样式示例

// 0 普通
notify.show({ notifyType: 0, channelID: '0', channelName: '普通通知', ID: 0,
  title: '普通通知', content: 'content', extend: '附加参数' })

// 1 大图(bigUrl 必填本地路径,thumbUrl 是右上角小图)
notify.show({ notifyType: 1, channelID: '1', channelName: '大图通知', ID: 1,
  title: '大图通知', content: 'content', bigUrl: '/sdcard/.../big.png', thumbUrl: '/sdcard/.../thumb.png' })

// 2 按钮
notify.show({ notifyType: 2, channelID: '2', channelName: '按钮通知', ID: 2,
  title: '按钮通知', content: 'content', leftBtnText: '左按钮', rightBtnText: '右按钮', extend: '附加参数' })

// 3 HeadUp(渠道重要性 HIGH,会横幅弹出)
notify.show({ notifyType: 3, channelID: '3', channelName: 'HeadUp', ID: 3,
  title: 'HeadUp', content: 'content', leftBtnText: '左按钮', rightBtnText: '右按钮', thumbUrl: '/sdcard/.../thumb.png' })

// 4 消息盒子
notify.show({ notifyType: 4, channelID: '4', channelName: '消息盒子', ID: 4,
  title: 'mailbox', content: 'content', msgList: ['消息1', '消息2', '消息3'], thumbUrl: '/sdcard/.../thumb.png' })

// 5 多行
notify.show({ notifyType: 5, channelID: '5', channelName: '多行通知', ID: 5,
  title: '多行通知', content: '《一代人》\n黑夜给了我黑色的眼睛\n我却用它寻找光明' })

// 6 进度(同一个 ID 反复 show 就是刷新进度;跑满显示 finishText)
notify.show({ notifyType: 6, channelID: '6', channelName: '进度通知', ID: 6,
  title: '下载文件', content: '正在下载', maxProgress: 100, progress: 40, finishText: '下载完成' })

// 常驻通知(侧滑删不掉,只有 clear/clearById 能清)
notify.show({ notifyType: 0, channelID: '7', channelName: '常驻渠道', ID: 7,
  title: '常驻通知', content: '侧滑删不掉', ongoing: true, autoCancel: false, isSound: false })

点击事件参数

点整条通知、点左按钮、点右按钮,回传的都是同一组字段(code 一类的返回字段不在这张表里):

字段 说明
BaNotifyChannelID 渠道 id
BaNotifyChannelName 渠道名
BaNotifyID 通知 id(字符串)
notifyType 样式类型(字符串)
extend 你传的附加参数;没传就没有这个键
Notify-Click 只有点按钮时才有:leftBtn / rightBtn;点整条没有这个键
leftBtnText / rightBtnText 传了按钮文字才会带

Android 接法(与原插件一致)

// 冷启动:参数在 plus.runtime.arguments 里
const args = plus.runtime.arguments
if (args) {
  const p = JSON.parse(args)
  console.log('点了通知', p.BaNotifyID, p['Notify-Click'])
}
// 应用在后台 / 前台:走 newintent
plus.globalEvent.addEventListener('newintent', () => {
  const p = JSON.parse(plus.runtime.arguments || '{}')
  console.log('newintent', p)
})

iOS 接法

import { notify } from '@/uni_modules/zeng-notify'

notify.onClick((p) => {
  console.log('iOS 点击', p.BaNotifyID, p['Notify-Click'])
  notify.clearLastClick()
})

// 冷启动可能早于 onClick 注册,用 getLastClick 兜底
const last = notify.getLastClick()
if (last) {
  console.log('补处理冷启动点击', last)
  notify.clearLastClick()
}

iOS 的点击参数会缓存在 UserDefaults(com.zeng.notify.lastClick), 插件在 applicationDidFinishLaunching 之前就装好了 UNUserNotificationCenter 代理,所以冷启动点通知不会丢事件。

iOS 与 Android 的差异

iOS 系统本身没有这些能力,插件按「能对齐就对齐、对齐不了就退化」处理:

能力 Android iOS 实际表现
通知渠道 真渠道,可在系统设置里单独关 用 threadIdentifier 归组,系统设置里没有渠道开关
进度条 notifyType=6 原生进度条 文字进度条 ▰▰▰▰▱▱▱▱▱▱ 40%,indeterminate 显示「处理中」,跑满显示 finishText
消息盒子 notifyType=4 InboxStyle 逐行展开 最多 5 行拼进正文,副标题写「N 条消息」
大图 notifyType=1 BigPictureStyle 展开即大图 作为通知附件,长按 / 下滑展开查看
按钮 notifyType=2 通知上直接显示按钮 注册为通知动作(category),长按 / 下拉展开后可点
常驻 ongoing FLAG_NO_CLEAR,侧滑删不掉 ❌ 系统不允许,通知始终可滑删
autoCancel=false 点击后保留 ❌ 点击必消失
ticker / isVibrate / isLights 支持 ❌ 系统无对应 API,参数被忽略
smallIcon 支持自定义资源名 ❌ 固定显示 App 图标
前台时弹通知 支持 支持(代理里返回 banner + list + sound)

另外 iOS 的本地通知是由系统托管的:App 被杀掉之后,已经发出去的通知仍然留在通知中心,但不会再有新的; 需要「杀掉还能继续弹」的场景请配合服务端推送(unipush / APNs),不在本插件范围内。

常见问题

Q:Android 通知不显示? 先查 isNotifyEnabled。Android 13+ 必须授予 POST_NOTIFICATIONS;8.0+ 还要看对应渠道有没有被用户在系统设置里关掉。

Q:ongoing: true 还是能侧滑删掉? 本插件在 Android 8+ 上会同时下 FLAG_ONGOING_EVENT 和 FLAG_NO_CLEAR(实测 flags=0x22)。 如果仍被划掉,检查是不是又用同一个 ID 发了一条 ongoing: false 的通知——同 id 会整条替换。

Q:改了 isSound 没效果? Android 渠道属性只在渠道首次创建时生效。换个 channelID,或让用户在系统设置里改,或先删掉渠道再建。

Q:大图 / 缩略图不显示? 只接受本地绝对路径。网络图先 uni.downloadFile;相对路径(static/xx.png)需要先转成绝对路径。

Q:iOS 点了按钮没回调? onClick 只能有一个监听者,重复注册会覆盖;页面 onUnload 里记得别把回调置空后又不重注册。冷启动场景用 getLastClick() 兜底。

目录结构

zeng-notify/
├── package.json
├── readme.md
├── changelog.md
├── utssdk/
│   ├── interface.uts                参数与回调类型
│   ├── app-android/
│   │   ├── index.uts                UTS 封装层
│   │   ├── config.json              minSdk 21 / abis
│   │   ├── AndroidManifest.xml      POST_NOTIFICATIONS + VIBRATE
│   │   └── libs/zeng-notify-core.jar  编译好的 Java 内核
│   └── app-ios/
│       ├── index.uts                UTS 封装层 + NotifyHookProxy 启动钩子
│       └── ZengNotifyNative.swift   iOS 原生内核
├── native-core/
│   ├── src/com/zeng/notify/NotifyCore.java   Java 内核源码
│   └── build.sh                              javac → jar → 自动拷进 libs
└── examples/
    ├── notify-demo.vue              uni-app 示例页(七种样式全按钮)
    └── README.md                    示例搭建说明

改了 native-core/src 下的 Java 之后重新打 jar:

cd uni_modules/zeng-notify/native-core && ./build.sh

然后在 HBuilderX 里重新制作自定义基座。

隐私、权限声明

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

POST_NOTIFICATIONS:Android 13+ 弹出通知授权;VIBRATE:按 isVibrate 控制通知震动。不申请前台服务、开机自启、网络、存储等任何其他权限。

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

不采集、不上报、不联网。Android 只在应用私有目录写 SharedPreferences(渠道参数),iOS 只在 UserDefaults 写一条最近点击参数(com.zeng.notify.lastClick),用于冷启动错过点击回调时兜底读取;卸载即清除。

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

无

暂无用户评论。