aggiornato per Swift 3.0
Come si è detto, si vuole Registe r per le notifiche remote in applicationDidLaunchWithOptions:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let pushSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
UIApplication.shared.registerUserNotificationSettings(pushSettings)
UIApplication.shared.registerForRemoteNotifications()
}
Non c'è modo di sapere in cui viewController si sarà quando si torna dalla lockscreen/Sfondo. Quello che faccio è inviare una notifica dall'appDelegate. Quando si riceve una notifica remota, è stata richiamata la notificaRemoteNotification nell'appDelegate.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
let notif = JSON(userInfo) // SwiftyJSON required
A seconda di cosa il vostro notifica contiene, si deve prima assicurarsi che non è pari a zero e quindi chiamare una notifica che verrà catturato dalle viewControllers che dovrebbero catturare questa notifica. Potrebbe assomigliare a questo, basta prendere come esempio:
if notif["callback"]["type"] != nil{
NotificationCenter.default.post(name: Notification.Name(rawValue: "myNotif"), object: nil)
// This is where you read your JSON to know what kind of notification you received, for example :
}
Ad esempio, se si riceve un messaggio di notifica e non si è connessi in più perché il token è scaduto, quindi la notifica non sarà mai catturato nel guarda il controller, perché non sarà mai guardato.
Ora per la parte in cui si riceve la notifica nel controller della vista. Nella viewWillAppear:
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(self.catchIt), name: NSNotification.Name(rawValue: "myNotif"), object: nil)
}
Ora che si è aggiunto questo osservatore, ogni volta che una notifica viene chiamato in questo controller, la funzione catchIt sarà inoltre chiamata. Dovrai implementarlo in ogni controller di visualizzazione che desideri implementare un'azione specifica.
func catchIt(_ userInfo: Notification){
if userInfo.userInfo?["userInfo"] != nil{
let prefs: UserDefaults = UserDefaults.standard
prefs.removeObject(forKey: "startUpNotif")
prefs.synchronize()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: RedirectAppInactiveVC = storyboard.instantiateViewController(withIdentifier: "RedirectAppInactiveVC") as! RedirectAppInactiveVC
self.navigationController?.pushViewController(vc, animated: true)
}
else{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: RedirectAppActiveVC = storyboard.instantiateViewController(withIdentifier: "RedirectAppActiveVC") as! RedirectAppActiveVC
self.navigationController?.pushViewController(vc, animated: true)
}
}
Non dimenticare di annullare l'iscrizione alle notifiche al momento di lasciare il controller della vista, altrimenti il viewController, se ancora in pila, prenderà la notifica ed eseguirlo (così si potrebbe desiderare di che, ma è più sicuro per sapere cosa stai andando in). Quindi suggerisco l'annullamento dell'iscrizione nel viewWillDisappear:
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self)
}
Facendo in questo modo, potrete caricare il viewController che si desidera. Ora non abbiamo ancora trattato tutti i casi. Cosa succede se non hai ancora aperto la tua applicazione. Ovviamente nessun UIViewController è stato caricato e nessuno di questi sarà in grado di ricevere la notifica. Vuoi sapere se hai ricevuto una notifica in didFinishLaunchingWithOptions: nell'appDelegate. Quello che faccio è:
let prefs: UserDefaults = UserDefaults.standard
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? NSDictionary {
prefs.set(remoteNotification as! [AnyHashable: Any], forKey: "startUpNotif")
prefs.synchronize()
}
Ora, è stata impostata una preferenza dicendo che l'applicazione è stata avviata utilizzando una notifica remota. Nei regolatori che devono essere caricati prima nella propria applicazione, io suggerisco di fare quanto segue nella viewDidAppear:
override func viewDidAppear(animated: Bool) {
let prefs:UserDefaults = UserDefaults.standard
if prefs.value(forKey: "startUpNotif") != nil{
let userInfo: [AnyHashable: Any] = ["inactive": "inactive"]
NotificationCenter.default.post(name: Notification.Name(rawValue: "myNotif"), object: nil, userInfo: userInfo as [AnyHashable: Any])
}
Speranza che aiuta. Ho anche creato un repository github per illustrare le notifiche locali: Local Notifications Observer Pattern (simile alle notifiche Remote). Una logica simile può essere implementata utilizzando la vista radice Controller Local Notifications Root Pattern, personalmente penso che dipenderà da ciò che si desidera implementare.
Ottimo lavoro con questo post davvero buono, ma una cosa che vorrei evitare per questo tipo è usare NSUserDefaults(). puoi semplicemente impostare rootViewController nel delegato dell'app e impostare lì i valori. Oh, e per favore correggi prefs.removeObjectForKey ("startUpNotification") a prefs.removeObjectForKey ("startUpNotif") poiché quella è la chiave che usi – Miknash
Penso che tu abbia ragione a seconda del contesto. Se stai impostando il controller della vista radice, non sarai mai in grado di raggiungere una vista specifica che dovrebbe essere precedente a quella vista. Ad esempio, se una notifica di conversazione rende la conversazione come root e poi vuoi far saltare il controller di navigazione per tornare indietro, sarai bloccato. Non sono sicuro di quello che ho appena detto, se sarai in grado di fare pop se hai cambiato la radice direttamente in quel modo? –
Grazie, anche se solo alcune domande, ancora non sono sicuro di come si distingua esattamente tra le diverse notifiche push? Come una notifica voglio passare a un VC e una notifica a un altro? Anche come @NickCatib ha affermato che solo rootViewController sarebbe molto più semplice di NSUserDefaults? –