18、通知的权限管理:POST_NOTIFICATIONS权限(Android 13+)、运行时权限申请、权限被拒绝的处理策略
通知权限这件事,在 Android 13 之前几乎没人操心。那时候只要在清单文件里声明一下,通知就能随便发。但 Google 从 Android 13(API 33)开始搞了个大动作——把通知权限变成了运行时权限。说白了,现在发通知跟访问相机、读取联系人一样,得弹窗问用户「你同意吗?」。
我个人习惯把这件事分成三个层面来理解:权限声明、运行时申请、被拒绝后的兜底策略。咱们一个一个聊。
18.1 权限声明:清单文件里必须做的事
不管你的 targetSdk 是多少,只要应用跑在 Android 13+ 的设备上,就必须在 AndroidManifest.xml 里加上这个权限声明:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
嗯,这里要注意:如果你的 targetSdk 低于 33,系统会默认帮你兼容,但 Google Play 从 2023 年开始强制要求 targetSdk 33+。所以别想着偷懒,老老实实加上。
18.2 运行时权限申请:弹窗的正确姿势
权限声明只是第一步。真正让开发者头疼的是运行时申请。我见过不少项目直接在 onCreate 里弹权限对话框,结果用户一脸懵——「这 App 刚打开就要发通知?」。
正确的做法是:在需要发通知的时候才申请。比如用户点击了「开启推送」按钮,或者你确实要发一条重要通知时。
代码其实很简单:
// 检查权限是否已授予
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
// 没有权限,发起申请
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.POST_NOTIFICATIONS},
REQUEST_CODE_POST_NOTIFICATIONS);
} else {
// 已有权限,直接发通知
sendNotification();
}
然后在 onRequestPermissionsResult 里处理结果:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_POST_NOTIFICATIONS) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户同意了
sendNotification();
} else {
// 用户拒绝了
handlePermissionDenied();
}
}
}
shouldShowRequestPermissionRationale() 判断一下,如果返回 false,说明用户已经勾选了「不再询问」,这时候弹窗也没用,得走引导用户去设置页的流程。
18.3 权限被拒绝的处理策略:别让用户卡死
用户拒绝权限是常态,不是异常。我见过有些 App 在权限被拒后直接弹 Toast「请开启通知权限」,然后什么都不做。用户想开都不知道去哪开。
合理的策略分三种情况:
| 场景 | 用户行为 | 推荐处理方式 |
|---|---|---|
| 第一次拒绝 | 点击「拒绝」 | 显示一个友好的说明弹窗,解释为什么需要通知权限,然后再次申请 |
| 拒绝并勾选「不再询问」 | 系统不再弹窗 | 引导用户去系统设置页手动开启 |
| 永久拒绝(设置页关闭) | 用户主动关闭 | 降级处理,比如用轮询代替推送,或者干脆不推送 |
引导用户去设置页的代码:
private void openAppSettings() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
核心原则: 永远不要强迫用户。通知权限不是核心功能依赖,用户拒绝后你的 App 应该能正常运行,只是少了一些推送体验。
18.4 知识体系总览
下面这张图把整个通知权限管理的流程串起来了。你想想看,从清单声明到运行时申请,再到被拒绝后的三种处理路径,其实就是一个完整的闭环。
18.5 避坑指南:我曾经踩过的坑
我曾经在一个项目中犯过一个低级错误——在 Application.onCreate() 里申请通知权限。结果呢?权限对话框还没弹出来,应用就已经在后台发了一条通知。用户看到通知后一脸疑惑:「我还没同意呢,你怎么就发了?」。
后来我才意识到,权限申请必须在 Activity 的上下文中进行。Application 上下文没有窗口,弹不出对话框。而且就算能弹,也不应该在用户还没看到 UI 的时候就申请。
另一个坑是:不要假设用户一定会同意。我见过有些团队在权限被拒后直接让 App 闪退,美其名曰「没有通知权限没法用」。这其实是在绑架用户。通知权限不是核心功能,你的 App 应该能在没有通知的情况下正常运行。
我的建议: 在权限被拒后,可以显示一个非侵入性的提示条(比如 Snackbar),告诉用户「开启通知可以及时收到消息」,然后提供一个「去设置」的按钮。这样既尊重了用户的选择,又给了他们一个便捷的入口。
18.6 总结
通知权限管理说白了就三件事:声明、申请、兜底。声明是基础,申请要讲究时机,兜底要体现对用户的尊重。我个人觉得,Android 13 的这个改动其实是好事——它让用户重新掌握了对自己通知栏的控制权。作为开发者,我们只需要把选择权交给用户,然后优雅地处理每一种结果。
嗯,关于权限管理就聊到这里。记住一句话:权限是用户的,不是你的。
公众号:蓝海资料掘金营,微信deep3321