iOS低版本推送权限是否已询问判断及拒后引导设置问题
解决iOS 10以下版本推送权限的询问状态判断与引导设置问题
嘿,我完全get你的需求——既要在用户拒绝推送权限时引导跳转到设置页,还要准确区分“从未询问过权限”和“已拒绝权限”这两种状态,尤其是iOS 10以下的老版本对吧?这确实是个容易被忽略的细节,因为不同系统版本的推送API差异不小,我来给你梳理一套完整的方案:
核心思路
在iOS 10及以上,UNUserNotificationCenter的API已经能直接给出完整的权限状态(包括是否从未授权、已授权、已拒绝),但iOS 10之前没有这么直观的API,我们需要结合UserDefaults标记和系统代理回调来实现判断。
具体实现步骤
1. 记录权限是否被询问过
在iOS 8-9中,当你调用registerUserNotificationSettings(_:)请求权限后,不管用户选择允许还是拒绝,系统都会触发UIApplicationDelegate的application(_:didRegisterUserNotificationSettings:)方法。我们可以在这个方法里记录“已询问过权限”的标记到UserDefaults中:
func application(_ application: UIApplication, didRegisterUserNotificationSettings settings: UIUserNotificationSettings) { // 标记已询问过推送权限 UserDefaults.standard.set(true, forKey: "hasAskedNotificationPermission") UserDefaults.standard.synchronize() // 如果用户允许,继续注册远程通知 if settings.types != .none { application.registerForRemoteNotifications() } }
对于iOS 7,系统会在调用registerForRemoteNotifications()后弹出权限弹窗,不管用户选择什么,都会触发对应回调,我们可以在这些方法里同样标记:
// iOS 7 注册成功回调 func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { UserDefaults.standard.set(true, forKey: "hasAskedNotificationPermission") UserDefaults.standard.synchronize() } // iOS 7 注册失败(包括用户拒绝)回调 func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { UserDefaults.standard.set(true, forKey: "hasAskedNotificationPermission") UserDefaults.standard.synchronize() }
2. 判断权限状态并引导设置
接下来,我们可以写一个统一的工具方法来判断当前的权限状态,以及是否需要引导用户去设置:
func checkNotificationPermissionAndGuide() { if #available(iOS 10.0, *) { // iOS 10及以上的逻辑,你已经熟悉,这里快速带过 UNUserNotificationCenter.current().getNotificationSettings { settings in DispatchQueue.main.async { switch settings.authorizationStatus { case .denied: // 用户已拒绝,引导去设置 self.showGuideToSettingsAlert() case .notDetermined: // 从未询问过,发起权限请求 self.requestNotificationPermission() default: // 已授权,无需处理 break } } } } else { // iOS 10以下版本的判断逻辑 let hasAsked = UserDefaults.standard.bool(forKey: "hasAskedNotificationPermission") guard let settings = UIApplication.shared.currentUserNotificationSettings() else { return } if hasAsked { if settings.types == .none { // 已询问过且用户拒绝,引导去设置 showGuideToSettingsAlert() } else { // 已授权,无需处理 } } else { // 从未询问过,发起权限请求 requestNotificationPermission() } } } // 发起推送权限请求的方法(适配iOS 10以下) func requestNotificationPermission() { if #available(iOS 10.0, *) { UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in // 处理授权结果 } } else { let settings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil) UIApplication.shared.registerUserNotificationSettings(settings) } } // 展示引导去设置的弹窗 func showGuideToSettingsAlert() { let alert = UIAlertController(title: "推送权限已关闭", message: "请前往设置开启推送权限,以便及时接收通知", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "取消", style: .cancel)) alert.addAction(UIAlertAction(title: "去设置", style: .default) { _ in // 打开APP设置页面 if let url = URL(string: UIApplicationOpenSettingsURLString) { if UIApplication.shared.canOpenURL(url) { UIApplication.shared.openURL(url) } } }) UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true) }
3. 注意事项
- 确保在APP启动时(比如
application(_:didFinishLaunchingWithOptions:))先初始化推送相关的注册逻辑,避免遗漏状态记录。 - iOS 10以下的
currentUserNotificationSettings()只能获取当前的权限类型,无法直接区分“从未询问”和“已拒绝”,所以必须依赖UserDefaults的标记,这个标记一定要在系统回调中设置,不能自己随便写,否则会出现判断错误。 - 对于iOS 7,
UIApplicationOpenSettingsURLString是从iOS 8开始引入的,所以iOS 7无法直接跳转到APP设置页,这种情况可以提示用户手动去设置里开启(不过iOS 7的用户占比已经极低,可根据你的APP用户群体决定是否适配)。
内容的提问来源于stack exchange,提问作者Prashant Tukadiya
相关产品推荐
相关产品推荐

