Приложение didReceiveLocalNotification не запускается iOS7

Проблема:

- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification

не вызывается иногда с iOS7. Это не значит, что мы планируем уведомление:

alarm.fireDate = [[NSDate date] dateByAddingTimeInterval:0.1];
[app scheduleLocalNotification:alarm];

или

[app presentLocalNotificationNow:alarm];

Мои мысли: Это происходит в случае, когда пользователь переместится до завершения анимации оповещений. И если он подождал всего полсекунды до того, как он соскользнет - уведомление будет уволено, и приложение поступит так, как ожидалось. Вероятно, проблема заключается в том, что приложение переходит на передний план до получения уведомления.

Кто-нибудь встречал это? Это ошибка? Любое решение? Спасибо!

Ответ 1

Является ли ваше приложение фоном или передним планом? Если это на первом плане, я уверен, что этот метод вызывается. Если это не так, возможно, вы не помещаете этот метод в свой делегат приложения.

Если это на фоне, вот несколько возможных сценариев:

  • Ваше приложение было убито пользователем или ОС. В этом случае, когда пользователь пробуждает ваше приложение, нажав на уведомление в центре уведомлений (или прокручивая экран блокировки), ваш делегат приложения будет иметь вызванный метод application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions. Вы можете получить уведомление от этого метода:

    [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];

  • Ваше приложение находится в фоновом режиме, и пользователь нажимает на уведомление в центре уведомлений или экране блокировки. В этом случае методы делегатов будут вызываться. В документации указано, что didReceiveLocalNotification: используется, когда приложение находится на переднем плане:

Если приложение работает на переднем плане, нет предупреждений, значков, или звук; вместо этого приложение: didReceiveLocalNotification: метод вызывается, если делегат реализует его.

Итак, надеюсь, вы сможете принять обоснованное решение о том, что делать, когда вы получите уведомление. Я лично считаю немного странным, что мы не получаем объект уведомления, когда пользователь запускает приложение, нажав на значок (а не на уведомление). Но сейчас я просто пишу свою логику.

Ответ 2

Apple явно упоминает в своей документации (Руководство по программированию локального и удаленного уведомлений), что вызываются разные методы в зависимости от того, в каком состоянии находится приложение, и какое действие предпринимает пользователь (как упоминал Энрико).

Резюме:

  • Пользователь вводит пользовательскую кнопку действия в уведомлении iOS 8. В этом случае iOS вызывает любое приложение: handleActionWithIdentifier: forRemoteNotification: completeHandler: или application: handleActionWithIdentifier: forLocalNotification: completeHandler:. В обоих методах вы получаете идентификатор действия, чтобы вы могли определить, какую кнопку пользователь прослушивал. Вы также получаете либо удаленный, либо локальный объект уведомления, чтобы вы могли получить любую информацию, необходимую для обработки действия.
  • Пользователь удаляет кнопку по умолчанию в оповещении или кранах (или кликах) значка приложения.... система запускает приложение, а приложение вызывает приложение для своих делегатов: didFinishLaunchingWithOptions: метод, передача в полезной нагрузке уведомления (для удаленных уведомлений) или локальном уведомлении (для локальных уведомлений)....
  • Уведомление доставляется, когда приложение работает на переднем плане. Приложение вызывает приложение метода UIApplicationDelegate: didReceiveLocalNotification: или приложение: didReceiveRemoteNotification: fetchCompletionHandler:.

Так что didReceiveLocalNotification запускается только после того, как приложение уже запущено и находится на переднем плане. Вы также должны обработать второй сценарий, в котором он не запущен, для которого у яблока есть следующий пример кода:

Objective-C:

- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
    if (localNotif) {
        NSString *itemName = [localNotif.userInfo objectForKey:ToDoItemKey];
        [viewController displayItem:itemName];  // custom method
        app.applicationIconBadgeNumber = localNotif.applicationIconBadgeNumber-1;
    }
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
    return YES;
}

Swift (приближение, предоставленное мною):

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    if let localNotification = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {
            if let itemName = localNotification.userInfo?[ToDoItemKey] as? String {
                handleNotification(localNotification)
                application.applicationIconBadgeNumber = localNotification.applicationIconBadgeNumber - 1
            }
    }
    .
    .
    .
}