iOS 9及以上推送通知状态区分与设置跳转实现咨询
区分推送通知"未注册"和"已关闭"的方案(支持iOS 9+)
我之前也碰到过这个棘手的问题——UIApplication.shared.isRegisteredForRemoteNotifications确实太不靠谱了,不管用户从来没授权过推送,还是授权后又手动关掉了,它都返回false。要区分这两种场景,核心得抓住一个关键点:只有用户被请求过推送权限的应用,才会出现在系统设置的通知列表里。
核心判断逻辑
- 如果用户从未被请求过推送权限(权限状态为
.notDetermined):系统设置里还没这个应用的推送选项,这时候应该引导用户在App内完成推送注册请求。 - 如果用户已经被请求过权限(状态为
.denied/.authorized/.provisional等):不管当前推送是开还是关,系统设置里都能找到对应选项,这时候直接通过Deep Link跳转到系统设置页面即可。
具体代码实现
因为要兼容iOS 9到最新系统,我们需要分版本处理权限获取的API:
1. 先导入必要框架
import UIKit // iOS 10及以上需要导入这个通知框架 @available(iOS 10.0, *) import UserNotifications
2. 封装状态判断方法
func checkPushNotificationStatus(completion: @escaping (Bool) -> Void) { if #available(iOS 10.0, *) { // iOS 10+ 用UNUserNotificationCenter直接获取权限状态 UNUserNotificationCenter.current().getNotificationSettings { settings in DispatchQueue.main.async { // .notDetermined 意味着用户从未被请求过权限,系统设置无此App选项 let hasSystemSettingsEntry = settings.authorizationStatus != .notDetermined completion(hasSystemSettingsEntry) } } } else { // iOS 9及以下的特殊处理:系统API无法直接区分"未请求"和"拒绝",需要本地记录 let hasRequestedPermission = UserDefaults.standard.bool(forKey: "HasRequestedPushPermission") if hasRequestedPermission { // 已经请求过权限,系统设置里有对应选项 completion(true) } else { // 从未请求过权限,系统设置里找不到 completion(false) } } }
3. 实际调用逻辑
checkPushNotificationStatus { hasSettingsEntry in if hasSettingsEntry { // 跳转到系统设置页面 if let settingsUrl = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(settingsUrl, options: [:], completionHandler: nil) } } else { // 引导用户注册推送 if #available(iOS 10.0, *) { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in // 记录已发起过权限请求 UserDefaults.standard.set(true, forKey: "HasRequestedPushPermission") if granted { // 用户允许后,注册远程推送 UIApplication.shared.registerForRemoteNotifications() } } } else { // iOS 9及以下的注册流程 let notificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil) UIApplication.shared.registerUserNotificationSettings(notificationSettings) // 记录已发起过权限请求 UserDefaults.standard.set(true, forKey: "HasRequestedPushPermission") // 记得在AppDelegate的`didRegisterUserNotificationSettings`方法里调用`registerForRemoteNotifications` } } }
4. iOS 9的额外注意事项
iOS 9的系统API有局限:不管是从未请求过权限,还是请求后被用户拒绝,currentUserNotificationSettings返回的类型都是.none。所以必须用UserDefaults记录“是否发起过权限请求”这个状态,才能准确区分两种场景。
关键总结
- iOS 10+ 可以直接通过
UNUserNotificationCenter的authorizationStatus判断,非常可靠; - iOS 9需要依赖本地存储记录请求状态,弥补系统API的不足;
- 跳转系统设置的Deep Link用
UIApplication.openSettingsURLString,从iOS 8就开始支持,完全覆盖你的需求。
内容的提问来源于stack exchange,提问作者Kenji
相关产品推荐
相关产品推荐

