Fragen Sie nach der Benutzerberechtigung zum Empfangen von UILocalNotifications in iOS 8

115

Ich habe lokale Benachrichtigungen im App-Delegaten eingerichtet. Verwenden Sie dazu Folgendes:

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

Wenn ich die App starte und dann beende, erhalte ich die Fehlermeldung:

2014-06-07 11: 14: 16.663 CCA-TV [735: 149070] Versuch, eine lokale Benachrichtigung zu planen {Branddatum = Samstag, 7. Juni 2014, 11:14:21 Uhr pazifische Sommerzeit, Zeitzone = Amerika / Los_Angeles (PDT) Offset -25200 (Tageslicht), Wiederholungsintervall = 0, Wiederholungszahl = UILocalNotificationInfiniteRepeatCount, nächstes Feuerdatum = Samstag, 7. Juni 2014, 11:14:21 Uhr Pacific Daylight Time, Benutzerinfo = (null)} mit einer Warnung Der Benutzer hat jedoch keine Berechtigung zum Anzeigen von Warnungen erhalten

Wie kann ich die erforderliche Berechtigung zum Anzeigen der Warnungen erhalten?

dannysandler
quelle
1
Ich denke, die App hat die Berechtigung einmal abgelehnt, Sie können versuchen, über Einstellungen zu aktivieren. Aber übrigens braucht UILocalNotification keine Benutzererlaubnis ..
iphonic
Versuchen Sie es registerUserNotificationSettings. Wäre es iOS 8 gewesen, hätte dieser Thread Ihre Frage beantwortet. Aber schauen Sie weiter - stackoverflow.com/questions/24006998/…
raurora

Antworten:

237

Da Sie in iOS 8 den Benutzer um Erlaubnis bitten müssen, Benachrichtigungen von Ihrer App anzuzeigen, gilt dies sowohl für Remote- / Push- als auch für lokale Benachrichtigungen. In Swift können Sie es so machen,

Update für 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.
    }

Die Ziel-C-Syntax ist ebenfalls sehr ähnlich.

- (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;
}

Um nach aktuell registrierten Benachrichtigungstypen zu suchen, können Sie die Methode der UIApplication-Klasse verwenden.

- (UIUserNotificationSettings *)currentUserNotificationSettings

Wenn der Benutzer zu Ihrer App Nein gesagt hat, sollte diese Funktion eine Einstellung ohne Typen zurückgeben.

Ich habe ein Tutorial darüber geschrieben, könnte man es sehen hier .

Satheeshwaran
quelle
1
Wie bestimmen Sie dies später programmgesteuert, wenn der Benutzer die Berechtigung verweigert?
jjxtra
@satheeshwaran Wenn ich diesen Code verwende, funktioniert er gut mit dem Simulator mit iOS8. Ich wollte das Bereitstellungsziel meiner App ab iOS7. Wenn ich diesen Code auf einem iOS7-Gerät ausführe, wird folgende Fehlermeldung angezeigt : dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings. Gibt es in Swift eine andere Möglichkeit, Benutzer nach Berechtigungen zu fragen, um in iOS7 arbeiten zu können? Bitte helfen Sie.
Raghavendra
@Raghav UIUserNotificationSettings ist nur unter iOS 8 verfügbar und Sie sehen sich mit dem richtigen Verhalten konfrontiert. Sie sollten dies nicht in iOS 7 verwenden.
Satheeshwaran
1
-1 zum Überprüfen des UIDevice der iOS-Version. Die Antwort von stackoverflow.com/a/25735175/1226304 hat einen besseren Ansatz, um dies zu tun.
derpoliuk
3
@derpoliuk Aktualisiert wie in der Antwort zum Nutzen aller, ok?
Satheeshwaran
38

Fügen Sie diesen Code in den View Controller ein, in dem Sie zuerst die Benachrichtigungen programmieren (wenn Sie sie beim Start programmieren, ist dies der Fall application:didFinishLaunchingWithOptions:):

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

In Swift:

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

Die Lösungen, die anhand der Versionsnummer des Systems getestet werden, sind nicht optimal und fehleranfällig.

KPM
quelle
Ich würde application.respondsToSelector(Selector("registerUserNotificationSettings"))andif ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
derpoliuk
7
Nun, das liegt nur daran, dass Sie es im Inneren verwenden, application:didFinishLaunchingWithOptions:was ein praktisches applicationObjekt darstellt :)
KPM
18

Versuchen Sie dies für Ziel-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];
  }
}

Für 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
quelle
5

Ich hatte gerade das gleiche Problem. Scheint, als müssten wir in iOS 8 einen zusätzlichen Schritt ausführen, der normalerweise im Inneren ausgeführt wird:

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

Sie können diesen Code verwenden, wenn Sie ihn abwärtskompatibel halten möchten:

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

Das System merkt sich die Entscheidung und fragt nur einmal.

ppalancica
quelle
Es ist besser, die iOS-Version mit diesem Code zu überprüfen, wenn ([[UIDevice currentDevice] .systemVersion floatValue] <10)
Mehul Chuahan
1

** Lokale Benachrichtigung mit drei Tasten für iOS8 +

// Button: Ich habe es genommen, später daran erinnert, es übersprungen **

        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
quelle