web-dev-qa-db-fra.com

Gestion des notifications push lorsque l'application n'est pas en cours d'exécution

Lorsque mon application est pas en cours d'exécution et reçoit une notification push, si je clique sur cette notification, l'application est lancée - mais alors il n'invite pas l'utilisateur avec la vue d'alerte que j'ai configurée, leur demandant s'ils veulent voir le contenu de la notification ou non. Il se lance juste et reste là.

Les notifications push fonctionnent parfaitement lorsque l'application est en cours d'exécution - en tant qu'application active ou en arrière-plan - mais rien ne fonctionne correctement lorsque l'application est pas fonctionnement.

J'ai essayé de me déconnecter du launchOptions NSDictionary dans application: didFinishLaunchingWithOptions: pour voir quelle charge son apport - mais il apparaît comme "(null)". Donc, il ne contient essentiellement rien - ce qui n'a pas de sens car ne devrait-il pas contenir la charge de la notification?

Quelqu'un a-t-il des idées sur la façon de faire fonctionner les notifications push à leur arrivée alors que l'application ne fonctionnait PAS?

EDIT: voici le code que j'utilise dans application: didReceiveRemoteNotification juste pour voir ce qui est quoi:

if (UIApplicationStateBackground) {

    NSLog(@"===========================");
    NSLog(@"App was in BACKGROUND...");
}
else if (UIApplicationStateActive == TRUE) {
    NSLog(@"===========================");
    NSLog(@"App was ACTIVE");
}
else {
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 99]; 
    UIAlertView *BOOM = [[UIAlertView alloc] initWithTitle:@"BOOM"
                                                   message:@"app was INACTIVE"
                                                  delegate:self
                                         cancelButtonTitle:@"a-ha!"
                                         otherButtonTitles:nil];
    [BOOM show];
    NSLog(@"App was NOT ACTIVE");
}

Donc, cela est censé prendre en charge tous les états de l'application - mais ce n'est pas le cas. Les notifications push ne fonctionnent que lorsque l'application est en cours d'exécution - en arrière-plan ou au premier plan ...

=================================================

UPDATE/EDIT # 2: selon la suggestion "@dianz" (ci-dessous), j'ai modifié le code de mon application: didFinishLaunchingWithOptions pour inclure les éléments suivants:

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"]; 

    UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"appDidFinishWithOptions"
                                                  message:json   
                                                 delegate:self
                                        cancelButtonTitle:@"cool"
                                        otherButtonTitles:nil];
    [bam show];

}

Cela fait apparaître la boîte AlertView, mais il ne semble pas y avoir de charge utile: le titre de AlertView apparaît ("appDidFinishWithOptions"), mais le json NSString apparaît VIDE ... Continuera à peaufiner ...

======================

EDIT # 3 - son fonctionne maintenant presque 100%
Donc, dans didFinishLaunchingWithOptions:

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if (localNotif) {
        // Grab the pushKey:
        pushKey = [localNotif valueForKey:@"pushKey"];
        // "pushKey" is an NSString declared globally
        // The "pushKey" in the "valueForKey" statement is part of my custom JSON Push Notification pay-load.
        // The value of pushKey will always be a String, which will be the name of the 
        // screen I want the App to navigate to. So when a Notification arrives, I go
        // through an IF statement and say "if pushKey='specials' then Push the                                      
        // specialsViewController on, etc.

        // Here, I parse the "alert" portion of my JSON Push-Notification:
        NSDictionary *tempDict = [localNotif valueForKey:@"aps"];
        NSString *pushMessage = [tempDict valueForKey:@"alert"];


        // Finally, ask user if they wanna see the Push Notification or Cancel it:
        UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"(from appDidFinishWithOptions)"
                                                      message:pushMessage  
                                                     delegate:self
                                            cancelButtonTitle:@"Cancel"
                                            otherButtonTitles:@"View Info", nil];
        [bam show];

    }

J'implémente ensuite le alertView: clickedButtonAtIndex méthode pour voir ce que l'utilisateur a choisi sur AlertView et procéder en conséquence.

Ceci, avec la logique didReceiveRemoteNotification fonctionne parfaitement.

CEPENDANT ... lorsque l'application n'est PAS en cours d'exécution, et je lui envoie une notification push, si je ne clique pas sur l'alerte de notification push dès qu'elle arrive et attendez plutôt qu'elle disparaisse (ce qui se produit après comme 3- 4 secondes), et puis je clique sur l'icône de l'application - qui a maintenant un BADGE de 1 dessus - l'application démarre, mais je ne le fais pas obtenir l'alerte de notification push du tout lors de son lancement. Il se trouve juste là.

Je suppose que je dois comprendre que permutation suivante ...

42
sirab333

Lorsque votre application n'est pas en cours d'exécution ou tuée et que vous appuyez sur Notification push, cette fonction se déclenchera;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

vous devez donc le gérer comme ça,

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"];
    // Parse your string to dictionary
}
36
dianz

Il vaut mieux que vous remplaciez didReceiveRemoteNotification C'est parti

NSDictionary * pushNotificationPayload = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(pushNotificationPayload) {
    [self application:application didReceiveRemoteNotification:pushNotificationPayload];
}

Cela déclenchera à nouveau la méthode didReceiveRemoteNotification et votre Push notification le code s'exécutera de la même manière qu'il s'exécute pendant l'exécution de l'application.

11
Vaibhav Saran

J'ai essayé la réponse de @ dianz, cela n'a pas fonctionné pour moi mais j'ai obtenu une aide de la réponse.

Dans mon cas;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

NSDictionary *apnsBody = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (apnsBody) {
    // Do your code with apnsBody
}
7
drskur

J'ai eu le même problème mais j'ai finalement pu gérer la notification push lorsque le est inactif (ne fonctionne pas) à l'aide de l'extension du service de notification. Cette solution a été recommandée par Apple Team Support et ce n'est que pour iOS 10, je l'ai implémentée et ça marche bien! Je laisse le lien:

https://developer.Apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ModifyingNotifications.html

Voici la procédure:

  1. Créez une nouvelle extension de service de notification pour votre application. Ouvrez votre projet et appuyez sur Fichier - Nouveau - Cible et sélectionnez sur la section iOS, l'option "Notification Service Extension". Mettez le nom de l'extension et les informations requises. Après cela, Xcode ajoutera deux fichiers en langage Objective C: le fichier .h et .m.

REMARQUE: considérez que vous utiliserez trois identifiants: 1) Identifiant pour votre application (vous en avez déjà) 2) Identifiant pour votre extension (vous allez créer) 3) Identifiant pour le groupe d'applications. (vous allez créer)

  1. Est nécessaire pour activer Groupes d'applications pour créer une ressource où vous pouvez enregistrer et lire les informations pour votre application et l'extension. Cliquez sur "Afficher le navigateur du projet". Dans la liste des cibles, sélectionnez votre projet principal. Ensuite, cliquez sur "Capacités" et activez l'option nommée "Groupes d'applications". Veuillez ajouter l'identifiant du groupe d'applications pour identifier les ressources partagées. Vous devez faire la même étape pour la cible de l'extension que vous avez créée (Sélectionner la cible de l'extension - Capacités - Activer dans "Groupes d'applications" - Ajouter le même identifiant pour le groupe d'applications)

  2. Vous devez ajouter l'identifiant de votre extension dans Apple Developer Site pour identifier l'extension du service de notification, vous devez également créer de nouveaux profils provisoires (développement, ad hoc et/ou production) et l'associer à les nouveaux profils provisoires.

  3. Sur les deux identifiants (application et extension), vous devez les modifier et activer le service "Groupes d'applications" dans les deux. Vous devez ajouter l'identifiant du groupe d'applications dans les services des groupes d'applications.

REMARQUE: l'identifiant pour l'application et l'identifiant pour l'extension DEVRAIENT AVOIR LE MÊME IDENTIFICATEUR POUR LE GROUPE D'APP.

  1. Téléchargez le nouveau profil provisoire sur Xcode et associez-le à votre extension de service de notification. Veuillez vous assurer que tout va bien avec eux.

  2. Après cela, dans "Capacités" de votre application et extension, ouvrez la section "Groupes d'applications" et mettez-les à jour. Les trois étapes - 1) Ajouter les droits des groupes d'applications à votre fichier de droits, 2) Appliquer la fonctionnalité Groupes d'applications à votre ID d'application et 3) Ajouter des groupes d'applications à votre ID d'application - doivent être vérifiées.

  3. Revenez au navigateur de projet et sélectionnez le dossier de votre extension. Ouvrez le fichier .m. Vous verrez une méthode appelée didReceiveNotificationRequest: (UNNotificationRequest *) request. Dans cette méthode, vous allez créer un NSUserDefaults différent avec SuiteName exactement égal à l'identifiant pour le groupe d'applications comme ceci:

    NSUserDefaults * defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @ "identifiant pour le groupe d'applications"];

  4. Dans cette même méthode, récupérez le corps de la notification et enregistrez-le dans un NSMutableArray, puis enregistrez-le dans les ressources de partage. Comme ça:

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler{
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];

    NSMutableArray *notifications = [NSMutableArray new];
    NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
    notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
    if (notifications != nil){
        [notifications addObject:self.bestAttemptContent.userInfo];
    }else{
        notifications = [NSMutableArray new];
        [notifications addObject:self.bestAttemptContent.userInfo];
    }
    [defaultsGroup setObject:notifications forKey:@"notifications"];    
}
  1. Enfin, dans le délégué d'application de votre projet principal, dans votre méthode didFinishLaunchingWithOptions, récupérez le tableau dans les ressources de partage avec ce code:
NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
  1. Profitez-en!

J'espère être clair à chaque étape. Je vais écrire un article pour implémenter cette solution avec des images dans ma page. Un autre point que vous devez considérer est que cela ne fonctionne pas avec la notification push silencieuse.

3

Bien que cela ait été répondu, aucune des réponses fournies n'a réellement fonctionné correctement. Voici mon implémentation que j'ai pu mettre au travail.

Ce code va dans application:didFinishLaunchingWithOptions:

Swift:

if let options = launchOptions, notification = options[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject : AnyObject] {
    // NOTE: (Kyle Begeman) May 19, 2016 - There is an issue with iOS instantiating the UIWindow object. Making this call without
    // a delay will cause window to be nil, thus preventing us from constructing the application and assigning it to the window.
    Quark.runAfterDelay(seconds: 0.001, after: {
        self.application(application, didReceiveRemoteNotification: notification)
    })
}

Objectif-C:

if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
    [self application:application didReceiveRemoteNotification:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
}

Quelques notes:

  • Peut-être en raison de la façon dont iOS met en file d'attente les allocations, l'objet racine UIApplication.sharedApplication().window est nul lors du lancement de l'application après avoir été tué. L'ajout d'un délai de 1 milliseconde a résolu ce problème. N'a pas testé cela dans Objective-C

  • Le cast vers [NSObject: AnyObject] était nécessaire pour éviter d'avoir des conflits de type mais je n'ai pas beaucoup expérimenté avec cela; gardez-le à l'esprit lors de la mise en œuvre de votre propre projet. Objective-C ne l'exige pas.

  • Quark est juste une petite bibliothèque amusante que j'utilise dans tous mes projets qui contient des extensions et des méthodes utiles et couramment utilisées. Utilisez simplement toute forme de retard qui correspond aux besoins de votre application.

3
Kyle Begeman

Essayez d'aller à la méthode didReceiveRemoteNotification et de la gérer. Là, vous pouvez vérifier les états de l'application en effectuant des conditions pour applicationState, par exemple en vérifiant s'il s'agit de UIApplicationStateActive ou d'autres.

1
NeonBlueHair

Swift et xCode 8.3.2:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // your code here

    // Check if app was not running in background and user taps on Push Notification
    // This will perform your code in didReceiveRemoteNotification where you should handle different application states
    if let options = launchOptions, let notification = options[UIApplicationLaunchOptionsKey.remoteNotification] as? [NSObject : AnyObject] {
        self.application(application, didReceiveRemoteNotification: notification)
    }

    return true
}
0
Eugene Pavlov

essaye ça

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    //register notifications
    if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) // ios 8
    {
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
        [application registerForRemoteNotifications];
    }
    else // ios 7
    {
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge];
    }

    // open app from a notification
    NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    if (notification) 
    {
        //your alert should be here
    }

    // Set icon badge number to zero
    application.applicationIconBadgeNumber = 0;

    return YES;
}
0
Cayke Prudente