iOS push push notification: як визначити, чи користувач натискав на сповіщення, коли додаток знаходиться у фоновому режимі?


116

На цю тему існує багато ниток стаціонарних потоків, але я все ще не знайшов хорошого рішення.

Якщо додаток не в фоновому режимі, можна перевірити launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]в application:didFinishLaunchingWithOptions:виклику , щоб побачити , якщо він відкритий з повідомленням.

Якщо програма знаходиться у фоновому режимі, усі публікації пропонують використовувати application:didReceiveRemoteNotification:та перевірити стан програми. Але коли я експериментував (а також, як випливає з назви цього API), цей метод викликається при отриманні сповіщення замість натискання.

Отже, проблема полягає в тому, що якщо додаток запущено, а потім на фоновому режимі, і ви знаєте, що повідомлення отримано від application:didReceiveNotification( application:didFinishLaunchWithOptions:не спрацьовує в цьому пункті), як дізнатися, чи користувач відновив додаток, натиснувши сповіщення або просто натиснувши на значок програми? Оскільки, якщо користувач натиснув сповіщення, очікується відкрити сторінку, згадану в цьому сповіщенні. Інакше не повинно.

Я міг би використовувати handleActionWithIdentifierдля користувацьких сповіщень про дії, але це спрацьовує лише тоді, коли натискається спеціальна кнопка дії, а не тоді, коли користувач натискає на основну частину сповіщення.

Дякую.

Редагувати:

прочитавши одну відповідь нижче, я подумав, що таким чином я можу уточнити своє питання:

Як можна диференціювати ці два сценарії:

(A) 1.app переходить на другий план; 2. отримане повідомлення; 3. користувачі натискає на повідомлення; 4. додаток виходить на перший план

(B) 1.app переходить на другий план; 2. отримане повідомлення; 3. користувач ігнорує сповіщення та торкається піктограми програми пізніше; 4. додаток виходить на перший план

Оскільки application:didReceiveRemoteNotification:в обох випадках спрацьовує на етапі 2.

Або його слід application:didReceiveRemoteNotification:запускати лише на кроці 3 для (A), але я якось неправильно налаштував свою програму, тому я бачу це на кроці 2?


Використовуйте спеціальне значення словника для вашої корисної навантаження та дійте відповідно. Досить просто.
сульшиний

@soulshined словник у корисному навантаженні може відображати, чи користувач натиснув сповіщення, правда? наприклад, ваш друг A розмістив статтю B, ви можете сказати {user: A, article: B} у корисному навантаженні, тоді як додаток знаходиться у фоновому режимі, і ви отримаєте didReceiveRemoteNotification. Як дізнатися, коли додаток відновиться, чи слід відображати статтю?
Бао Лей

2
@soulshined Я читав документацію, і я навчався, що робить ReceiveRemoteNotification. Ви насправді читали моє запитання? Згідно офіційної документації Apple didReceiveRemoteNotification "повідомляється делегату, що запущена програма отримала віддалене повідомлення". Я запитую, що є хорошим способом повідомити, чи користувач натиснув сповіщення. Посилання SO, на яке ви згадували, є, коли програма запускається з нового початку, я запитую сценарій, коли програма знаходиться у фоновому режимі.
Бао Лей


1
@soulshined Добре, можливо, я не заявив це досить ясно. Я маю на увазі, якщо додаток буде повністю закрито, а не у фоновому режимі, так didFinishLaunching буде викликано. Але якщо ви запустите свою програму, а потім застосуєте фон, і тепер надходить сповіщення, і користувач натискає на сповіщення, і тепер didFinishLaunching не буде викликаний знову. Замість цього буде викликано applicationWillEnterForeground та applicationDidBecomeActive. Як ви можете сказати, що додаток виходить на перший план, оскільки користувач натискає сповіщення або піктограму додатка?
Бао Лей

Відповіді:


102

Добре, я нарешті зрозумів.

На цільових налаштуваннях tab Вкладка Можливості ➝ Фонові режими, якщо ви встановите прапорець "Віддалені сповіщення", application:didReceiveRemoteNotification:будуть спрацьовувати, як тільки надійде повідомлення (поки програма перебуває у фоновому режимі), і в цьому випадку немає способу визначити, чи користувач натисне сповіщення.

Якщо ви знімете цей прапорець, application:didReceiveRemoteNotification:його буде запущено лише тоді, коли ви натиснете сповіщення.

Дещо дивно, що встановлення цього вікна змінить, як поводиться один із методів делегування додатків. Було б приємніше, якщо це поле встановлено, Apple використовує два різні способи делегування для отримання та натискання повідомлень. Я думаю, що більшість розробників завжди хочуть знати, чи ввімкнено сповіщення чи ні.

Сподіваємось, це буде корисно для всіх, хто зіткнувся з цим питанням. Apple , теж не документували його явно тут , так що мені потрібно якийсь час , щоб з'ясувати.

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


6
У мене фонові режими повністю встановлені на "ВИМКНЕНО", але все одно отримую сповіщення, коли надходить повідомлення із програмою у фоновому режимі.
Готфрід

5
Чудово! Це мені допомогло. Однак шкода, що мені потрібно вимкнути віддалені сповіщення. Я хотів би попередньо вилучити дані, коли надійде push-повідомлення І виявить натискання користувача. Я не можу знайти спосіб досягти цього.
Пітер Феннема

1
Я встановив режим "Фоновий" на "УВІМКНЕНО" і ввімкнув віддалені сповіщення. Ще не вдається виявити подію сповіщення.
kalim sayyad

1
У мене така ж проблема Фоновому режиму встановлено значення "УВІМКНЕНО" і ввімкнено віддалене сповіщення, але все одно не отримувати сповіщення, коли повідомлення надходить до програми у фоновому режимі
Swapnil Dhotre

@Bao - Я думаю, що це спричинить відмову в Appstore, оскільки ця опція в основному використовується для завантаження вмісту, пов’язаного з повідомленням у фоновому режимі. Тож якщо ви не завантажуєте жодного вмісту, Apple може відхилити ваш додаток. developer.apple.com/library/ios/documentation/iPhone/Conceptual/…
niks

69

Я шукав те саме, що і ви, і насправді знайшов рішення, яке не вимагає відмітки віддаленого повідомлення.

Щоб перевірити, чи користувач натискав, чи програма перебуває у фоновому режимі чи активна, потрібно лише перевірити стан програми

-(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> Довідка про клас UIApplication> UIApplicationState


10
Що з приводу того, що програма UIApplicationStateInactive в результаті взаємодії користувача з Центром сповіщень (проведіть пальцем зверху) або Центром управління (проведіть пальцем знизу), коли програма з’являється на екрані. Мабуть, немає ніякого способу визначити, отримано APNS у неактивному стані чи користувач насправді натиснув його.
Костя Кім

1
@KostiaKim Ви маєте рацію, але це надзвичайний випадок ... окрім цього, ця відповідь є найбільш вірною з точки зору розділення між додатком на передньому плані ... користувач натискає ... додаток у фоновому режимі
Honey

Дякую, цей вид демістифікує все. Пам’ятайте, що для виклику методу делегата, коли програма знаходиться у фоновому режимі, сповіщення про натискання повинно містити content-availableключ, але тоді сповіщення повинно бути беззвучним (тобто не включати звук чи значок), як зазначено в офіційних документах .
Nickkk

1
@KostiaKim Насправді мені вдалося виправити проблему, не знаючи, чи відкрито центр керування, чи користувач насправді натискав на сповіщення, додавши логічне значення, встановлене на "істинне" func applicationDidEnterBackground(_ application: UIApplication)та "Неправильне" в func applicationDidBecomeActive(_ application: UIApplication)цьому, що дозволило мені показувати додаток сповіщення, коли додаток неактивний через центр управління або список сповіщень
DatForis

3
він міркує про те, чому Apple не представила іншу подію або просто додала прапор у метадані, щоб вказати, що користувач насправді взаємодіяв із сповіщенням. Здійснювати "висновок", чи користувач вчинив дії на основі навколишньої інформації про стан програми, є досить необґрунтованим ключовим бітом інформації, що впливає на очікування користувача щодо поведінки програми. Мабуть, єдине, що потрібно зробити - це створити власну дію, щоб відкрити додаток із цією інформацією?
Аллан Ніенхайс

20

Відповідно до iOS / XCode: як дізнатися, що додаток було запущено натисканням на сповіщення або на піктограму додатка трампліну? ви повинні перевірити стан програми у didReceiveLocalNotification, як це:

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

Хоча це не має для мене абсолютно сенсу, але, здається, працює.


1
У цьому сценарії це не буде працювати. Я пробував це раніше. Коли це прапорець встановлено (див. Мою прийняту відповідь для деталей), коли повідомлення надійде, ваш рядок із коментарем "// користувач натиснув сповіщення" буде введено, навіть якщо користувач не натискав сповіщення (сповіщення щойно надійшло ).
Бао Лей

3
Я не погоджуюсь. У моїх фонових можливостях перевірено "Віддалене сповіщення", і воно працює так, як описано у моїй відповіді. Я також перевірив "Вибір фону". Може, це викликає зміни?
Вернер Кратохвіл

ви можете, будь ласка, поставити +1 моїй відповіді? ;-) Мені все ж потрібні кілька голосів, щоб більше брати участь у стартовому потоці. Велике спасибі
Вернер Кратохвіл

Юпе, це рішення. tnx.
Афшин

Зауважте, що це буде помилковим позитивом, якщо сповіщення буде надіслано, коли користувач перебуває на іншому екрані (наприклад, якщо він знищить рядок стану, а потім отримає сповіщення від вашого додатка).
Кевін Купер

16

Якщо хтось хоче цього в швидкому 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
}

На якому тригері ми повинні додати цей код, didReceiveRemoteNotification або didFinishLaunchingWithOptions?
Дашрат

2
On didReceiveRemoteNotification
Хамід

@Hamid sh ,,,, я отримав сповіщення про push у всіх станах, тобто коли додаток знаходиться у підземному, фоновому режимі, закрити (припинено) ..! але моя проблема полягає в тому, як збільшувати кількість значків, коли додаток знаходиться у фоновому стані та закриває (припиняє) стан ???? Скажіть, будь ласка, докладно, як я це роблю ....? мій номер значка додатка збільшується лише тоді, коли програма перебуває у станковому стані .....? якщо можливо, скажіть мені коротко .......!
Кіран джадхав

8

Якщо у вас є "Фонові режими"> "Віддалені сповіщення" == ТАК, торкніться події сповіщення:

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

Це мені допомогло. Будь ласка, насолоджуйтесь :)


Я бачив, що Apple додала це, але не могла розібратися, як отримати власну корисну навантаження сповіщення таким чином.
судо

Ця функція викликається, коли додаток перебуває у фоновому стані та стає активним, а також коли програма починається із стану вбитого
Нікхіл Мускур

@NikhilMuskur, тільки якщо "віддалені сповіщення" включені, так?
Зорайр

@Zorayr yup правильно
Nikhil Muskur

8

Я також зіткнувся з цією проблемою - але на iOS 11 з новим UserNotificationsFramework.

Ось для мене це так:

  • Новий запуск: application:didFinishLaunchingWithOptions:
  • Отримано від стану припинення: application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
  • Отримано на передньому плані: userNotificationCenter(_:willPresent:withCompletionHandler:)
  • Отримано у фоновому режимі: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:

Це так зробити в iOS 11 +
OhadM

Це просто так складно 🤦‍♂️
Зорайр

4

У моєму випадку фоновий режим OFF не змінився. Однак, коли додаток було призупинено, і користувач натиснув сповіщення, я міг обробити цей випадок у цьому способі зворотного виклику:

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

}

Про це говорить офіційний спосіб Apple. Згідно з документом Apple, він буде викликатися щоразу, коли користувач взаємодіє з інтерфейсом push-повідомлення. Якщо додаток не знаходиться у фоновому режимі, він запустить додаток у фоновому режимі і викликає цей метод.
Райан

3

Для iOS 10 і вище помістіть це в AppDelegate, щоб дізнатися про те, що повідомлення натискається (працює навіть програма закрита або відкрита)

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

1
Це правильна відповідь для iOS 10+. Повне пояснення надано на іншій темі тут: stackoverflow.com/a/41783666/1761357 .
dead_can_dance

2

Є два функції функцій для обробки, отриманої в PushNotificationManagerкласі PushNotification :

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate{

}

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

@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()
}

Я також перевірив це як увімкнено, так і вимкнено стан віддаленого сповіщення (у фонових режимах)


1

SWIFT 5.1

UIApplication.State не працювало для мене, тому що як тільки я читаю відбитки пальців (відображається модальний) у моєму додатку, повідомлення також викидається у верхню панель і користувач повинен натиснути його.

Я створив

public static var isNotificationFromApp: Bool = false

в AppDelegateі я поставив його trueв своєму запуску , viewControllerа потім в моєму повідомленні storyboard/ viewControllerя просто перевірити , що :)

Сподіваюся, це може стати в нагоді


-7

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

З документації Apple ви повинні використовувати ці методи для завантаження нового вмісту, пов’язаного з push-повідомленням. Також для цього потрібно включити Віддалене сповіщення з фонових режимів, а навантажувальний навантажувальний сповіщення повинен містити content-availableключ із значенням, встановленим на 1. З докладнішою інформацією див. Розділ Використання натискань сповіщень для ініціювання розділу завантаження з Apple doc тут .

Інший спосіб полягає в тому, щоб підрахунок значків в корисному навантаженні сповіщення про push. Тож наступного разу, коли ваша програма запуститься, ви можете перевірити кількість значків програми. Якщо його тертка дорівнює нулю, виконайте також свою операцію та кількість значків нуля / очищення значка також із сервера.

Сподіваюся, це вам допоможе.


@bhusan Ви читали деталі мого запитання? Я бачу, як didReceiveRemoteNotification викликали, коли повідомлення надходить (перш ніж користувач натискає на нього). Я хотів з’ясувати, чи користувач натискав на нього.
Бао Лей

Ви не відповіли на запитання ОП. Він не просто хоче знати, що надійшло повідомлення. Він хоче знати, чи користувач відкрив додаток, натиснувши це віддалене сповіщення.
Джо С
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.