Notifica push iOS: come rilevare se l'utente ha toccato la notifica quando l'app è in background?


116

Ci sono molti thread di stackoverflow su questo argomento, ma non ho ancora trovato una buona soluzione.

Se l'applicazione non è in background, posso verificare launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]in application:didFinishLaunchingWithOptions:chiamata per vedere se è aperto da una notifica.

Se l'app è in background, tutti i post suggeriscono di utilizzare application:didReceiveRemoteNotification:e controllare lo stato dell'applicazione. Ma come ho sperimentato (e anche come suggerisce il nome di questa API), questo metodo viene chiamato quando viene ricevuta la notifica, invece di essere toccato.

Quindi il problema è che, se l'app viene avviata e poi in background e sai che una notifica viene ricevuta da application:didReceiveNotification( application:didFinishLaunchWithOptions:non si attiverà a questo punto), come fai a sapere se l'utente ha ripreso l'app da toccando la notifica o semplicemente toccando il icona dell'app? Perché se l'utente ha toccato la notifica, l'aspettativa è di aprire la pagina menzionata in quella notifica. Altrimenti non dovrebbe.

Potrei usarlo handleActionWithIdentifierper le notifiche di azioni personalizzate, ma questo viene attivato solo quando viene toccato un pulsante di azione personalizzato, non quando l'utente tocca il corpo principale della notifica.

Grazie.

MODIFICARE:

dopo aver letto una risposta di seguito, ho pensato in questo modo di poter chiarire la mia domanda:

Come possiamo differenziare questi 2 scenari:

(A) 1.app va in background; 2. notifica ricevuta; 3. l'utente tocca la notifica; 4. l'app entra in primo piano

(B) 1.app va in background; 2. notifica ricevuta; 3. l'utente ignora la notifica e tocca successivamente l'icona dell'app; 4. l'app entra in primo piano

Poiché application:didReceiveRemoteNotification:viene attivato in entrambi i casi al passaggio 2.

Oppure, dovrebbe application:didReceiveRemoteNotification:essere attivato nel passaggio 3 solo per (A), ma in qualche modo ho configurato la mia app in modo errato, quindi lo vedo al passaggio 2?


Utilizza un valore di dizionario personalizzato per il tuo payload e agisci di conseguenza. Abbastanza semplice.
soulshined

@soulshined un dizionario nel payload può rappresentare se l'utente ha toccato la notifica, giusto? Ad esempio, il tuo amico A ha pubblicato un articolo B, puoi dire {utente: A, articolo: B} nel payload, mentre l'app è in background e ottieni didReceiveRemoteNotification. Come fai a sapere quando l'app riprende, se devi visualizzare l'articolo?
Bao Lei

2
@soulshined Ho letto la documentazione e mi sono informato su cosa fa didReceiveRemoteNotification. Hai davvero letto la mia domanda? Secondo la documentazione ufficiale di Apple, didReceiveRemoteNotification "comunica al delegato che l'app in esecuzione ha ricevuto una notifica remota". Chiedo qual è un buon modo per sapere se l'utente ha toccato una notifica. Il collegamento SO a cui hai fatto riferimento è per quando l'app viene avviata da un nuovo inizio, sto chiedendo lo scenario quando l'app è in background.
Bao Lei


1
@soulshined OK forse non l'ho detto abbastanza chiaro. Voglio dire, se l'app viene chiusa completamente, non in background, sì, didFinishLaunching verrà chiamato. Ma se avvii la tua app, quindi l'app in background, e ora arriva una notifica e l'utente tocca la notifica, e ora didFinishLaunching non verrà chiamato di nuovo. Verranno invece chiamati applicationWillEnterForeground e applicationDidBecomeActive. Come puoi sapere che l'app sta entrando in primo piano perché l'utente ha toccato la notifica o l'icona dell'app?
Bao Lei

Risposte:


102

OK ho finalmente capito.

Nelle impostazioni di destinazione ➝ scheda Funzionalità ➝ Modalità in background, se selezioni "Notifiche remote", application:didReceiveRemoteNotification:verranno attivate non appena arriva la notifica (purché l'app sia in background), e in tal caso non c'è modo di dire se l'utente toccherà la notifica.

Se deselezioni quella casella, application:didReceiveRemoteNotification:verrà attivato solo quando tocchi la notifica.

È un po 'strano che la selezione di questa casella cambierà il comportamento di uno dei metodi delegati dell'app. Sarebbe più bello se quella casella fosse selezionata, Apple utilizza due diversi metodi delegati per la ricezione delle notifiche e il tocco delle notifiche. Penso che la maggior parte degli sviluppatori voglia sempre sapere se una notifica viene attivata o meno.

Si spera che questo sia utile per chiunque altro si imbatta in questo problema. Anche Apple non lo ha documentato chiaramente qui, quindi mi ci è voluto un po 'per capirlo.

inserisci qui la descrizione dell'immagine


6
Ho impostato le modalità in background completamente su "OFF", ma ricevo comunque una notifica quando arriva una notifica con l'app in modalità background.
Gottfried

5
Grande! Questo mi ha aiutato. È un peccato, tuttavia, dover disattivare le notifiche remote. Vorrei precaricare i dati quando arriva una notifica push E rilevare il tocco dell'utente. Non riesco a trovare un modo per raggiungere questo obiettivo.
Peter Fennema

1
Ho impostato la modalità Background su "ON" e abilito le notifiche remote. Non riesco ancora a rilevare l'evento di notifica.
kalim sayyad

1
Ho lo stesso problema La modalità in background è impostata su "ON" e la notifica remota è abilitata, ma non ricevo ancora la notifica quando la notifica arriva all'app in modalità in background
Swapnil Dhotre

@Bao - Penso che causerà il rifiuto su Appstore, poiché questa opzione è fondamentalmente utilizzata per scaricare contenuti relativi alla notifica in background. Quindi, se non stai scaricando alcun contenuto, Apple potrebbe rifiutare la tua app. developer.apple.com/library/ios/documentation/iPhone/Conceptual/…
niks

69

Stavo cercando la tua stessa cosa e in realtà ho trovato una soluzione che non richiede la notifica remota per essere spuntata.

Per verificare se l'utente ha toccato, o l'app è in background o è attiva, devi solo controllare lo stato dell'applicazione in

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

    }

Per maggiori informazioni controlla:

Riferimento framework UIKit> Riferimento classe UIApplication> UIApplicationState


10
Che dire se l'app è UIApplicationStateInactive a seguito dell'interazione dell'utente con il centro di notifica (scorrimento dall'alto) o il centro di controllo (scorrimento dal basso) mentre l'app è sullo schermo. Apparentemente, non c'è modo di sapere se APNS è stato ricevuto in stato inattivo o se l'utente lo ha effettivamente toccato.
Kostia Kim,

1
@KostiaKim Hai ragione, ma questo è un caso super limite ... a parte questo, questa risposta è la più valida in termini di separazione tra le app in primo piano ... il tocco dell'utente ... l'app in background
Honey

Grazie, questo tipo di demistifica tutto. Ricorda che per poter chiamare il metodo delegato quando l'app è in background, la notifica push deve includere la content-availablechiave, ma poi la notifica deve essere silenziosa (cioè non includere un suono o un badge) come indicato nei documenti ufficiali .
Nickkk

1
@KostiaKim Sono stato effettivamente in grado di risolvere il problema di non sapere se il centro di controllo era aperto o se l'utente ha effettivamente toccato la notifica aggiungendo un valore booleano impostato su true in func applicationDidEnterBackground(_ application: UIApplication)e false in func applicationDidBecomeActive(_ application: UIApplication)questo mi ha permesso di mostrare l'app in notifiche quando l'app è inattiva a causa del centro di controllo o dell'elenco delle notifiche
DatForis

3
mi stupisce il motivo per cui Apple non ha presentato un evento diverso o semplicemente ha aggiunto un flag nei metadati per indicare che l'utente ha effettivamente interagito con la notifica. Dover "dedurre" se l'utente ha intrapreso un'azione in base alle informazioni ambientali sullo stato dell'applicazione è piuttosto irragionevole per un bit di informazioni chiave che influisce sulle aspettative dell'utente del comportamento dell'applicazione. Forse l'unica cosa da fare è creare un'azione personalizzata per aprire l'app con quelle informazioni?
Allan Nienhuis

20

Secondo iOS / XCode: come sapere che l'app è stata avviata con un clic sulla notifica o sull'icona dell'app trampolino di lancio? devi controllare lo stato dell'applicazione in didReceiveLocalNotification in questo modo:

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

Sebbene non abbia del tutto senso per me, sembra funzionare.


1
Non funzionerebbe in questo scenario. L'ho provato prima. Quando quella casella di controllo è stata selezionata (vedi la mia risposta accettata per i dettagli), quando arriva la notifica, verrà inserita la tua riga con il commento "// l'utente ha toccato la notifica", anche se l'utente non ha toccato la notifica (la notifica è appena arrivata ).
Bao Lei

3
Non sono d'accordo. Ho selezionato "Notifiche remote" nelle mie capacità in background e funziona nel modo descritto nella mia risposta. Ho anche selezionato "Recupero in background". Forse questo causa il cambiamento?
Werner Kratochwil

potresti per favore +1 la mia risposta? ;-) Ho ancora bisogno di alcuni voti per partecipare di più a stackoverflow. Grazie mille
Werner Kratochwil

Yupe, questa è la soluzione. tnx.
Afshin

Tieni presente che questo sarà un falso positivo se la notifica viene inviata mentre l'utente si trova su una schermata diversa (ad esempio, se apre la barra di stato e poi riceve una notifica dalla tua app).
Kevin Cooper

16

Se qualcuno lo vuole in 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
    }

per swift 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
}

Su quale trigger dovremmo aggiungere questo codice, didReceiveRemoteNotification o didFinishLaunchingWithOptions?
Dashrath

2
Su didReceiveRemoteNotification
Hamid Shahsavari

@Hamid sh ,,,, Ho ricevuto una notifica push in tutti gli stati, ad esempio quando l'app è in primo piano, in background, in chiusura (terminata) ..! ma il mio problema è come aumentare il conteggio dei badge quando l'app è in background e chiudere (terminare) lo stato ???? Per favore dimmi in dettaglio come lo faccio ....? il numero di badge dell'app aumenta solo quando l'app è in primo piano .....? se possibile per favore dimmelo in breve .......!
Kiran jadhav

8

Se hai selezionato "Modalità in background"> ​​"Notifiche remote" == SÌ, tocca l'evento di notifica che arriverà tra:

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

Mi ha aiutato. Divertitevi :)


Ho visto che Apple lo ha aggiunto ma non è riuscito a capire come ottenere il payload personalizzato della notifica in questo modo.
sudo

Questa funzione viene chiamata quando l'app è in uno stato in background e diventa attiva e anche quando l'app viene avviata dallo stato ucciso
Nikhil Muskur

@NikhilMuskur solo se le "notifiche remote" sono abilitate, vero?
Zorayr

@Zorayr sì, è vero
Nikhil Muskur il

8

Mi sono imbattuto anche in questo problema, ma su iOS 11 con il nuovo UserNotificationsFramework.

Qui per me è così:

  • Nuovo lancio: application:didFinishLaunchingWithOptions:
  • Ricevuto da uno stato di terminazione: application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
  • Ricevuto in primo piano: userNotificationCenter(_:willPresent:withCompletionHandler:)
  • Ricevuto in background: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:

Questo è il modo per farlo in iOS 11 +
OhadM

È così complicato 🤦‍♂️
Zorayr

4

Nel mio caso, la modalità sfondo OFF non ha fatto alcuna differenza. Tuttavia, quando l'app è stata sospesa e l'utente ha toccato la notifica, ho potuto gestire il caso con questo metodo di richiamata:

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

}

Questo è il modo ufficiale in cui dice Apple. Secondo il documento di Apple, verrà chiamato ogni volta che l'utente interagisce con l'interfaccia utente delle notifiche push. Se l'app non è in background, avvierà l'app in modalità background e chiamerà questo metodo.
Ryan

3

Per iOS 10 e versioni successive, mettilo in AppDelegate, per sapere che la notifica è toccata (funziona anche se l'app è chiusa o aperta)

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

1
Questa è la risposta corretta per iOS 10+. Spiegazione completa fornita su un altro thread qui: stackoverflow.com/a/41783666/1761357 .
dead_can_dance

2

Ci sono due funzioni per l'handle ricevuto PushNotification all'interno della PushNotificationManagerclasse:

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate{

}

Come ho provato il primo trigger non appena è arrivata la notifica

@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([])

}

E il secondo quando si tocca la notifica:

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

L'ho anche testato con entrambi gli stati ON e OFF della notifica remota (in modalità in background)


1

SWIFT 5.1

UIApplication.State non ha funzionato per me, perché una volta che ho letto l'impronta digitale (viene mostrato modale) nella mia app, la notifica viene anche lanciata nella barra superiore e l'utente deve fare clic su di essa.

Ho creato

public static var isNotificationFromApp: Bool = false

in AppDelegatee l'ho impostato trueall'inizio viewControllere poi nella mia notifica storyboard/ viewControllerlo controllo solo :)

Spero che possa tornare utile


-7

È possibile configurare il payload della notifica push per chiamare il application:didReceiveRemoteNotification:fetchCompletionHandler:metodo del delegato dell'app quando l'app è in background. È possibile impostare alcuni flag qui in modo che la prossima volta che l'utente avvierà l'applicazione, sia possibile eseguire l'operazione.

Dalla documentazione di Apple dovresti usare questo metodo per scaricare nuovi contenuti associati alla notifica push. Inoltre, affinché funzioni, è necessario abilitare la notifica remota dalle modalità in background e il payload della notifica push deve contenere la content-availablechiave con il valore impostato su 1. Per ulteriori informazioni, vedere la sezione Utilizzo delle notifiche push per avviare un download da Apple doc qui .

Un altro modo è avere il conteggio dei badge nel payload delle notifiche push. Quindi la prossima volta che la tua applicazione verrà avviata potrai controllare il numero di badge dell'applicazione. Se è maggiore di zero, esegui l'operazione e azzera / cancella anche il conteggio dei badge dal server.

Spero che questo ti aiuti.


@bhusan hai letto i dettagli della mia domanda? Vedo che didReceiveRemoteNotification viene chiamato quando arriva la notifica (prima che l'utente la tocchi). Volevo scoprire se l'utente lo ha toccato.
Bao Lei

Non hai risposto alla domanda di OP. Non vuole solo sapere che c'è stata una notifica. Vuole sapere se l'utente ha aperto l'app toccando quella notifica remota.
Joe C
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.