web-dev-qa-db-fra.com

Notification Push iOS: comment détecter si l'utilisateur a tapé sur la notification lorsque l'application est en arrière-plan?

Il y a beaucoup de threads stackoverflow concernant ce sujet, mais je n'ai toujours pas trouvé de bonne solution.

Si l'application n'est pas en arrière-plan, je peux vérifier launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey] dans application:didFinishLaunchingWithOptions: appel pour voir si elle est ouverte à partir d'une notification.

Si l'application est en arrière-plan, tous les articles suggèrent d'utiliser application:didReceiveRemoteNotification: et de vérifier l'état de l'application. Mais comme j'ai expérimenté (et aussi comme le nom de cette API le suggère), cette méthode est appelée lorsque la notification est reçue, au lieu d'être exploitée.

Le problème est donc que si l'application est lancée, puis mise en arrière-plan, et que vous savez qu'une notification est reçue de application:didReceiveNotification (application:didFinishLaunchWithOptions: ne se déclenchera pas à ce stade), comment savoir si l'utilisateur a repris la app de en appuyant sur la notification ou en tapant simplement sur l'icône de l'application? Parce que si l'utilisateur a appuyé sur la notification, il est attendu d'ouvrir la page mentionnée dans cette notification. Sinon, ça ne devrait pas.

Je pourrais utiliser handleActionWithIdentifier pour les notifications d'actions personnalisées, mais cela ne se déclenche que lorsqu'un bouton d'action personnalisée est activé, et non lorsque l'utilisateur appuie sur le corps principal de la notification.

Merci.

MODIFIER:

après avoir lu une réponse ci-dessous, j'ai pensé de cette manière que je peux clarifier ma question:

Comment pouvons-nous différencier ces 2 scénarios:

(A) 1.app va au fond; 2. notification reçue; 3. l'utilisateur appuie sur la notification; 4. l'application entre au premier plan

(B) 1.app va au fond; 2. notification reçue; 3. L'utilisateur ignore la notification et appuie sur l'icône de l'application plus tard. 4. l'application entre au premier plan

Depuis application:didReceiveRemoteNotification: est déclenché dans les deux cas à l’étape 2.

Ou bien, application:didReceiveRemoteNotification: doit-il être déclenché à l'étape 3 pour (A) uniquement, mais j'ai en quelque sorte configuré mon application de manière erronée et je la vois donc à l'étape 2?

104
Bao Lei

OK j'ai finalement compris.

Dans les paramètres de cible ➝ onglet Fonctions ➝ Modes d’arrière-plan, si vous cochez la case "Notifications à distance", application:didReceiveRemoteNotification: sera déclenché dès que la notification arrive (tant que l’application est en arrière-plan) et, dans ce cas, aucun moyen de dire si l'utilisateur va taper sur la notification.

Si vous décochez cette case, application:didReceiveRemoteNotification: ne sera déclenché que lorsque vous appuyez sur la notification.

C'est un peu étrange que cocher cette case changera le comportement de l'une des méthodes de délégation d'application. Il serait préférable que cette case soit cochée. Apple utilise deux méthodes de délégation différentes pour les notifications de réception et de notification. Je pense que la plupart des développeurs veulent toujours savoir si une notification est exploitée ou non.

Espérons que cela sera utile à quiconque se heurtera à ce problème. Apple n'a pas non plus clairement documenté le problème ici , donc il m'a fallu un certain temps pour le comprendre.

enter image description here

90
Bao Lei

Je cherchais la même chose que vous et j'ai en fait trouvé une solution qui n'exige pas de notification à distance pour être cochée.

Pour vérifier si l'utilisateur a tapé, ou si l'application est en arrière-plan ou est active, il vous suffit de vérifier l'état de l'application dans

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

    }

Pour plus d'informations, consultez:

Référence du cadre UIKit> Référence de la classe UIApplication> UIApplicationState

63
Dennism

Selon iOS/XCode: comment savoir qu'une application a été lancée en cliquant sur la notification ou sur l'icône de l'application springboard? vous devez vérifier l'état de l'application dans didReceiveLocalNotification de la manière suivante:

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

Bien que cela ne me semble pas tout à fait logique, cela semble fonctionner.

19
Werner Kratochwil

Si quelqu'un le veut dans 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
    }

pour 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
}
16
Hamid Shahsavari

Si vous avez coché "Modes de fond"> "Notifications à distance" == OUI, appuyez sur l'événement de notification qui arrivera dans:

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

Ça m'a aidé. Amusez-vous :)

5
Aleks Osipov

J'ai rencontré ce problème aussi - mais sur iOS 11 avec le nouveau Framework UserNotifications.

Voici pour moi c'est comme ça:

  • Nouveau lancement: application:didFinishLaunchingWithOptions:
  • Reçu au premier plan: application:didReceiveRemoteNotification:fetchCompletionHandler:
  • Reçu en arrière-plan: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
4
pre

Dans mon cas, le mode d’arrière-plan désactivé ne faisait aucune différence. Cependant, lorsque l'application a été suspendue et que l'utilisateur a tapé sur la notification, je pouvais gérer le cas dans cette méthode de rappel:

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

}
2
DoruChidean

Pour iOS 10 et supérieur, mettez ceci dans AppDelegate, pour faire connaissance, la notification est activée (même si l'application est fermée ou ouverte)

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

Il y a deux Funcs pour gérer la PushNotification reçue à l'intérieur:

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate{

}

Comme j'ai testé le premier sur déclencheur dès que la notification est arrivée

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

}

Et le second lorsque vous appuyez sur Notification:

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

De plus, je l'ai testé avec l'état d'activation/désactivation des notifications à distance (en arrière-plan).

1
Saeid