Gestione delle notifiche push quando l’app NON è in esecuzione

Quando la mia app non è in esecuzione e riceve una notifica push, se faccio clic su tale notifica, l’app viene avviata, ma in seguito non richiede all’utente la vista avviso impostata, chiedendo loro se desiderano visualizzare la Contenuto della notifica o meno. Si avvia e si siede lì.

Le notifiche push funzionano perfettamente quando l’app è in esecuzione, o come app triggers o mentre è in background, ma nulla funziona correttamente quando l’app non è in esecuzione.

Ho provato a disconnettere il launchOptions NSDictionary in application: didFinishLaunchingWithOptions: per vedere cosa carica il suo caricamento – ma viene visualizzato come “(null)”. Quindi in pratica non contiene nulla, che non ha senso perché non dovrebbe contenere il carico della notifica?

Qualcuno ha qualche idea su come far funzionare le notifiche push quando arrivano mentre l’app NON è in esecuzione?

EDIT: ecco il codice che sto usando application: didReceiveRemoteNotification solo per vedere cosa è cosa:

 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"); } 

Quindi questo dovrebbe avere cura di tutti gli stati dell’applicazione – ma non è così. Le notifiche push funzionano solo quando l’app è in esecuzione, in background o in primo piano …

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

UPDATE / EDIT # 2: come da “@dianz” suggerimento (sotto,) Ho modificato il codice della mia application: didFinishLaunchingWithOptions per includere quanto segue:

 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]; } 

Questo fa apparire la finestra di AlertView, ma sembra che non ci sia alcun payload: il titolo di AlertView si presenta (“appDidFinishWithOptions”), ma la NSString JSON arriva EMPTY … Continuerà a modificarla …

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

EDIT # 3 – ora funziona quasi al 100%
Quindi, in 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]; } 

Successivamente implemento il metodo alertView: clickedButtonAtIndex per vedere cosa l’utente ha scelto su AlertView e procedere di conseguenza.

Questo, insieme con la logica didReceiveRemoteNotification , funziona perfettamente.

TUTTAVIA … quando l’app NON è in esecuzione, e io invio una notifica push, se NON clicco sull’avviso di notifica push non appena arriva e invece attendo che si dissolva (cosa che succede dopo 3) 4 secondi), quindi faccio clic sull’icona dell’app, che ora ha un BADGE di 1 su di esso, l’app si avvia, ma non ricevo l’avviso di notifica push quando viene avviato. Si siede proprio lì.

Credo di aver bisogno di capire quella permutazione dopo …

Quando la tua app non viene eseguita o uccisa e tocchi la notifica push, questa funzione verrà triggersta;

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

quindi dovresti gestirlo in questo modo,

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

Meglio essere se si didReceiveRemoteNotification override didReceiveRemoteNotification Ecco qui

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

Ciò attiverà nuovamente il metodo didReceiveRemoteNotification e il codice di push notification verrà eseguito allo stesso modo in cui viene eseguito durante l’esecuzione dell’applicazione.

Ho provato la risposta di @ dianz, non ha funzionato per me, ma ho ricevuto un aiuto dalla risposta.

Nel mio caso;

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSDictionary *apnsBody = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; if (apnsBody) { // Do your code with apnsBody } 

Sebbene sia stata fornita una risposta, nessuna delle risposte fornite funzionava correttamente. Ecco la mia implementazione che sono riuscito a lavorare.

Questo codice va in 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) }) } 

Objective-C:

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

Un paio di note:

  • Probabilmente a causa del modo in cui le allocazioni delle code iOS, l’object della UIApplication.sharedApplication().window root UIApplication.sharedApplication().window è nullo quando si avvia l’applicazione dopo essere stato ucciso. L’aggiunta di un ritardo di 1 millisecondo ha risolto il problema. Non ha provato questo in Objective-C

  • Il casting su [NSObject: AnyObject] era necessario per evitare conflitti di tipo, ma non ho sperimentato molto; tienilo a mente quando implementi nel tuo progetto. Objective-C non richiede questo.

  • Quark è solo una piccola libreria divertente che utilizzo in tutti i miei progetti che contiene estensioni e metodi utili e comunemente usati. Basta usare qualsiasi forma di ritardo che soddisfi le tue esigenze applicative.

Ho avuto lo stesso problema, ma alla fine ho potuto gestire la notifica push quando è inattivo (non in esecuzione) utilizzando l’estensione del servizio di notifica. Questa soluzione è stata consigliata dall’Apple Team Support ed è solo per iOS 10, l’ho implementata e funziona bene! Lascio il link:

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

Questa è la procedura:

  1. Crea una nuova estensione del servizio di notifica per la tua app. Aprire il progetto e premere File – Nuovo – Destinazione e selezionare nella sezione iOS l’opzione “Estensione del servizio di notifica”. Inserisci il nome dell’estensione e le informazioni richieste. Successivamente, Xcode aggiungerà due file con il linguaggio Objective C: il file .h e .m.

NOTA: considera che utilizzerai tre identificatori: 1) Identificatore per la tua app (hai già) 2) Identificatore per la tua estensione (che creerai) 3) Identificatore per App Group. (creerai)

  1. È necessario abilitare i gruppi di app per creare una risorsa in cui è ansible salvare e leggere le informazioni per l’app e l’estensione. Clicca su “Mostra Navigatore progetto”. Nella lista degli obiettivi seleziona il tuo progetto principale. Quindi, fai clic su “Funzionalità” e triggers l’opzione “Gruppi di app”. Aggiungi l’identificatore per App Group per identificare le risorse di condivisione. Dovresti fare lo stesso passo per la destinazione dell’estensione che hai creato (Seleziona la destinazione dell’estensione – Funzionalità – Attiva in “Gruppi di app” – Aggiungi lo stesso identificatore per App Group)

  2. È necessario aggiungere l’identificativo per la propria estensione nel sito degli sviluppatori Apple per identificare l’estensione del servizio di notifica, inoltre è necessario creare nuovi profili provvisori (sviluppo, ad hoc e / o produzione) e associarli ai nuovi profili provvisori.

  3. Su entrambi gli identificatori (app ed estensione) è necessario modificarli e abilitare il servizio “Gruppi di app” in entrambi. È necessario aggiungere il gruppo Identificatore per app nei Servizi gruppi di app.

NOTA: Identificatore per app e identificativo per estensione DOVRESTA AVERE LO STESSO IDENTIFICATORE PER GRUPPO DI APP.

  1. Scarica il nuovo profilo provvisorio su Xcode e associalo con l’estensione del servizio di notifica. Per favore assicurati che tutto sia a posto con loro.

  2. Successivamente, in “Funzionalità” della tua app ed estensione, apri la sezione “Gruppi di app” e aggiornali. I tre passaggi: 1) Aggiungere le autorizzazioni Gruppi di app al file delle autorizzazioni, 2) App la funzione Gruppi di app al tuo ID app e 3) Aggiungi gruppi di app al tuo ID app: deve essere selezionato.

  3. Torna al navigatore del progetto e seleziona la cartella della tua estensione. Apri il file .m. Verrà visualizzato un metodo chiamato didReceiveNotificationRequest: (UNNotificationRequest *) request. In questo metodo creerai un NSUserDefaults differente con SuiteName esattamente uguale all’Identificatore per il gruppo di app in questo modo:

    NSUserDefaults * defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @ “identificatore per gruppo di app”];

  4. In questo stesso metodo, ottenere il corpo della notifica e salvarlo in un NSMutableArray, quindi salvarlo nelle risorse di condivisione. Come questo:

 - (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. Infine, nel Delegato app del progetto principale, nel tuo metodo didFinishLaunchingWithOptions, recupera l’array nelle risorse di condivisione con questo codice:
 NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"]; NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy]; 
  1. Divertirsi!

Spero di essere chiaro ad ogni passo. Ho intenzione di scrivere un post per implementare questa soluzione con le immagini nella mia pagina. Un altro punto che dovresti considerare è che non funziona con Silent Push Notification.

Prova ad andare al metodo didReceiveRemoteNotification e didReceiveRemoteNotification lì. UIApplicationStateActive è ansible verificare gli stati dell’applicazione facendo condizionali per lo stato applicationState , ad esempio controllando se è UIApplicationStateActive o altri.

prova questo

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

Swift 3 e 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 }