IOS push notification: как определить, прослушивает ли пользователь уведомление, когда приложение находится в фоновом режиме?

В этой теме много потоков stackoverflow, но я до сих пор не нашел хорошего решения.

Если приложение не находится в фоновом режиме, я могу проверить launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] в application:didFinishLaunchingWithOptions: вызов, чтобы узнать, открыт ли он из уведомления.

Если приложение находится в фоновом режиме, все сообщения предлагают использовать application:didReceiveRemoteNotification: и проверить состояние приложения. Но когда я экспериментировал (а также, как указывает название этого API), этот метод вызывается, когда уведомление получено, а не постукивается.

Таким образом, проблема заключается в том, что приложение запускается, а затем заходит в фоновом режиме, и вы знаете, что уведомление получено из application:didReceiveNotification (application:didFinishLaunchWithOptions: не будет запускаться на данном этапе), откуда вы узнаете, возобновил ли пользователь приложение от нажатия на уведомление или просто нажав значок приложения? Поскольку, если пользователь прослушивает уведомление, ожидание заключается в том, чтобы открыть страницу, указанную в этом уведомлении. В противном случае это не должно быть.

Я могу использовать handleActionWithIdentifier для уведомлений о специальных действиях, но это запускается только при нажатии на кнопку пользовательского действия, а не при нажатии пользователем основной части уведомления.

Спасибо.

EDIT:

после прочтения одного из ответов ниже, я подумал, что я могу уточнить свой вопрос:

Как мы можем различать эти 2 сценария:

(A) 1.app переходит к фону; 2. полученная информация; 3. пользовательский ответ на уведомление; 4. приложение переходит на передний план

(B) 1.app переходит на задний план; 2. полученная информация; 3. пользователь игнорирует уведомление и краны на значке приложения позже; 4. приложение переходит на передний план

Так как application:didReceiveRemoteNotification: запускается в обоих случаях на шаге 2.

Или, если application:didReceiveRemoteNotification: запускается только на шаге 3 для (A), но я как-то неправильно настроил свое приложение, поэтому я вижу его на шаге 2?

Ответ 1

ОК, я, наконец, понял.

В целевых настройках ➝ вкладка "Возможности" ➝ "Режимы фона", если вы отметите "Удаленные уведомления", application:didReceiveRemoteNotification: будет запущен сразу после получения уведомления (пока приложение будет в фоновом режиме), и в этом случае не может сказать, будет ли пользователь использовать уведомление.

Если вы снимите этот флажок, application:didReceiveRemoteNotification: будет запущен только при нажатии на уведомление.

Немного странно, что проверка этого поля изменит поведение одного из методов делегирования приложения. Было бы лучше, если этот флажок установлен, Apple использует два разных метода делегирования для приема уведомлений и уведомления. Я думаю, что большинство разработчиков всегда хотят знать, включено ли уведомление или нет.

Надеюсь, это будет полезно для всех, кто сталкивается с этой проблемой. Apple также не документировала это явно здесь, поэтому мне потребовалось некоторое время, чтобы понять.

введите описание изображения здесь

Ответ 2

Я искал то же самое, что и вы, и фактически нашел решение, для которого не требуется дистанционное уведомление.

Чтобы проверить, был ли пользователь нажат, или приложение находится в фоновом режиме или активно, вам просто нужно проверить состояние приложения в

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{

    if(application.applicationState == UIApplicationStateActive) {

        //app is currently active, can update badges count here

    }else if(application.applicationState == UIApplicationStateBackground){

        //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here

    }else if(application.applicationState == UIApplicationStateInactive){

        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here

    }

Подробнее:

Ссылка на UIKit Framework > Ссылка на класс UIApplication > UIApplicationState

Ответ 3

Согласно iOS/XCode: как узнать, что приложение было запущено с щелчком на уведомлении или на значке приложения для трамплинов? вы должны проверить состояние приложения в didReceiveLocalNotification следующим образом:

if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive)
{
    // user has tapped notification
}
else
{
    // user opened app from app icon
}

Хотя это не имеет для меня никакого смысла, похоже, что это работает.

Ответ 4

Если кто-то хочет это в Swift 3.0

switch application.applicationState {
    case .active:
        //app is currently active, can update badges count here
        break
    case .inactive:
        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here
        break
    case .background:
        //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
        break
    default:
        break
    }

для быстрой 4

switch UIApplication.shared.applicationState {
case .active:
    //app is currently active, can update badges count here
    break
case .inactive:
    //app is transitioning from background to foreground (user taps notification), do what you need when user taps here
    break
case .background:
    //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
    break
default:
    break
}

Ответ 5

Если у вас есть "Фоновые режимы" > "Удаленные уведомления" отмечены == ДА, прикоснитесь к событию уведомления, прибудет:

-(void)userNotificationCenter:(UNUserNotificationCenter *)center **didReceiveNotificationResponse**:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler.

Это помогло мне. Пожалуйста, наслаждайтесь:)

Ответ 6

Я тоже столкнулся с этой проблемой - но на iOS 11 с новой UserNotifications Framework.

Вот для меня это так:

  • Новый запуск: application:didFinishLaunchingWithOptions:
  • Получено на application:didReceiveRemoteNotification:fetchCompletionHandler:
  • Получено в фоновом режиме: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:

Ответ 7

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

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler completionHandler: @escaping () -> Void) {

}

Ответ 8

Для iOS 10 и выше, поместите это в AppDelegate, чтобы узнать, что уведомление касается (работает, даже приложение закрыто или открыто)

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
print("notification tapped here")
}

Ответ 9

Есть две функции для обработки полученных push-уведомлений.

Как я тестировал первый на триггере, как только пришло уведомление

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

    completionHandler(UNNotificationPresentationOptions.alert)

    //OnReceive Notification
    let userInfo = notification.request.content.userInfo
    for key in userInfo.keys {
         Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler([])

}

И второй, когда нажал на уведомление:

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

    //OnTap Notification
    let userInfo = response.notification.request.content.userInfo
    for key in userInfo.keys {
        Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler()
}

Я тоже тестировал его с обоими состояниями удаленного оповещения (в фоновом режиме).

Ответ 10

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

Из документации яблок вы должны использовать эти методы для загрузки нового контента, связанного с push-уведомлением. Кроме того, для этого вам необходимо включить удаленное уведомление из фоновых режимов, а полезная нагрузка push-уведомления должна содержать ключ content-available с его значением, установленным в 1. Из дополнительной информации см. Раздел Использование уведомлений Push Notification to Initiate Download из Apple Doc здесь.

Другим способом является присвоение значка в полезной нагрузке push-уведомления. Поэтому в следующий раз, когда ваше приложение запускается, вы можете проверить количество значков приложений. Если его терка больше нуля, выполните свою операцию и нуль/очистить количество значков с сервера.

Надеюсь, это поможет вам.