Demander l'autorisation de l'utilisateur pour recevoir des notifications UILocal dans iOS 8

115

J'ai configuré des notifications locales dans le délégué d'application en utilisant ceci:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    UILocalNotification *notification = [[UILocalNotification alloc]init];
    [notification setAlertBody:@"Watch the Latest Episode of CCA-TV"];
    [notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:5]];
    [notification setTimeZone:[NSTimeZone defaultTimeZone]];
    [application setScheduledLocalNotifications:[NSArray arrayWithObject:notification]];
}

Lorsque j'exécute l'application, puis que je la quitte, je reçois une erreur disant:

2014-06-07 11: 14: 16.663 CCA-TV [735: 149070] Tentative de planification d'une notification locale {fire date = samedi 7 juin 2014 à 11:14:21 Pacific Daylight Time, time zone = America / Los_Angeles (PDT) offset -25200 (Daylight), intervalle de répétition = 0, nombre de répétitions = UILocalNotificationInfiniteRepeatCount, prochaine date d'incendie = samedi 7 juin 2014 à 11:14:21 Pacific Daylight Time, user info = (null)} avec une alerte mais n'ont pas reçu la permission de l'utilisateur d'afficher des alertes

Comment puis-je obtenir l'autorisation nécessaire pour afficher les alertes?

Dannysandler
la source
1
Je pense que l'application a rejeté l'autorisation une fois, vous pouvez essayer d'activer à partir des paramètres. Mais au fait, UILocalNotification n'a pas besoin de la permission de l'utilisateur ..
iphonic
Essayez registerUserNotificationSettings. Si cela avait été iOS 8, ce fil aurait répondu à votre question. Mais, allez-y, jetez un œil - stackoverflow.com/questions/24006998/…
raurora

Réponses:

237

Depuis iOS 8, vous devez demander l'autorisation de l'utilisateur pour afficher les notifications de votre application, cela s'applique à la fois aux notifications à distance / push et locales. Dans Swift, vous pouvez le faire comme ça,

Mise à jour pour Swift 2.0

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    // Override point for customization after application launch.
    if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:")))
    {
        let notificationCategory:UIMutableUserNotificationCategory = UIMutableUserNotificationCategory()
        notificationCategory.identifier = "INVITE_CATEGORY"
        notificationCategory.setActions([replyAction], forContext: UIUserNotificationActionContext.Default)

        //registerting for the notification.
        application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes:[.Sound, .Alert, .Badge], categories: nil))
    }
    else
    {
       //do iOS 7 stuff, which is pretty much nothing for local notifications.
    }
    return true
}

Swift 3.2

if(UIApplication.instancesRespond(to: #selector(UIApplication.registerUserNotificationSettings(_:)))){
     let notificationCategory:UIMutableUserNotificationCategory = UIMutableUserNotificationCategory()
     notificationCategory.identifier = "INVITE_CATEGORY"
     notificationCategory.setActions([replyAction], forContext: UIUserNotificationActionContext.Default)

     //registerting for the notification.
        application.registerUserNotificationSettings(UIUserNotificationSettings(types:[.sound, .alert, .badge], categories: nil))
}
else{
        //do iOS 7 stuff, which is pretty much nothing for local notifications.
    }

La syntaxe Objective C est également très similaire.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]){
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
    }
    // Override point for customization after application launch.
    return YES;
}

Pour vérifier les types de notification actuellement enregistrés, vous pouvez utiliser la méthode de la classe UIApplication,

- (UIUserNotificationSettings *)currentUserNotificationSettings

Donc, si l'utilisateur a dit non à votre application, cette fonction devrait renvoyer un paramètre sans aucun type.

J'ai écrit un tutoriel à ce sujet, vous pouvez le voir ici .

Satheeshwaran
la source
1
Si l'utilisateur refuse l'autorisation, comment déterminez-vous cela ultérieurement par programme?
jjxtra
@satheeshwaran Quand j'utilise ce code, cela fonctionne bien avec le simulateur avec iOS8. Je voulais la cible de déploiement de mon application à partir d'iOS7. Alors, quand je lance ce code sur un appareil iOS 7, je reçois cette erreur: dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings. Existe-t-il un autre moyen dans Swift de demander à l'utilisateur des autorisations afin de travailler dans iOS7? veuillez aider.
Raghavendra
@Raghav UIUserNotificationSettings n'est disponible qu'à partir d'iOS 8 et ce à quoi vous êtes confronté est le bon comportement. Vous ne devriez pas utiliser cela dans iOS 7.
Satheeshwaran
1
-1 pour vérifier la version iOS UIDevice. La réponse stackoverflow.com/a/25735175/1226304 a une meilleure approche pour ce faire.
derpoliuk
3
@derpoliuk Mise à jour comme dans la réponse pour le bénéfice de tous, ok ??
Satheeshwaran
38

Mettez ce code dans le contrôleur de vue où vous programmerez d'abord les notifications (si vous les programmez au lancement, alors ce sera application:didFinishLaunchingWithOptions:):

if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
    [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeSound categories:nil]];
}

Dans Swift:

if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:"))) {
    UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert | .Sound, categories: nil))
}

Les solutions qui testent par rapport au numéro de version du système sont sous-optimales et sujettes aux erreurs.

KPM
la source
J'utiliserais application.respondsToSelector(Selector("registerUserNotificationSettings"))etif ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
derpoliuk
7
Eh bien, c'est seulement parce que vous l'utilisez à l'intérieur, application:didFinishLaunchingWithOptions:ce qui fournit un applicationobjet pratique :)
KPM
18

Essayez ceci pour Objective-C:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:    (NSDictionary *)launchOptions
{
// are you running on iOS8?
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) 
  {
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
    [application registerUserNotificationSettings:settings];
  } 
else // iOS 7 or earlier
  {
    UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
    [application registerForRemoteNotificationTypes:myTypes];
  }
}

Pour Swift:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
// Override point for customization after application launch.
 if(UIApplication.instancesRespondToSelector(Selector("registerUserNotificationSettings:")))
 {
    application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: UIUserNotificationType.Sound | UIUserNotificationType.Alert | UIUserNotificationType.Badge, categories: nil))
 }
 else
 {
    //
 }
return true
}
Nagarjun
la source
5

J'ai juste fait face au même problème. On dirait que dans iOS 8, nous devons faire une étape supplémentaire, généralement effectuée à l'intérieur:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { /*...*/ }

Vous pouvez utiliser ce code si vous souhaitez le garder compatible avec les versions antérieures:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)])
    {
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]];
    }
#endif

Le système se souviendra de la décision et ne demandera qu'une seule fois.

ppalancica
la source
Mieux vaut vérifier la version iOS avec ce code si ([[UIDevice currentDevice] .systemVersion floatValue] <10)
Mehul Chuahan
1

** Notification locale avec action à trois boutons pour iOS8 +

// Bouton: JE L'AI PRIS, RAPPELER PLUS TARD, SAUTER **

        let completeAction = UIMutableUserNotificationAction()
        completeAction.identifier = "COMPLETE_TODO"
        completeAction.title = "I TOOK IT"
        completeAction.activationMode = .Background
        completeAction.destructive = true
        completeAction.authenticationRequired = false

        let remindAction = UIMutableUserNotificationAction()
        remindAction.identifier = "REMIND_TODO"
        remindAction.title = "REMIND LATER"
        remindAction.activationMode = .Background
        remindAction.destructive = false
        //  remindAction.authenticationRequired = false

        let skipAction = UIMutableUserNotificationAction()
        skipAction.identifier = "SKIP_TODO"
        skipAction.title = "SKIP IT"
        skipAction.activationMode = .Background
        skipAction.destructive = false
        skipAction.authenticationRequired = false


        let todoCategory = UIMutableUserNotificationCategory()
        todoCategory.identifier = "TODO_CATEGORY"
        todoCategory.setActions([completeAction, remindAction, skipAction], forContext: .Default)
        todoCategory.setActions([completeAction,remindAction,skipAction], forContext: .Minimal)


        if application.respondsToSelector("isRegisteredForRemoteNotifications")
        {

            let categories = NSSet(array: [todoCategory,todoVideoCategory])
            let types:UIUserNotificationType = ([.Alert, .Sound, .Badge])

            let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: categories as? Set<UIUserNotificationCategory>)

            application.registerUserNotificationSettings(settings)
            application.registerForRemoteNotifications()

        }

    }
PSS
la source