iOS 9:如何检测用户何时对推送通知请求说“不允许”? [复制]

Posted

技术标签:

【中文标题】iOS 9:如何检测用户何时对推送通知请求说“不允许”? [复制]【英文标题】:iOS 9: How to detect when user said 'Don't Allow' to the push notification request? [duplicate] 【发布时间】:2016-02-01 08:56:05 【问题描述】:

ios 9 中,我是否可以读取系统级回调,告诉我用户是否在推送通知请求中点击了“不允许”?

我使用自定义屏幕提示用户推送通知及其在我的应用中的价值。

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

现在,如果用户点击“是”,则会有一个名为didRegisterForRemoteNotificationsWithDeviceToken 的函数告诉我该设备已注册推送通知。我可以使用它进入下一个屏幕(并在注册后将它们带到第一个屏幕)

但是,我如何检测用户是否点击了不允许?我需要知道这一点,以便我可以相应地将用户移动到下一个屏幕(并将他们带到第一个屏幕注册后)。如果用户点击“不允许”,则不会调用函数didFailToRegisterForRemoteNotificationsWithError

这个问题不是重复的,因为该问题接受的答案是特定于 iOS 7,而我的问题是特定于 iOS 9。

【问题讨论】:

@iThink 但是这个警报视图是由操作系统传播的。我认为我无权访问此警报视图委托方法。 只需在以下堆栈溢出链接上查看答案,希望这会起作用。 . Show Answer ***.com/questions/26051950/… in iOS 10 如果你使用UserNotifications framework 那么你可以通过回调来判断用户是否点击了yes/no。见here 你找到合适的解决方案了吗? 【参考方案1】:

从 iOS 8 开始,通知注册过程发生了变化,不再需要用户仅授予远程通知权限。

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

您通过UIApplication 上的-[UIApplication registerUserNotificationSettings:] 方法请求权限,并且根据文档,您会收到对-[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.

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


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

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

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

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

【讨论】:

你拯救了我的理智。非常感谢。 developer.apple.com/documentation/usernotifications/…【参考方案2】:

我刚刚设法解决了同样的问题,并且非常乐意分享我是如何做到的(从 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'
    

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

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

@IBAction func notificationsPermissionsButtonTouched(sender: AnyObject) 
    let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
    UIApplication.sharedApplication().registerUserNotificationSettings(settings)

然后,我们需要实现正确的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)

现在回到我们的视图控制器,我们需要处理这些通知。所以,在我们的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)

还有通知处理程序本身:

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'


奖金

如果用户拒绝了通知提示,并且我们希望有一个按钮将他们引导到设置面板,他们可以重新启用它,并让我们的 UI 做出相应的反应,该怎么办?嗯,很高兴你问。

在“设置”中,有一个鲜为人知的机制可以深度链接到您的“应用”部分(它从 iOS 8 开始就存在,但直到几个小时前我才有机会了解它)。在我们的 settings 按钮触摸处理程序中,我们这样做:

@IBAction func settingsButtonTouched(sender: AnyObject) 
    if let settingsURL = NSURL(string: UIApplicationOpenSettingsURLString) 
        UIApplication.sharedApplication().openURL(settingsURL)
    

由于我们想要更新我们的 UI 以反映用户可能做出的任何更改,因此我们在 viewWillAppear(animated) 实现中为 UIApplicationDidBecomeActiveNotification 添加了一个通知侦听器(不要忘记从 viewWillDisapper(animated) 中删除侦听器。并且最后,在相应的通知处理程序方法中,我们只需调用现有的updateButtonStatus()

【讨论】:

嘿玻利瓦。这是一个很好的答案。您是否碰巧知道它是否是我们可以信任未来 iOS 的已定义行为?或者它是一个黑客? 嗨@RoiMulia。对于未来的 iOS 版本,您实际上不应该相信这一点,因为 UIUserNotifications 已被弃用,取而代之的是 UserNotifications 框架。我需要更新此代码以反映这一点。【参考方案3】:

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

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

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

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]

或使用您收到的notificationSettings

【讨论】:

【参考方案4】:

不,如果不允许,则无法在应用程序中检测来自 APNS 的推送通知。

使用此代码检查它是否被允许并导航应用程序以启用它:

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types == UIRemoteNotificationTypeNone)

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"app-settings:"]];

希望这会有所帮助!

【讨论】:

你应该使用这个字符串常量 UIApplicationOpenSettingsURLString 而不是@"app-settings" 谢谢...这对我帮助很大..!【参考方案5】:

有一种快速而廉价的方法可以做到这一点。 iOS9这个委托方法

- (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken

在显示对话框时调用一次,然后在用户点击“Ok”时调用第二次次。只需在此处添加一个标志。

然后,当您希望显示自定义“提醒用户如何启用推送”消息时,只需检查标志和您当前的通知设置(如上面的许多答案所述)。

- (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 

    self.pushDialogShown = YES;


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  

    // not a great place to put this logic. For demonstration purposes ONLY
    if (self.pushDialogueShown && ![self pushMessageEnabled]) 
        [self showPushReminderMessage];
    

【讨论】:

【参考方案6】:

用途:

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications];

NSUserDefaults。当出现推送通知的系统对话框时,将密钥(例如HasSeenSystemPushNotification)存储到true

然后您可以检查 NSUD 密钥和 isRegisteredForRemoteNotifications bool 以查看它是否已被提交/接受并相应地进行工作。

【讨论】:

那是行不通的,因为用户可以在显示系统对话框时退出应用程序,对吧? 推送通知的系统对话框只能显示一次我相信 对不起,你说得对。但是,其他系统对话框并非如此。感谢您的跟进。【参考方案7】:

用这种方法检查:-

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications];

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

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


【讨论】:

当用户点击“不允许”时,我需要得到回调。我不能简单地打电话给[[UIApplication sharedApplication] isRegisteredForRemoteNotifications];

以上是关于iOS 9:如何检测用户何时对推送通知请求说“不允许”? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何检测真正的 iOS/APNS 推送令牌何时向 Firebase Cloud Messaging (FCM) 注册?

如何控制何时在 iOS 中提示用户提供推送通知权限

是否可以在 IOS 上再次请求推送通知?

iOS 开发/生产推送证书:何时以及如何?

在 iOS 8 中取消注册推送通知

如何检测用户卸载的iOS App?我需要推送严肃的通知。我不想失去它