Ermitteln Sie anhand einer Push-Benachrichtigung, ob die App gestartet / geöffnet wurde

171

Ist es möglich zu wissen, ob die App über eine Push-Benachrichtigung gestartet / geöffnet wurde?

Ich denke, die Auftaktveranstaltung kann hier abgefangen werden:

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

    if (launchOptions != nil) {
         // Launched from push notification
         NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    }
}

Wie kann ich jedoch anhand einer Push-Benachrichtigung erkennen, dass die App im Hintergrund geöffnet wurde?

Joao
quelle
6
Dies ist ein alter, aber sehr nützlicher Beitrag. Leider lösen die Top-Antworten das Problem nicht wirklich (wie aus den Kommentaren hervorgeht). Bitte markieren Sie eine neue Antwort als "akzeptiert", da die aktuelle nicht vollständig ist.
MobileVet
1
Diese Frage hat mehr als 100.000 Aufrufe, aber die ausgewählte Antwort ist falsch oder vollständig. Für Besucher ist es wichtig, nach Aktiv statt nach Stimmen zu sortieren, um moderne Lösungen zu finden.
Albert Renshaw

Antworten:

187

Siehe diesen Code:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

gleich wie

-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification
Shanegao
quelle
19
@ ManuelM. Dies ist insofern eine gute Antwort, als es zeigt, wie man erkennt, wenn eine App im Hintergrund aus einer Push-Benachrichtigung in den Vordergrund gerückt wird. Wenn die App nicht ausgeführt wird, benötigen Sie die Antwort von M.Othman unten.
OpenUserX03
6
Ich erhalte den Aufruf zur Anwendung: didReceiveRemoteNotification: Nach dem Tippen auf die Benachrichtigung, unabhängig davon, ob die App nur im Hintergrund ausgeführt wird oder überhaupt nicht, sodass diese Antwort perfekt zu meinen Anforderungen passt. Getestet auf iOS 7 & 8
Newtz
16
Wie einige andere betonten, erkennt dies nicht "gestartet / geöffnet von einer Push-Benachrichtigung". Dies wird aufgerufen, wenn die Benachrichtigung empfangen wird, nicht wenn sie geöffnet wird. Wenn Sie also eine Benachrichtigung im Hintergrund erhalten haben, aber auf das App-Symbol getippt haben, um die App zu öffnen, wird der Code, den Sie hier haben, weiterhin ausgeführt, und Sie öffnen möglicherweise eine Seite, die der Benutzer nicht öffnen wollte.
Bao Lei
4
@ ManuelM. Diese Methode erkennt nicht, ob die App über das Benachrichtigungscenter oder das App-Symbol geöffnet wurde, wenn der Hintergrundmodus - Remote-Benachrichtigung aktiviert ist. Dies ist der Fall, wenn das Kontrollkästchen deaktiviert ist. Ich habe den Unterschied in diesem Beitrag dokumentiert: stackoverflow.com/questions/32061897/…
Bao Lei
2
Bestätigt, dass dies mit Google Cloud Messaging funktioniert.
CularBytes
127

spät, aber vielleicht nützlich

Wenn die App nicht ausgeführt wird

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

wird genannt ..

Hier müssen Sie nach Push-Benachrichtigungen suchen

NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
    NSLog(@"app recieved notification from remote%@",notification);
    [self application:application didReceiveRemoteNotification:notification];
} else {
    NSLog(@"app did not recieve notification");
}
M.Othman
quelle
2
Beachten Sie, dass im obigen Snippet die Benachrichtigung nicht als (UILocalNotification *), sondern als (NSDictionary *)
deklariert werden sollte
1
Auf diese Weise können Sie sehen, ob Benachrichtigungen für die App vorhanden waren, während sie nicht ausgeführt wurde! Die Frage war, wie man erkennt, ob die App anhand einer Benachrichtigung geöffnet wurde. In diesem Fall wird didReceiveRemoteNotification aufgerufen, auch wenn die App überhaupt nicht ausgeführt wurde. - Ich mag Ihre Antwort, weil sie in vielen Fällen sehr wichtig ist, aber nicht die richtige Antwort auf die Frage.
Axel Zehden
Tun Ihre Antwort und diese Antwort dasselbe?
Honey
38

Das Problem bestand darin, die Ansicht nach dem Start der App korrekt zu aktualisieren. Hier gibt es komplizierte Sequenzen von Lebenszyklusmethoden, die verwirrend werden.

Lebenszyklusmethoden

Unsere Tests für iOS 10 ergaben die folgenden Sequenzen von Lebenszyklusmethoden für die verschiedenen Fälle:

DELEGATE METHODS CALLED WHEN OPENING APP  

Opening app when system killed or user killed  
    didFinishLaunchingWithOptions  
    applicationDidBecomeActive    

Opening app when backgrounded  
    applicationWillEnterForeground  
    applicationDidBecomeActive  

DELEGATE METHODS WHEN OPENING PUSH

Opening push when system killed
    [receiving push causes didFinishLaunchingWithOptions (with options) and didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

Opening push when user killed
    didFinishLaunchingWithOptions (with options)
    didReceiveRemoteNotification:inactive [only completionHandler version]
    applicationDidBecomeActive

Opening push when backgrounded
    [receiving push causes didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

Das Problem

Ok, jetzt müssen wir:

  1. Stellen Sie fest, ob der Benutzer die App über einen Push öffnet
  2. Aktualisieren Sie die Ansicht basierend auf dem Push-Status
  3. Löschen Sie den Status, damit nachfolgende Öffnungen den Benutzer nicht an dieselbe Position zurückbringen.

Das Knifflige ist, dass die Aktualisierung der Ansicht erfolgen muss, wenn die Anwendung tatsächlich aktiv wird. Dies ist in allen Fällen die gleiche Lebenszyklusmethode.

Skizze unserer Lösung

Hier sind die Hauptkomponenten unserer Lösung:

  1. Speichern Sie eine notificationUserInfoInstanzvariable im AppDelegate.
  2. Stellen Sie notificationUserInfo = nilbeide applicationWillEnterForegroundund ein didFinishLaunchingWithOptions.
  3. Setzen Sie notificationUserInfo = userInfoeindidReceiveRemoteNotification:inactive
  4. applicationDidBecomeActiveRufen Sie immer eine benutzerdefinierte Methode auf openViewFromNotificationund übergeben Sie self.notificationUserInfo. Wenn self.notificationUserInfonil, kehren Sie frühzeitig zurück, andernfalls öffnen Sie die Ansicht basierend auf dem Benachrichtigungsstatus in self.notificationUserInfo.

Erläuterung

Wenn Sie von einem Push öffnen didFinishLaunchingWithOptionsoder applicationWillEnterForegroundimmer unmittelbar vorher aufgerufen werden didReceiveRemoteNotification:inactive, setzen wir BenachrichtigungUserInfo zuerst in diesen Methoden zurück, damit kein veralteter Status vorliegt. Wenn didReceiveRemoteNotification:inactivedann aufgerufen wird, wissen wir, dass wir von einem Push aus öffnen, also setzen wir, self.notificationUserInfowas dann aufgenommen wird applicationDidBecomeActive, um den Benutzer zur richtigen Ansicht weiterzuleiten.

Es gibt einen letzten Fall: Der Benutzer hat die App im App-Umschalter geöffnet (dh durch zweimaliges Tippen auf die Home-Taste, während sich die App im Vordergrund befindet) und erhält dann eine Push-Benachrichtigung. In diesem Fall wird nur didReceiveRemoteNotification:inactiveaufgerufen, und weder WillEnterForeground noch didFinishLaunching werden aufgerufen, sodass Sie einen speziellen Status benötigen, um diesen Fall zu behandeln.

Hoffe das hilft.

Eric Conner
quelle
Endlich etwas, das funktioniert, danke! Ich wollte ein Flag "appResuming" erstellen und den Bildschirm in den receiveMethoden öffnen , wenn der App-Status aktiv ist oder die App fortgesetzt wird. Dies kann zu Problemen beim Ändern von VCs führen, wenn die App noch inaktiv ist. Ihre Lösung sieht gut aus, bis Apple den Lebenszyklus erneut ändert.
Shelll
Was ist mit iOS 9? Werden die Lebenszyklusmethoden auf dieselbe Weise und in derselben Reihenfolge aufgerufen? Ich habe bereits keine iOS 9-Geräte, daher kann ich dies nicht richtig testen.
Shelll
2
Es gibt zwei weitere Randfälle außer dem App-Umschalter. 1) Wenn das Benachrichtigungscenter von oben gezogen wird und die App überlagert. 2) Wenn das iOS-Bedienfeld mit WLAN / BT / etc von unten gezogen wird und die App überlagert. In allen drei Fällen wird nur das applicationWillResignActiveaufgerufen und dann das applicationDidBecomeActive. applicationWillResignActiveSpeichern Sie die empfangene Benachrichtigung nach dem Aufruf von oder erst, wenn ein applicationDidEnterBackgroundoder applicationDidBecomeActiveaufgerufen wird.
Shelll
Vielen Dank für das Hinzufügen dieser Fälle @shelll. Es wird immer komplizierter! Ich bin mir bei iOS9 nicht sicher. Ich würde sagen, es ist wahrscheinlich sicher anzunehmen, dass sie gleich sind, aber wer weiß.
Eric Conner
Nur ein Kopf hoch. Ich habe heute iOS 11 Beta 9 getestet und festgestellt, dass in dem Fall, in dem Sie Ihre App im Vordergrund haben, das Telefon sperren und dann eine Push-Benachrichtigung auf dem Sperrbildschirm auswählen, didReceiveRemoteNotification: background aufgerufen wird, kurz bevor applicationWillEnterForeground aufgerufen wird, anstatt Was wir unter iOS 10 sehen, wo es applicationWillEnterForeground und dann didReceiveRemoteNotification aufruft: inaktiv - dies ist also ein Randfall, der noch nicht behandelt wurde. Meiner Meinung nach ist dies ein Fehler im iOS-Code, aber angesichts der Nähe der iOS 11-Version ist dies zu beachten.
Roy
24

Dies ist ein abgenutzter Beitrag ... aber es fehlt immer noch eine tatsächliche Lösung für das Problem (wie in den verschiedenen Kommentaren ausgeführt).

Bei der ursprünglichen Frage geht es darum, anhand einer Push-Benachrichtigung zu erkennen, wann die App gestartet / geöffnet wurde , z. B. wenn ein Benutzer auf die Benachrichtigung tippt. Keine der Antworten deckt diesen Fall tatsächlich ab.

Der Grund kann im Anrufverlauf gesehen werden, wenn eine Benachrichtigung eintrifft. application:didReceiveRemoteNotification...

wird aufgerufen, wenn die Benachrichtigung empfangen wird UND erneut, wenn der Benutzer auf die Benachrichtigung tippt. Aus diesem Grund können Sie nicht erkennen, UIApplicationStateob der Benutzer darauf getippt hat.

Außerdem müssen Sie die Situation eines Kaltstarts der App nicht mehr bewältigen, application:didFinishLaunchingWithOptions...wie application:didReceiveRemoteNotification...sie nach dem Start in iOS 9+ erneut aufgerufen wird (möglicherweise auch 8).

Wie können Sie also feststellen, ob der Benutzer die Ereigniskette gestartet hat? Meine Lösung besteht darin, die Zeit zu markieren, zu der die App aus dem Hintergrund oder dem Kaltstart herauskommt, und diese Zeit dann einzuchecken application:didReceiveRemoteNotification.... Wenn es weniger als 0,1 Sekunden ist, können Sie ziemlich sicher sein, dass der Tipp den Start ausgelöst hat.

Swift 2.x.

class AppDelegate: UIResponder, UIApplicationDelegate {

  var wakeTime : NSDate = NSDate()        // when did our application wake up most recently?

  func applicationWillEnterForeground(application: UIApplication) {    
    // time stamp the entering of foreground so we can tell how we got here
    wakeTime = NSDate()
  }

  func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    // ensure the userInfo dictionary has the data you expect
    if let type = userInfo["type"] as? String where type == "status" {
      // IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
      if application.applicationState != UIApplicationState.Background && NSDate().timeIntervalSinceDate(wakeTime) < 0.1 {
        // User Tap on notification Started the App
      }
      else {
        // DO stuff here if you ONLY want it to happen when the push arrives
      }
      completionHandler(.NewData)
    }
    else {
      completionHandler(.NoData)
    }
  }
}

Swift 3

class AppDelegate: UIResponder, UIApplicationDelegate {

    var wakeTime : Date = Date()        // when did our application wake up most recently?

    func applicationWillEnterForeground(_ application: UIApplication) {
      // time stamp the entering of foreground so we can tell how we got here
      wakeTime = Date()
    }

  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

      // ensure the userInfo dictionary has the data you expect
      if let type = userInfo["type"] as? String, type == "status" {
        // IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
        if application.applicationState != UIApplicationState.background && Date().timeIntervalSince(wakeTime) < 0.1 {
          // User Tap on notification Started the App
        }
        else {
          // DO stuff here if you ONLY want it to happen when the push arrives
        }
        completionHandler(.newData)
      }
      else {
        completionHandler(.noData)
      }
    }
}

Ich habe dies für beide Fälle (App im Hintergrund, App läuft nicht) unter iOS 9+ getestet und es funktioniert wie ein Zauber. 0,1s ist auch ziemlich konservativ, der tatsächliche Wert ist ~ 0,002s, also ist 0,01 ebenfalls in Ordnung.

MobileVet
quelle
1
Dies scheint die einzige funktionierende Lösung zu sein, die zwischen dem tatsächlichen Tippen auf die Benachrichtigung und dem Öffnen der Statusleiste über der App unterscheidet.
Liviucmg
4
Dies ist die einzige funktionierende Lösung aus dem gesamten StackOverflow. Das einzige, was ich hinzufügen möchte, ist, wenn Sie iOS 10 und höher unterstützen, können Sie einfach die UNNotificationCenterAPI verwenden, insbesondere die UNNotificationCenterDelegate-Methoden. Diese API-Aufruffunktion funktioniert userNotificationCenter(UNUserNotificationCenter, didReceive: UNNotificationResponse, withCompletionHandler: @escaping () -> Void) nur, wenn der Benutzer tatsächlich auf die Benachrichtigung getippt hat.
DenHeadless
Wie sieht es für Swift 3 aus?
Jochen Österreicher
Die Lösung funktioniert nicht, während sich eine App im inaktiven Zustand befindet (Benutzer wischt das Benachrichtigungscenter nach unten oder das Kontrollzentrum nach oben) und erhält eine Benachrichtigung. Wenn der Benutzer auf die Benachrichtigung tippt, erhält die App keinen applicationWillEnterForeground Anruf. Infolgedessen erkennt die Lösung das Tippen nicht.
DevGansta
@ DevGansta Wenn Sie Ihre Klasse wie UNUserNotificationCenter.current().delegatein hinzufügen application:didFinishLaunchingWithOptions, wird die App userNotificationCenter(didReceive response)nach dem Tippen in dem von Ihnen beschriebenen Fall aufrufen
Dorian Roy
22

Wenn die App beendet wird und der Benutzer auf die Push-Benachrichtigung tippt

public func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
   if launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] != nil {
      print("from push")
    }
}

Wenn sich die App im Hintergrund befindet und der Benutzer auf die Push-Benachrichtigung tippt

Wenn der Benutzer Ihre App über die vom System angezeigte Warnung öffnet, ruft das System diese Methode möglicherweise erneut auf, wenn Ihre App in den Vordergrund tritt, damit Sie Ihre Benutzeroberfläche aktualisieren und Informationen zur Benachrichtigung anzeigen können.

public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
  if application.applicationState == .inactive {
    print("from push")
  }
}

Abhängig von Ihrer App kann es Ihnen auch einen stillen Push mit content-availableInside senden. Beachten Sie apsdies auch :) Siehe https://stackoverflow.com/a/33778990/1418457

onmyway133
quelle
2
Nur eine Antwort, die sich nicht wie ein schmutziger Hack anfühlt und korrekt ist. Was mir fehlt ist, wenn die App im Hintergrund ist und der Benutzer sie manuell öffnet, wie kann man das überprüfen? Während immer noch in der Lage ist, auf Push-Kaltstart und Push aus dem Hintergrund zu prüfen.
Jochen Österreicher
1
@ JochenÖsterreicher Hallo, ich fasse es hier zusammen, bitte überprüfen Sie medium.com/@onmyway133/…
onmyway133
19

Swift 2.0 für den Status "Nicht ausgeführt" (lokale und Remote-Benachrichtigung)

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {


// Handle notification
if (launchOptions != nil) {

    // For local Notification
    if let localNotificationInfo = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {

        if let something = localNotificationInfo.userInfo!["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }


    } else

    // For remote Notification
    if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as! [NSObject : AnyObject]? {

        if let something = remoteNotification["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }
    }

}


return true
}
Włodzimierz Woźniak
quelle
15

In application:didReceiveRemoteNotification:Prüfung , ob Sie die Mitteilung erhalten , wenn Sie Ihre App im Vordergrund oder im Hintergrund sind.

Wenn es im Hintergrund empfangen wurde, starten Sie die App über die Benachrichtigung.

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        NSLog(@"Notification received by running app");
    } else {
        NSLog(@"App opened from Notification");
    }
}
Madhu
quelle
3
Beachten Sie, dass "App über Benachrichtigung geöffnet" falsch positiv ist, wenn die Benachrichtigung gesendet wird, während sich der Benutzer auf einem anderen Bildschirm befindet (z. B. wenn er die Statusleiste herunterzieht und dann eine Benachrichtigung von Ihrer App erhält).
Kevin Cooper
4
@ Kevin Genau. Man wundert sich, warum Apple anscheinend einen Praktikanten beauftragt hat, den Prozess der Bearbeitung von Benachrichtigungen zu gestalten ...
Andreas
Wie können wir erkennen, ob wir auf die im aktiven Zustand
empfangene
13

Für schnell:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
    PFPush.handlePush(userInfo)

    if application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background {
        //opened from a push notification when the app was in the background

    }

}
LondonGuy
quelle
4

Ja, Sie können mit dieser Methode in appDelegate Folgendes erkennen :

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
      /* your Code*/
}

Für lokale Benachrichtigung:

- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
         /* your Code*/
}
Unmöglich
quelle
1
Diese Methode wird nicht aufgerufen, wenn die App nicht ausgeführt wird. Das hat hier gefragt
Pfitz
Mein Problem besteht nicht darin, die Benachrichtigung zu bearbeiten, sondern zu wissen, ob sie geöffnet wurde, wenn Sie auf das Banner klicken (wenn sich die App im Hintergrund befindet).
Joao
3

wenn jemand die Antwort in schnell 3 will

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    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
    }
}
Hamid Shahsavari
quelle
aber wie man weiß, ob die Anwendung geöffnet wird, indem man auf Push-Benachrichtigung tippt, wenn die App beendet wird
user3804063
1
Wenn jemand auf den Push tippt, ist die App geöffnet, unabhängig davon, ob sie beendet wurde oder nicht. und der inaktive Fall ruft an
Hamid Shahsavari
1
Ich muss erkennen, ob die App durch Tippen auf den Push geöffnet wird, und möchte zu den entsprechenden Inhalten navigieren. Ich habe gesehen, wie Instagram dies tat
user3804063
Wie wäre es mit lokalen Benachrichtigungen?
Amir Shabani
3

Posting dies für Xamarin-Benutzer.

Der Schlüssel zum Erkennen, ob die App über eine Push-Benachrichtigung gestartet wurde, ist die AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options)Methode und das übergebene Optionswörterbuch.

Das Optionswörterbuch enthält diesen Schlüssel, wenn es sich um eine lokale Benachrichtigung handelt: UIApplication.LaunchOptionsLocalNotificationKey .

Wenn es sich um eine Remote-Benachrichtigung handelt, ist dies der Fall UIApplication.LaunchOptionsRemoteNotificationKey.

Wenn der Schlüssel ist LaunchOptionsLocalNotificationKey, ist das Objekt vom Typ UILocalNotification. Sie können dann die Benachrichtigung anzeigen und feststellen, um welche spezifische Benachrichtigung es sich handelt.

Pro-Tipp: UILocalNotificationEnthält keine Kennung, genauso UNNotificationRequestwie. Fügen Sie einen Wörterbuchschlüssel in die UserInfo ein, der eine requestId enthält, damit beim Testen der UILocalNotificationeine bestimmte requestId zur Verfügung steht, auf der eine Logik basiert.

Ich habe festgestellt, dass selbst auf iOS 10+ -Geräten, die beim Erstellen von Standortbenachrichtigungen mit dem UNUserNotificationCenter's AddNotificationRequest& UNMutableNotificationContent, wenn die App nicht ausgeführt wird (ich habe sie beendet) und durch Tippen auf die Benachrichtigung im Benachrichtigungscenter gestartet werden, das Wörterbuch noch enthält dasUILocalNotificaiton Objekt.

Dies bedeutet, dass mein Code, der nach einem auf Benachrichtigungen basierenden Start sucht, auf iOS8- und iOS 10+ -Geräten funktioniert

public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
    _logger.InfoFormat("FinishedLaunching");

    if(options != null)
    {
        if (options.ContainsKey(UIApplication.LaunchOptionsLocalNotificationKey))
        {
            //was started by tapping a local notification when app wasn't previously running.
            //works if using UNUserNotificationCenter.Current.AddNotificationRequest OR UIApplication.SharedApplication.PresentLocalNotificationNow);

            var localNotification = options[UIApplication.LaunchOptionsLocalNotificationKey] as UILocalNotification;

            //I would recommended a key such as this :
            var requestId = localNotification.UserInfo["RequestId"].ToString();
        }               
    }
    return true;
}
Wir s
quelle
2

Direkt aus der Dokumentation für

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo:nil

Wenn die App ausgeführt wird und eine Remote-Benachrichtigung erhält, ruft die App diese Methode auf, um die Benachrichtigung zu verarbeiten.

Ihre Implementierung dieser Methode sollte die Benachrichtigung verwenden, um geeignete Maßnahmen zu ergreifen.

Und ein bisschen später

Wenn die App beim Eintreffen einer Push-Benachrichtigung nicht ausgeführt wird, startet die Methode die App und stellt die entsprechenden Informationen im Wörterbuch für Startoptionen bereit.

Die App ruft diese Methode nicht auf, um diese Push-Benachrichtigung zu verarbeiten.

Stattdessen wird Ihre Implementierung des

application:willFinishLaunchingWithOptions:

oder

application:didFinishLaunchingWithOptions:

Die Methode muss die Nutzdaten der Push-Benachrichtigung abrufen und entsprechend reagieren.

Pfitz
quelle
2

Ich beginne mit einem Zustandsdiagramm, das ich für meinen eigenen Gebrauch erstellt habe, um es genauer zu visualisieren und alle anderen Zustände zu berücksichtigen: https://docs.google.com/spreadsheets/d/e/2PACX-1vSdKOgo_F1TZwGJBAED4C_7cml0bEATqeL3P9UKpBwASlT6ZkU3kk3 gid = 0 & single = true

Anhand dieser Tabelle können wir sehen, was tatsächlich erforderlich ist, um ein robustes Benachrichtigungshandhabungssystem zu entwickeln, das in fast allen möglichen Anwendungsfällen funktioniert.

Komplettlösung ↓

  • Speichern Sie die Benachrichtigungsnutzdaten in didReceiveRemoteNotification
  • Löschen Sie gespeicherte Benachrichtigungen in applicationWillEnterForeground und didFinishLaunchingWithOptions
  • Um Fälle zu behandeln, in denen Control Center / Notification Center gezogen wurde, können Sie ein Flag willResignActiveCalled verwenden und es zunächst auf false setzen . Setzen Sie dies in der applicationWillResignActive- Methode auf true .
  • In didReceiveRemoteNotification Methode Benachrichtigungen (userInfo) nur, wenn willResignActiveCalled false ist.
  • Zurücksetzen von willResignActiveCalled auf false in der applicationDidEnterBackground- und applicationDidBecomeActive- Methode.

Hinweis: Eine ähnliche Antwort wird in Kommentaren zu Erics Antwort vorgeschlagen. Das Statusblatt hilft jedoch dabei, alle möglichen Szenarien zu finden, wie ich es in meiner App getan habe.

Bitte finden Sie den vollständigen Code unten und kommentieren Sie unten, wenn ein bestimmter Fall nicht behandelt wird:

AppDelegate

class AppDelegate: UIResponder, UIApplicationDelegate {
  private var willResignActiveCalled = false

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    NotificationUtils.shared.notification = nil
    return true
  }
  func applicationWillResignActive(_ application: UIApplication) {
    willResignActiveCalled = true
  }
  func applicationDidEnterBackground(_ application: UIApplication) {
    willResignActiveCalled = false
  }
  func applicationWillEnterForeground(_ application: UIApplication) {
    NotificationUtils.shared.notification = nil
  }
  func applicationDidBecomeActive(_ application: UIApplication) {
    willResignActiveCalled = false
    NotificationUtils.shared.performActionOnNotification()
  }
  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if !willResignActiveCalled { // Check if app is in inactive by app switcher, control center, or notification center
      NotificationUtils.shared.handleNotification(userInfo: userInfo)
    }
  }
}

NotificationUtils : Hier können Sie Ihren gesamten Code schreiben, um zu verschiedenen Teilen der Anwendung zu navigieren, Datenbanken (CoreData / Realm) zu verwalten und alle anderen Aufgaben zu erledigen, die beim Empfang einer Benachrichtigung ausgeführt werden müssen.

   class NotificationUtils {
  static let shared = NotificationUtils()
  private init() {}

  var notification : [AnyHashable: Any]?

  func handleNotification(userInfo : [AnyHashable: Any]){
    if UIApplication.shared.applicationState == UIApplicationState.active {
      self.notification = userInfo //Save Payload
      //Show inApp Alert/Banner/Action etc
      // perform immediate action on notification
    }
    else if UIApplication.shared.applicationState == UIApplicationState.inactive{
      self.notification = userInfo
    }
    else if UIApplication.shared.applicationState == UIApplicationState.background{
      //Process notification in background,
      // Update badges, save some data received from notification payload in Databases (CoreData/Realm)
    }
  }

  func performActionOnNotification(){
    // Do all the stuffs like navigating to ViewControllers, updating Badges etc
    defer {
      notification = nil
    }
  }
}
Chetan Anand
quelle
Setzen Sie dies besser als Kommentar ein, da dies nicht die Antwort ist.
Maddy
@Maddy Danke für den Vorschlag, Aktualisierte die Antwort mit allen Details
Chetan und 9.
1
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
    print("Push notification received: \(data)")

    if let info = data["aps"] as? Dictionary<String, AnyObject> {
        let alertMsg = info["alert"] as! String
        print(alertMsg)
        switch application.applicationState {
        case .active:
            print("do stuff in case App is active")
        case .background:
            print("do stuff in case App is in background")
           // navigateToChatDetailViewControler(pushdata: data)
        case .inactive:
            print("do stuff in case App is inactive")
            // navigateToChatDetailViewControler(pushdata: data)
        }
    }
}
Hardik Bar
quelle
1

Es gibt nur einen zuverlässigen Weg und er funktioniert nur für iOS 10+ :

Verwenden der UNUserNotificationCenterImplementierungsmethode UNUserNotificationCenterDelegate:

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

    //Here you can get your original push if you need to
    NSDictionary* pusDict = response.notification.request.content.userInfo;

    if ([response.actionIdentifier isEqualToString: UNNotificationDefaultActionIdentifier]) {
        //User tapped the notification
    } else if ([response.actionIdentifier isEqualToString: UNNotificationDismissActionIdentifier]) {
        //User dismissed the notification 
    } else if ([response.actionIdentifier isEqualToString: MYCustomActionId]) {
        //User chose my custom defined action
    }
    ...
}
Lauten
quelle
0

Sie können verwenden:

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

um die Remote-Push-Benachrichtigungen zu behandeln.

Überprüfen Sie hier die Dokumentation

sunkehappy
quelle
0
     // shanegao's code in Swift 2.0
     func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
    {
            if ( application.applicationState == UIApplicationState.Inactive || application.applicationState == UIApplicationState.Background ){
                    print("opened from a push notification when the app was on background")
            }else{
                    print("opened from a push notification when the app was on foreground")
            }
    }
Sean Dev
quelle
Aber was ist, wenn die App geschlossen (beendet) wurde? Wie Twitter oder Instagram erkennt es es irgendwie und wenn die App sogar geschlossen ist, leitet es Sie zu neuen
Posts
0

Das Problem bei dieser Frage ist, dass das "Öffnen" der App nicht genau definiert ist. Eine App wird entweder aus einem nicht laufenden Zustand kalt gestartet oder aus einem inaktiven Zustand reaktiviert (z. B. aus einer anderen App zurück zu ihr). Hier ist meine Lösung, um all diese möglichen Zustände zu unterscheiden:

typedef NS_ENUM(NSInteger, MXAppState) {
    MXAppStateActive = 0,
    MXAppStateReactivated = 1,
    MXAppStateLaunched = 2
};

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // ... your custom launch stuff
    [[MXDefaults instance] setDateOfLastLaunch:[NSDate date]];
    // ... more custom launch stuff
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // Through a lot of trial and error (by showing alerts), I can confirm that on iOS 10
    // this method is only called when the app has been launched from a push notification
    // or when the app is already in the Active state.  When you receive a push
    // and then launch the app from the icon or apps view, this method is _not_ called.
    // So with 99% confidence, it means this method is called in one of the 3 mutually exclusive cases
    //    1) we are active in the foreground, no action was taken by the user
    //    2) we were 'launched' from an inactive state (so we may already be in the main section) by a tap
    //       on a push notification
    //    3) we were truly launched from a not running state by a tap on a push notification
    // Beware that cases (2) and (3) may both show UIApplicationStateInactive and cant be easily distinguished.
    // We check the last launch date to distinguish (2) and (3).

    MXAppState appState = [self mxAppStateFromApplicationState:[application applicationState]];
    //... your app's logic
}

- (MXAppState)mxAppStateFromApplicationState:(UIApplicationState)state {
    if (state == UIApplicationStateActive) {
        return MXAppStateActive;
    } else {
        NSDate* lastLaunchDate = [[MXDefaults instance] dateOfLastLaunch];
        if (lastLaunchDate && [[NSDate date] timeIntervalSinceDate:lastLaunchDate] < 0.5f) {
            return MXAppStateLaunched;
        } else {
            return MXAppStateReactivated;
        }
    }
    return MXAppStateActive;
}

Und MXDefaultsist nur eine kleine Hülle für NSUserDefaults.

Skensell
quelle
0

Zum swift

 func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]){

    ++notificationNumber
    application.applicationIconBadgeNumber =  notificationNumber;

    if let aps = userInfo["aps"] as? NSDictionary {

        var message = aps["alert"]
        println("my messages : \(message)")

    }
}
idris yıldız
quelle
0

Xcode 10 Swift 4.2

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {

    let state : UIApplicationState = application.applicationState
    if (state == .Inactive || state == .Background) {
        // coming from background
    } else {
        // App is running in foreground
    }
}
Prashant Gaikwad
quelle
0

Unter iOS 10+ können Sie diese Methode verwenden, um festzustellen, wann auf Ihre Benachrichtigung geklickt wird, unabhängig vom Status der App.

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

    //Notification clicked
    completionHandler()
}
manishsharma93
quelle
0

M.Othman Antwort ist richtig für Anwendungen , die nicht enthalten Szene Delegat für Szene Delegate Apps Dies ist für mich gearbeitet iOS 13

Hier ist der Code, in den geschrieben werden soll, um die Szene zu verbinden

if connectionOptions.notificationResponse == nil { 
//Not opened from push notification
} else {
  //Opened from push notification
}

Code für App-Delegaten zur Unterstützung früherer Versionen didFinishLaunchingWithOptions

let notification = launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification]
        if (notification != nil) {

            //Launched from push notification
        } else {

            //Launch from other source
        }
Noman Haroon
quelle
-1

Für schnelle Benutzer:

Wenn Sie beim Öffnen von Push oder ähnlichem eine andere Seite starten möchten, müssen Sie sie didFinishLaunchingWithOptionswie folgt einchecken :

let directVc: directVC! = directVC(nibName:"directVC", bundle: nil)
let pushVc: pushVC! = pushVC(nibName:"pushVC", bundle: nil)

if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
     self.navigationController = UINavigationController(rootViewController: pushVc!)
} else {
     self.navigationController = UINavigationController(rootViewController: directVc!)
}
self.window!.rootViewController = self.navigationController
AAA
quelle
Delegierter hat kein Mitglied navigationController
Pablo Cegarra
1
Erstellen Sie einen Navigationscontroller in der Datei AppDelegate.h. Ich benutze es und es funktioniert!
AAA
-1

IN SCHNELL:

Ich führe Push-Benachrichtigungen aus (mit Hintergrundabruf). Wenn sich meine App im Hintergrund befindet und ich eine Push-Benachrichtigung erhalte, habe ich festgestellt, dass didReceiveRemoteNotification in appDelegate zweimal aufgerufen wird. einmal, wenn eine Benachrichtigung empfangen wird, und einmal, wenn der Benutzer auf die Benachrichtigung klickt.

Um festzustellen, ob auf eine Benachrichtigung geklickt wurde, überprüfen Sie einfach, ob application'date raw value == 1 in didReceiveRemoteNotification in appDelegate enthalten ist.

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject: AnyObject]) {
    // If not from alert click applicationState(1)
    if (application.applicationState.rawValue != 1) {
        // Run your code here
    }
}

Ich hoffe das hilft.

Johnny5
quelle
-1

Wenn die App als Shanegao im Hintergrund ist, können Sie sie verwenden

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

Wenn Sie die Anwendung jedoch starten möchten und wenn die App geschlossen ist und Sie Ihre Anwendung debuggen möchten, gehen Sie zu Schema bearbeiten und wählen Sie im linken Menü Ausführen und dann beim Starten die Option Warten auf den Start der ausführbaren Datei. Anschließend starten Sie die Anwendung Klicken Sie auf Push-Benachrichtigung

Schema bearbeiten> Ausführen> Warten Sie, bis die ausführbare Datei gestartet wird

salmancs43
quelle