You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:16:43