16、权限与通知:通知权限、POST_NOTIFICATIONS、通知渠道权限

通知权限,说实话,是 Android 13(API 33)之后变化最大的一个运行时权限。以前我们发通知,只要建个 NotificationManager 就能弹,用户根本拦不住。现在不行了——你得先问用户「我能不能给你发通知」。

我个人习惯把通知权限看作「用户对 App 骚扰程度的容忍阈值」。你想想看,如果一个天气 App 天天弹广告通知,用户大概率会关掉它。所以,处理好通知权限,不仅是合规问题,更是用户体验问题。

16.1 通知权限的演进史

先简单回顾一下历史。Android 12 及之前,通知权限是隐式的——只要 App 有前台服务或者用户主动交互,就能发通知。但 Google 发现,很多 App 滥用这个能力,导致用户被大量垃圾通知轰炸。

所以 Android 13 引入了 POST_NOTIFICATIONS 权限。这是一个 Normal 级别的运行时权限,需要用户在运行时授权。

关键点:

  • Android 13+:必须声明 POST_NOTIFICATIONS 权限
  • Android 12 及以下:不需要此权限,但建议适配
  • 如果用户拒绝,App 将无法发送任何通知(包括前台服务通知)

我记得第一次适配这个权限时,踩了个坑——我的 App 有个前台服务,用户拒绝通知权限后,前台服务的持续通知直接消失了。嗯,这里要注意:前台服务的通知也受此权限管控。

16.2 声明与请求通知权限

首先,在 AndroidManifest.xml 中声明权限:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

然后,在代码中请求权限。和普通运行时权限一样:

// 检查权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
        != PackageManager.PERMISSION_GRANTED) {
    // 请求权限
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.POST_NOTIFICATIONS},
            NOTIFICATION_PERMISSION_REQUEST_CODE);
}

但这里有个坑——用户拒绝后,系统不会再次弹窗。我曾经遇到一个用户反馈:「我点了拒绝,然后 App 再也不问我要通知权限了。」这就是 Android 的权限机制:用户拒绝一次后,再次请求会直接回调 onRequestPermissionsResult 返回拒绝。

避坑指南:

我曾经在项目中遇到一个 Bug:用户拒绝通知权限后,App 的前台服务崩溃了。原因是前台服务需要显示一个持续通知,但权限被拒导致通知无法创建。解决方案是:在权限被拒时,降级处理——比如不启动前台服务,或者使用其他方式提示用户。

16.3 通知渠道权限

通知渠道(Notification Channel)是 Android 8.0(API 26)引入的。它允许用户对不同类型的通知进行精细控制。比如,一个社交 App 可以有「私信通知」「点赞通知」「系统通知」三个渠道,用户可以单独关闭某个渠道。

但注意:通知渠道的权限和 POST_NOTIFICATIONS 权限是两回事

  • POST_NOTIFICATIONS:控制 App 能否发通知(全局开关)
  • 通知渠道:控制某个类型的通知是否显示(局部开关)

用户可以在系统设置中,对每个渠道单独设置:

  • 允许通知
  • 静默通知(无声音、无震动)
  • 完全关闭

我个人建议:不要创建太多渠道。我见过一个 App 创建了 20 多个渠道,用户根本分不清。一般来说,3-5 个渠道就足够了。

16.4 创建通知渠道的最佳实践

创建通知渠道的代码很简单:

NotificationChannel channel = new NotificationChannel(
        CHANNEL_ID,
        "渠道名称",
        NotificationManager.IMPORTANCE_HIGH
);
channel.setDescription("渠道描述");

NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);

这里有个细节:渠道的重要性级别

重要性级别 行为表现 使用场景
IMPORTANCE_HIGH 弹出横幅、有声音、有震动 私信、紧急通知
IMPORTANCE_DEFAULT 有声音、无横幅 一般通知
IMPORTANCE_LOW 无声音、无横幅 静默通知
IMPORTANCE_MIN 不显示在状态栏 后台任务通知

嗯,这里要注意:渠道一旦创建,重要性级别就不能修改了。用户可以在设置中手动调整,但代码层面无法覆盖。所以,创建渠道时一定要想清楚。

小技巧:

如果你需要修改渠道的重要性,可以删除旧渠道重新创建。但删除渠道会导致该渠道的所有通知被移除,用户可能会困惑。我一般建议:创建时就用 IMPORTANCE_DEFAULT,后续通过更新渠道描述来引导用户调整。

16.5 权限与通知渠道的交互逻辑

说白了,整个流程是这样的:

  1. 用户安装 App,系统弹出通知权限请求
  2. 用户同意 → App 可以发通知
  3. 用户拒绝 → App 无法发任何通知
  4. 即使同意了,用户还可以在设置中关闭某个渠道

所以,你的代码需要处理两种状态:

  • 全局权限被拒:不要尝试发通知,直接降级处理
  • 渠道被关闭:发通知不会报错,但用户看不到

我曾经在项目中遇到一个场景:用户关闭了「促销通知」渠道,但 App 仍然在后台发促销通知。虽然不会崩溃,但浪费了系统资源。后来我加了一个检查:

NotificationManager manager = getSystemService(NotificationManager.class);
if (manager.getNotificationChannel(CHANNEL_ID).getImportance() == NotificationManager.IMPORTANCE_NONE) {
    // 渠道被关闭,不要发通知
    return;
}

16.6 知识体系总览

下面这张图,是我梳理的通知权限与渠道的核心逻辑:

通知权限与渠道核心逻辑 POST_NOTIFICATIONS 用户授权? 无法发送通知 可以发送通知 通知渠道控制 渠道开启 → 显示通知 渠道关闭 → 通知被静默

从图中可以看出,POST_NOTIFICATIONS 是总开关,通知渠道是分开关。总开关关了,分开关再精细也没用。反过来,总开关开了,用户还可以通过分开关来过滤不想要的通知。

16.7 总结

通知权限这块,说白了就是「尊重用户的选择」。我见过太多 App 在用户拒绝通知权限后,反复弹窗请求,甚至用「不授权就无法使用」来要挟用户。这种做法,用户体验极差,而且 Google Play 也会下架这类 App。

我个人建议的做法是:

  • 第一次请求时,解释清楚为什么需要通知权限
  • 用户拒绝后,不要反复弹窗,而是提供手动开启的引导
  • 通知渠道不要太多,3-5 个足矣
  • 渠道的重要性级别要合理,别把垃圾通知设成 HIGH

嗯,最后说一句:通知权限的适配其实不难,难的是想清楚「用户到底需不需要我的通知」。想明白这一点,代码怎么写都顺。


公众号:蓝海资料掘金营,微信deep3321