web-dev-qa-db-fra.com

iOS 9: Comment détecter lorsque l'utilisateur a dit "Ne pas autoriser" à la demande de notification Push?

Dans iOS 9, y a-t-il un rappel au niveau du système que je peux lire qui m'indique si l'utilisateur a tapé sur 'Ne pas autoriser' sur la demande de notification Push?

Je demande à l'utilisateur un écran personnalisé pour l'informer des notifications Push et de la valeur qu'il apporte à mon application. 

 Custom Tripnary Prompt

Ils ont deux choix, oui ou non. S'ils sélectionnent Oui, je demande au système d'exploitation la notification Push et ils voient apparaître une fenêtre semblable à l'image ci-dessous.

 iOS Level system Prompt for Push notifications

Maintenant, si l'utilisateur appuie sur YES, il existe une fonction appelée didRegisterForRemoteNotificationsWithDeviceToken qui me dit que ce périphérique a été enregistré pour les notifications Push. Je peux l'utiliser pour passer à l'écran suivant (et les emmener dans le premier écran après l'inscription)

Cependant, comment puis-je détecter si l'utilisateur appuie sur NE PAS autoriser? J'ai besoin de savoir cela pour pouvoir déplacer l'utilisateur vers l'écran suivant (et l'amener ensuite au premier écran après l'inscription). La fonction didFailToRegisterForRemoteNotificationsWithError n'est pas appelée si l'utilisateur appuie sur 'Ne pas autoriser'. 

Cette question n'est pas un doublon car la réponse acceptée pour cette question est spécifique à iOS 7, où ma question est spécifique à iOS 9. 

18
goelv

À partir d'iOS 8, le processus d'enregistrement des notifications a changé et s'éloignait de l'obligation pour l'utilisateur de n'autoriser que les notifications remote.

Vous pouvez maintenant vous inscrire techniquement pour les notifications à distance sans avoir à obtenir l'autorisation de l'utilisateur. Ce dont vous avez besoin d’autorisation, ce sont les paramètres de notification de l’utilisateur (alertes, sons et badges). Celles-ci sont désormais génériques pour les notifications locales et distantes, rendant les autres réponses techniquement incorrectes.

Vous demandez l'autorisation via la méthode -[UIApplication registerUserNotificationSettings:] sur UIApplication et, conformément à la documentation, vous obtenez un rappel de la méthode déléguée -[UIApplicationDelegate application: didRegisterUserNotificationSettings:].

Dans l'en-tête, il y a un commentaire disant ce qui suit:

// 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.

Cela signifie que si l'utilisateur n'a pas accordé d'autorisations pour les notifications (locales et distantes), le second paramètre ne contiendra aucune valeur.


-[UIApplication isRegisteredForRemoteNotifications] vous indiquera simplement si l’application a été enregistrée auprès des serveurs Push d’Apple et a reçu un jeton de périphérique:

Valeur de retour
OUI si l'application est enregistrée pour les notifications à distance et a reçu son jeton d'appareil ou NON si l'enregistrement n'a pas eu lieu, a échoué ou a été refusé par l'utilisateur.

Il vaut la peine de lire la documentation UIApplication car elle contient toutes les informations dont vous avez besoin.

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

26
liamnichols

J'ai juste réussi à résoudre ce même problème et je serais plus qu'heureux de partager comment je l'ai fait (à partir de iOS 9.3).

Dans mon cas, j’utilise un seul bouton personnalisé pour activer les notifications avec trois états possibles: défaut (ce qui signifie que l’utilisateur n’a pas encore été invité à activer les notifications), terminé (l’utilisateur a été invité à accepter les notifications) et a échoué (l'utilisateur a rejeté l'invite de notification). Le bouton est activé uniquement dans l'état par défaut.

Maintenant, je n’utilise pas une seule technique ici, mais une combinaison de quelques appels (bien que liés).

La logique est la suivante: même si l'utilisateur rejette l'invite de notification (qui n'apparaît qu'une fois jusqu'à ce que l'utilisateur supprime et réinstalle l'application), nous continuons à nous enregistrer pour les notifications à distance. Le processus se poursuivra comme d'habitude, le périphérique sera enregistré mais l'utilisateur ne sera pas informé de la publication d'une nouvelle notification. Nous pouvons alors tirer parti de la connaissance des paramètres de notification actuels et du fait que l'utilisateur est déjà enregistré pour les notifications à distance afin de savoir si elles ont déjà été invitées (le bouton obtiendra alors le statut par défaut).

Cette méthode n'est pas sans faille. Si l'utilisateur accepte initialement de recevoir des notifications, mais décide ultérieurement de le désactiver manuellement depuis Paramètres, le bouton sera réglé sur l'état par défaut, mais, lors de l'activation, l'invite ne sera pas invitée à réactiver les notifications. Mais dans la plupart des cas, cela ne devrait pas avoir d’importance, car ce type d’UI n’est généralement affiché qu’une seule fois lors du processus d’inscription/d’inscription.

En ce qui concerne le code lui-même (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'
    }
}

Nous appelons cette méthode à partir de l'implémentation viewWillAppear(animated) de notre contrôleur de vue.

À ce stade, il reste encore quelques choses à faire: premièrement, chaque fois que vous appuyez sur le bouton (ce qui ne se produit que s'il est dans son état par défaut), vous devez inviter l'utilisateur à accepter ou refuser les notifications, et nous souhaitons également que notre interface utilisateur réagisse. correctement, quel que soit l'utilisateur choisit:

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

Et ensuite, nous devons implémenter les méthodes UIApplicationDelegate appropriées pour gérer l'événement. Comme il n'y a pas de notifications globales UIApplication pour celles-ci, nous envoyons les nôtres:

// 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)
}

Revenons maintenant à notre contrôleur de vue, nous devons gérer ces notifications. Ainsi, dans nos implémentations viewWillAppear(animated) et viewWillDisappear(animated), nous faisons:

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)
}

Et les gestionnaires de notification eux-mêmes:

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'
}

Prime

Que se passe-t-il si l'utilisateur a rejeté l'invite de notification et que nous souhaitons disposer d'un bouton pour le guider vers le panneau Paramètres où il peut le réactiver et faire réagir notre interface utilisateur en conséquence? Eh bien, je suis content que vous avez demandé.

Il existe un mécanisme très peu connu permettant de créer des liens profonds avec votre section App dans les paramètres (il existe depuis iOS 8, mais je n'ai pas eu la chance de le connaître avant quelques heures auparavant). Dans notre settings button touch handler nous faisons ceci:

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

Puisque nous voulons mettre à jour notre interface utilisateur pour refléter les modifications apportées par l'utilisateur, nous ajoutons un écouteur de notification pour UIApplicationDidBecomeActiveNotification dans notre implémentation viewWillAppear(animated) (n'oubliez pas de supprimer l'écouteur de viewWillDisapper(animated). Et enfin, à l'intérieur de la méthode de gestionnaire de notification correspondante. nous appelons simplement notre updateButtonStatus() existant.

20
boliva

Non, il n'y a aucun moyen de détecter la notification Push d'APNS dans l'application si elle est interdite.

Utilisez ce code pour vérifier s'il est autorisé et accédez à l'application pour l'activer:

UIRemoteNotificationType types = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
if (types == UIRemoteNotificationTypeNone)
{
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"app-settings:"]];
}

J'espère que cela t'aides!

4
Dharmesh Siddhpura

Utilisation: 

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications]; 

et NSUserDefaults. Stockez une clé (par exemple, HasSeenSystemPushNotification) dans true lorsque la boîte de dialogue système pour les notifications Push est présentée. 

Ensuite, vous pouvez vérifier la clé NSUD et le bool isRegisteredForRemoteNotifications pour voir si elle a été présentée/acceptée et faire votre travail en conséquence.

1
Josh O'Connor

Il existe un moyen rapide et peu coûteux de le faire. iOS9 cette méthode déléguée

- (void)didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken

s'appelle une fois lorsque le dialogue est affiché, puis un seconde fois lorsque l'utilisateur appuie sur "Ok". Ajoutez simplement un drapeau ici. 

Ensuite, chaque fois que vous souhaitez afficher le message personnalisé "rappeler à l'utilisateur comment activer le message Push", il vous suffit de cocher l'indicateur et vos paramètres de notification actuels (comme indiqué dans de nombreuses réponses ci-dessus).

- (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];
    }
}
1
ajmccall

Contrôle par cette méthode: -

[[UIApplication sharedApplication] isRegisteredForRemoteNotifications];

Mais si votre application prend en charge une version inférieure à iOS 8, vous devez procéder comme suit: -

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

}
0
Vizllx