回拨方法,如果用户拒绝推送通知提示?

我的问题是我想显示一个加载屏幕的初始推送通知提示“该应用程序想发送推送通知。”

所以,如果用户点击yes我可以继续,然后启动应用程序,然后调用委托方法:

 - (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { [self hideLoadingScreen]; } - (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error { [self hideLoadingScreen]; } 

但是,如果用户打no ,这些方法都不会被调用,这是有道理的。 我的问题是,是否有不同的委托方法会被拒绝?

我的问题是,如果noselect,加载屏幕永远不会消失。 所以我不知何故需要知道用户何时完成select。

在iOS 7中,系统的推送通知提示出现时,应用程序将变为非活动状态,并且会触发UIApplicationWillResignActiveNotification。 同样,当用户对提示做出响应(按“是”或“否”)时,应用程序会再次变为活动状态,并且UIApplicationDidBecomeActiveNotification会触发。

所以你可以听这个通知,然后隐藏你的加载屏幕。

注意:显示提示时,主页button,通知中心和控制中心被禁用,因此它们不能触发误报UIApplicationDidBecomeActiveNotification。 但是,如果用户按下lockingbutton,将触发UIApplicationDidBecomeActiveNotification。

您始终可以获取当前允许的通知types:

 UIRemoteNotificationType notificationTypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes]; 

请记住,用户也可以在电话设置中禁用通知。

如果你检查didRegisterForRemoteNotificationsWithDeviceToken你应该看看你要求的types是否被启用。

你不能只是做以下几点:

 - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { BOOL pushEnabled = notificationSettings.types & UIUserNotificationTypeAlert; } 

这个方法应该是对那个推送通知提示的callback,并且从那里,你可以检查位掩码来查看推送通知是否被启用。

这里是我在Swift 3中做的。他们的关键是在内部跟踪应用程序的生命周期状态。 当出现提示提示时,应用程序会暂停,但不会进入后台。 这一切都在我的AppDelegate.swift。

这是一个非常大的黑客,不build议在生产中。 苹果可能会改变这些警报的呈现方式,随时可能会中断。 这是使用运行iOS 9和10的各种iPhone和iPadtesting的。

 /// An internal value used to track application lifecycle state enum ApplicationLifecycleState { case willResignActive case didEnterBackground case willEnterForeground case didBecomeActive case unknown } /// This is used purely for tracking the application lifecycle for handling the system push notification alert var internalLifecycleState: ApplicationLifecycleState = .unknown { didSet { // If we're not in the middle of asking for push permissions, none of the below applies, just bail out here if !isAskingForPushPermissions { return } // WARNING: Application lifecycle trickery ahead // The normal application lifecycle calls for backgrounding are as follows: // applicationWillResignActive -> applicationDidEnterBackground -> applicationWillEnterForeground -> applicationDidBecomeActive // However, when the system push notification alert is presented, the application resigns active, but does not enter the background: // applicationWillResignActive -> [user taps on alert] -> applicationDidBecomeActive // We can use this discrepancy to our advantage to detect if the user did not allow push permissions // If applicationDidBecomeActive // AND the previous state was applicationWillResignActive // AND the notification types bitmask is 0, we know that the user did not allow push permissions // User denied permissions if internalLifecycleState == .didBecomeActive && oldValue == .willResignActive && UIApplication.shared.currentUserNotificationSettings?.types.rawValue == 0 { // We're done firePushCompletionBlockAndCleanup(registered: false) } else { // The state below can only be entered on iOS 10 devices. // If the user backgrounds the app while the system alert is being shown, // when the app is foregrounded the alert will dismiss itself without user interaction. // This is the equivalent of the user denying push permissions. // On iOS versions below 10, the user cannot background the app while a system alert is being shown. if #available(iOS 10, *), internalLifecycleState == .didBecomeActive { firePushCompletionBlockAndCleanup(registered: false) } } } } /// Used internally to track if the system push notification alert is currently being presented var isAskingForPushPermissions = false typealias PushNotificationRegistrationCompletionBlock = ((_ registered: Bool) -> Void) // ... func applicationWillResignActive(_ application: UIApplication) { internalLifecycleState = .willResignActive } func applicationDidEnterBackground(_ application: UIApplication) { internalLifecycleState = .didEnterBackground } func applicationWillEnterForeground(_ application: UIApplication) { internalLifecycleState = .willEnterForeground } func applicationDidBecomeActive(_ application: UIApplication) { internalLifecycleState = .didBecomeActive } // ... func setupPushNotifications(_ application: UIApplication = UIApplication.shared, completion: @escaping PushNotificationRegistrationCompletionBlock) { isAskingForPushPermissions = true pushCompletionBlock = completion let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil) application.registerUserNotificationSettings(settings) application.registerForRemoteNotifications() } fileprivate func firePushCompletionBlockAndCleanup(registered: Bool) { pushCompletionBlock?(registered) pushCompletionBlock = nil isAskingForPushPermissions = false } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { // application:didRegisterForRemoteNotificationsWithDeviceToken may be called more than once (once for each notification type) // By checking that the notification types bitmask is greater than 0, we can find the final time this is called (after the user actually tapped "allow") // If the user denied push permissions, this function is never called with a positive notification type bitmask value if UIApplication.shared.currentUserNotificationSettings?.types.rawValue ?? 0 > 0 { firePushCompletionBlockAndCleanup(registered: true) } } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print("Failed to register for notifications with error: " + error.localizedDescription) firePushCompletionBlockAndCleanup(registered: false) } 

用法:

 appDelegate.setupPushNotifications(completion: { [weak self] (registered) in // If registered is false, the user denied permissions }) 

我猜你可以有一个BOOLvariables来检查你的AppDelegate,因为除了使用外部API似乎没有办法。 看到这个

 AppDelegate.m // declare a BOOL BOOL allow = NO; - (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { allow = YES; [self hideLoadingScreen]; } - (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error { allow = YES; [self hiedLoadingScreen]; } 

现在我猜你可以访问这个BOOLvariables来区分什么时候不允许被按下或没有。

这里有一个SWIFT 2代码示例,对于你们来说…这有点复杂,但是我希望我的意见能够帮助你理解它。

定义variables

 var appDidBecomeActiveCount = 0 var userDefaults:NSUserDefaults! 

AppDelegate – didFinishLaunchingWithOptions

 func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { userDefaults = NSUserDefaults.standardUserDefaults() if userDefaults.valueForKey("FirstLaunche") == nil { userDefaults.setBool(true, forKey: "FirstLaunche") userDefaults.synchronize() } // Register for notification //iOS 8+ let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert , UIUserNotificationType.Badge ,UIUserNotificationType.Sound], categories: nil) UIApplication.sharedApplication().registerUserNotificationSettings(settings) UIApplication.sharedApplication().registerForRemoteNotifications() } 

AppDelegate – applicationDidBecomeActive

 func applicationDidBecomeActive(application: UIApplication) { //Delay until alert get dismissed and notification type setted in app delay(0.5, closure: { () -> () in self.checkTheDilemma() }) } //I love this short method <3_<3 func delay(delay:Double, closure:()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), closure) } 

检查行动

 func checkTheDilemma (){ //Checking if this user turned off push notifications or didn't allow it at all let notificationType = UIApplication.sharedApplication().currentUserNotificationSettings()?.types if userDefaults.valueForKey("FirstLaunche") as! Bool == true { //User now is asked for notification permission because it's app's first launche // if appDidBecomeActiveCount == 0 --> Pop up message will appeare // if appDidBecomeActiveCount == 1 --> Pop up message dismissed // if notificationType?.rawValue == 0 --> Notifications off // if notificationType?.rawValue > 0 --> Notifications on if notificationType?.rawValue == 0 && appDidBecomeActiveCount == 1 { //If user disabled notifications from pop up alert // ** User just tapped "Don't allow" btn :\ // Do what ever you are here for //Now set FirstLaunche = false userDefaults.setBool(false, forKey: "FirstLaunche") userDefaults.synchronize() } } else { if notificationType?.rawValue == 0 && appDidBecomeActiveCount == 0 { // This guy is not registered for push notification // ** User disabled notifications in past (because this is not his first launch) } } appDidBecomeActiveCount++ } 

您可以通过检查notificationSettings.types来检测用户是否已经取消了在调用registerForRemoteNotificationTypes后触发的didRegisterUserNotificationSettings方法中的通知提示。

如果您已经请求了一些设置,但notificationSettings.types == UIUserNotificationTypeNone表示该用户已经取消提示。

但是不要忘记registerForRemoteNotificationTypes方法现在已经被弃用了!

对于Swift 3Swift 4.0,使用NotificationCenter和AppDelegate方法didRegister notificationSettings 。 通知设置显示用户是否select了徽章,声音等,如果他们拒绝推送通知将是一个空数组。 当用户响应推送通知提示,并且似乎是大多数开发人员使用的,因为它比检查didBecomeActive更具体。 但苹果可能会改变这一点。 谁知道?

不幸的是,NotificationCenter没有预设的通知名称,所以你必须设置和扩展(见最后)或使用原始值(SO有更多的)。

在AppDelegate中:

  func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) { // if not registered users will have an empty set of settings let accepted: Bool = !notificationSettings.types.isEmpty NotificationCenter.default.post(name: Notification.Name(rawValue: "didRespondToPrompt"), object: self, userInfo: ["didAccept" : accepted]) } 

然后观察你需要的任何地方,例如在视图控制器中:

 class MyViewController: UIViewController { //MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.didRespondToPushPrompt(_:)), name: NSNotification.Name(rawValue: "didRespondToPrompt"), object: nil) } @objc func didRespondToPushPrompt(_ notification: Notification) { if let userInfo: [AnyHashable : Any] = notification.userInfo, let didAccept: Bool = userInfo[NSNotificationKeyNames.didAccept] as? Bool, !didAccept { //if user doesn't accept, do this... } else { //all other situations code goes here } } } 

几件事情:首先,对于Swift 4.0,我在一种方法前使用了“@objc”,但对Swift 3来说并不是必须的。
此外,对于使用NotificationCenter,实际上我没有使用“rawValue”。 相反,我做了如下扩展:

 import Foundation extension NSNotification.Name { static let DidRegisterForPushNotifications = NSNotification.Name("DidRegisterForPushNotifications") } 

我可以这样使用它:

NotificationCenter.default.post(name: Notification.Name.DidRegisterForPushNotifications, object: self, userInfo: ["didAccept" : myBool])等等