iOS 9:如何检测用户何时对推送通知请求说"不允许"?

goe*_*elv 19 objective-c apple-push-notifications ios

在iOS 9中,是否有我可以阅读的系统级回调告诉我用户是否在推送通知请求上点击了"不允许"?

我通过自定义屏幕提示用户,告知他们推送通知及其在我的应用中的价值.

自定义Tripnary提示

他们有两个选择,是或否.如果他们选择是,我请求操作系统进行推送通知,他们会看到如下图所示的弹出窗口.

用于推送通知的iOS Level系统提示

现在,如果用户点击YES,则会有一个函数调用didRegisterForRemoteNotificationsWithDeviceToken,告诉我此设备已注册推送通知.我可以使用它来进入下一个屏幕(并在注册后将它们带入第一个屏幕)

但是,如何检测用户是否点击不允许?我需要知道,所以我可以相应地将用户移动到下一个屏幕(并在注册后将它们带入第一个屏幕).didFailToRegisterForRemoteNotificationsWithError如果用户点击"不允许",则不会调用该函数.

这个问题不重复,因为该问题的答案是针对iOS 7的,因为我的问题是具体的iOS 9.

lia*_*ols 27

从iOS 8开始,通知注册过程发生了变化,从必须授予权限的用户转移到远程通知.

您现在可以在技术上注册远程通知,而无需获得用户的许可.您需要的权限是用户通知设置(警报,声音和徽章).现在这些通知对于本地和远程通知都是通用的,使得其他答案在技术上不正确.

您通过该-[UIApplication registerUserNotificationSettings:]方法请求权限,UIApplication并根据文档,您获得-[UIApplicationDelegate application: didRegisterUserNotificationSettings:]委托方法的回调.

在标题中,有一条评论说明如下:

// This callback will be made upon calling -[UIApplication registerUserNotificationSettings:]. The settings the user has granted to the application will be passed in as the second argument.
Run Code Online (Sandbox Code Playgroud)

这意味着如果用户未授予通知(本地和远程)权限,则第二个参数将不包含任何值.


-[UIApplication isRegisteredForRemoteNotifications] 只会告诉您应用程序是否已实际注册Apple的推送服务器并且已收到设备令牌:

返回值
如果应用程序已注册远程通知并收到其设备令牌,则返回 YES;如果未发生注册,失败或已被用户拒绝,则返回NO.

值得阅读UIApplication文档,因为它包含您需要的所有信息.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/#//apple_ref/occ/instm/UIApplication


bol*_*iva 21

我只是设法解决了同样的问题,并且非常乐意分享我的做法(截至iOS 9.3).

就我而言,我使用一个自定义按钮来启用具有三种可能状态的通知:默认(意味着用户尚未提示启用通知),已完成(用户已被提示并同意接收通知)和失败(用户拒绝了通知提示).该按钮仅在处于默认状态时启用.

现在,我不是在使用单一技术,而是使用一些(尽管是相关的)调用.

逻辑如下:即使用户拒绝通知提示(在用户删除并重新安装应用程序之前只显示一次),我们仍会注册远程通知.该过程将照常继续,设备将被注册,但用户在发布新通知时将不会收到任何通知.然后,我们可以利用了解当前通知设置以及用户是否已注册远程通知以了解是否曾提示他们(因此按钮获得默认状态).

这种方法并不完美.如果用户最初同意收到通知,但稍后决定手动将其从"设置"中关闭,则该按钮将设置为默认状态,但在激活时,不会提示用户再次启用通知.但在大多数情况下,这并不重要,因为这种UI通常仅在入职/注册过程中显示一次.

至于代码本身(Swift 2.2):

func updateButtonStatus() {
    // as currentNotificationSettings() is set to return an optional, even though it always returns a valid value, we use a sane default (.None) as a fallback
    let notificationSettings: UIUserNotificationSettings = UIApplication.sharedApplication().currentUserNotificationSettings() ?? UIUserNotificationSettings(forTypes: [.None], categories: nil)
    if notificationSettings.types == .None {
        if UIApplication.sharedApplication().isRegisteredForRemoteNotifications() {
            // set button status to 'failed'
        } else {
            // set button status to 'default'
        }
    } else {
        // set button status to 'completed'
    }
}
Run Code Online (Sandbox Code Playgroud)

我们从视图控制器的viewWillAppear(animated)实现中调用此方法.

此时还需要做一些其他事情:首先,每当触摸按钮时(仅在处于默认状态时才会发生),我们必须提示用户接受或拒绝通知,我们还希望我们的UI做出反应正确地,无论用户选择什么:

@IBAction func notificationsPermissionsButtonTouched(sender: AnyObject) {
    let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
    UIApplication.sharedApplication().registerUserNotificationSettings(settings)
}
Run Code Online (Sandbox Code Playgroud)

然后,我们需要实现适当的UIApplicationDelegate方法来处理事件.由于没有UIApplication针对这些的全局通知,我们发送自己的通知:

// AppDelegate.swift

func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
    application.registerForRemoteNotifications()
    if notificationSettings.types == .None {
        NSNotificationCenter.defaultCenter().postNotificationName("ApplicationDidFailToRegisterUserNotificationSettingsNotification", object: self)
    }
}

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    NSNotificationCenter.defaultCenter().postNotificationName("ApplicationDidRegisterForRemoteNotificationsNotification", object: self)
}
Run Code Online (Sandbox Code Playgroud)

现在回到我们的视图控制器,我们需要处理这些通知.因此,在我们viewWillAppear(animated)viewWillDisappear(animated)实施中,我们做的:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PermissionsViewController.applicationDidRegisterForRemoteNotificationsNotification(_:)), name: "ApplicationDidRegisterForRemoteNotificationsNotification", object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PermissionsViewController.applicationDidFailToRegisterUserNotificationSettingsNotification(_:)), name: "ApplicationDidFailToRegisterUserNotificationSettingsNotification", object: nil)
    updateButtonStatus()
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: "ApplicationDidRegisterForRemoteNotificationsNotification", object: nil)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: "ApplicationDidFailToRegisterUserNotificationSettingsNotification", object: nil)
}
Run Code Online (Sandbox Code Playgroud)

通知处理程序本身:

func applicationDidRegisterForRemoteNotificationsNotification(notification: NSNotification) {
    let notificationSettings: UIUserNotificationSettings = UIApplication.sharedApplication().currentUserNotificationSettings() ?? UIUserNotificationSettings(forTypes: [.None], categories: nil)
    if notificationSettings.types != .None {
        // set button status to 'completed'
    }
}

func applicationDidFailToRegisterUserNotificationSettingsNotification(notification: NSNotification) {
    // set button status to 'failed'
}
Run Code Online (Sandbox Code Playgroud)

奖金

如果用户拒绝了通知提示并且我们想要一个按钮来引导他们进入"设置"面板,他们可以重新启用它,并使我们的UI做出相应的反应,该怎么办?嗯,我很高兴你问.

有很少的已知机制可以深入链接到"设置"中的"应用"部分(自iOS 8以来它一直存在,但直到几个小时前我还没有机会了解它).在我们的设置按钮触摸处理程序中,我们执

@IBAction func settingsButtonTouched(sender: AnyObject) {
    if let settingsURL = NSURL(string: UIApplicationOpenSettingsURLString) {
        UIApplication.sharedApplication().openURL(settingsURL)
    }
}
Run Code Online (Sandbox Code Playgroud)

由于我们想要更新我们的UI以反映用户可能做出的任何更改,我们UIApplicationDidBecomeActiveNotificationviewWillAppear(animated)实现中添加了一个通知监听器(不要忘记从中移除监听器viewWillDisapper(animated).最后,从我们刚刚调用的相应通知处理程序方法内部我们现有的updateButtonStatus().


Eli*_*kiy 5

在您的应用委托中使用此方法

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings

那么你可以通过使用知道用户是否给出了通知权限

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]

或使用notificationSettings你收到的.


Viz*_*llx 0

通过此方法检查:-

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
Run Code Online (Sandbox Code Playgroud)

但如果您的应用程序支持低于 iOS 8 的版本,那么您必须进行如下检查:-

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types == UIRemoteNotificationTypeNone) 
{ 
  //notification is not enabled by user

}
Run Code Online (Sandbox Code Playgroud)

  • 当用户点击“不允许”时,我需要得到回调。我不能简单地调用 `[[UIApplication sharedApplication] isRegisteredForRemoteNotifications];` (5认同)