Спросите у пользователя разрешение на получение UILocalNotifications в iOS 8

115

Я настроил локальные уведомления в делегате приложения, используя это:

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

Когда я запускаю приложение, а затем выхожу из него, я получаю сообщение об ошибке:

2014-06-07 11: 14: 16.663 CCA-TV [735: 149070] Попытка запланировать локальное уведомление {fire date = суббота, 7 июня 2014 г., 11:14:21 Тихоокеанское летнее время, часовой пояс = America / Los_Angeles (PDT) смещение -25200 (дневной свет), интервал повтора = 0, количество повторов = UILocalNotificationInfiniteRepeatCount, дата следующего возгорания = суббота, 7 июня 2014 г., 11:14:21 по тихоокеанскому летнему времени, информация о пользователе = (null)} с предупреждением но не получил разрешения от пользователя на отображение предупреждений

Как я могу получить необходимое разрешение для отображения предупреждений?

dannysandler
источник
1
Я думаю, что приложение однажды отклонило разрешение, вы можете попробовать включить его в настройках. Но, кстати, UILocalNotification не требует разрешения пользователя ..
iphonic 07
Попробуй registerUserNotificationSettings. Если бы это была iOS 8, эта ветка ответила бы на ваш вопрос. Но, вперед, посмотрите - stackoverflow.com/questions/24006998/…
raurora

Ответы:

237

Начиная с iOS 8 вам необходимо запрашивать разрешение пользователя на отображение уведомлений из вашего приложения, это применимо как для удаленных / push-уведомлений, так и для локальных. В Swift это можно сделать так:

Обновление для 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.
    }

Синтаксис Objective C также очень похож.

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

Чтобы проверить зарегистрированные в настоящее время типы уведомлений, вы можете использовать метод класса UIApplication,

- (UIUserNotificationSettings *)currentUserNotificationSettings

Поэтому, если пользователь отказался от вашего приложения, эта функция должна вернуть параметр без каких-либо типов.

Я написал об этом учебник, вы можете увидеть его здесь .

Satheeshwaran
источник
1
Если пользователь отказывает в разрешении, как определить это позже программно?
jjxtra
@satheeshwaran Когда я использую этот код, он отлично работает с симулятором с iOS8. Я хотел, чтобы цель развертывания моего приложения начиналась с iOS7. Поэтому, когда я запускаю этот код на устройстве iOS7, я получаю эту ошибку: dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings. Есть ли в Swift другой способ запросить у пользователя разрешения для работы в iOS7? пожалуйста помоги.
Рагхавендра
@Raghav UIUserNotificationSettings доступен только в iOS 8, и вы сталкиваетесь с правильным поведением. Вы не должны использовать это в iOS 7.
Сатишваран,
1
-1 для проверки версии iOS UIDevice. stackoverflow.com/a/25735175/1226304 answer имеет лучший подход для этого.
derpoliuk
3
@derpoliuk Обновил как в ответе для всеобщей пользы, ок ??
Satheeshwaran
38

Поместите этот код в контроллер представления, где вы сначала запрограммируете уведомления (если вы запрограммируете их при запуске, то это будет application:didFinishLaunchingWithOptions:):

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

В Swift:

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

Решения, которые проверяют номер версии системы, неоптимальны и подвержены ошибкам.

KPM
источник
Я бы использовал application.respondsToSelector(Selector("registerUserNotificationSettings"))иif ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
derpoliuk
7
Ну, это только потому, что вы используете его внутри, application:didFinishLaunchingWithOptions:что дает удобный applicationобъект :)
КПМ
18

Попробуйте это для 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];
  }
}

Для 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
источник
5

Я столкнулся с той же проблемой. Похоже, что в iOS 8 нам нужно сделать дополнительный шаг, обычно выполняемый внутри:

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

Вы можете использовать этот код, если хотите, чтобы он был обратно совместим:

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

Система запомнит решение и спросит только один раз.

ppalancica
источник
Лучше проверять версию iOS с помощью этого кода if ([[UIDevice currentDevice] .systemVersion floatValue] <10)
Мехул Чуахан
1

** Локальное уведомление с помощью трех кнопок для iOS8 +

// Кнопка: Я ПОЛУЧИЛ, НАПОМИНАТЬ ПОЗЖЕ, ПРОПУСТИТЬ **

        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
источник