Uygulamanın bir push bildiriminden başlatılıp başlatılmadığını / açılmadığını algılama


172

Uygulamanın bir push bildiriminden başlatılıp başlatılmadığını / açılmadığını bilmek mümkün müdür?

Başlatma etkinliğinin burada yakalanabileceğini düşünüyorum:

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

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

    }
}

Ancak, uygulama arka plandayken push bildiriminden açıldığını nasıl tespit edebilirim?


6
Bu eski ama çok kullanışlı bir gönderi. Ne yazık ki en iyi cevaplar sorunu çözmez (yorumların belirttiği gibi). Mevcut cevap tam olmadığından lütfen yeni bir cevabı 'kabul edildi' olarak işaretlemeyi düşünün.
16:16

1
Bu sorunun 100 binden fazla görünümü var, ancak seçilen yanıt yanlış veya tam. Ziyaretçilere, modern çözümler bulmak için Oylar yerine Aktif'e göre sıralamayı düşünün.
Albert Renshaw

Yanıtlar:


187

Bkz. Bu kod:

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

ile aynı

-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification

19
@ManuelM. Bu, arka planda bir uygulama bir push bildirimi ile ön plana getirildiğinde nasıl tespit edileceğini göstermesi açısından iyi bir cevaptır. Uygulama çalışmıyorken, aşağıdaki M.Othman'ın cevabına ihtiyacınız var.
OpenUserX03

6
Ben uygulama çağrısı alıyorum: didReceiveRemoteNotification: bildirimi dokunduktan sonra app sadece arka planda olup olmadığını ya da hiç çalışmıyor bu yüzden bu cevap benim ihtiyaçlarına mükemmel şekilde uyuyor.
İOS

16
Bazılarının belirttiği gibi, bu "bir push bildirimden başlatıldı / açıldı" algılamaz. Bu, bildirim açıldığında değil, alındığında çağrılır. Dolayısıyla, bg'de bir bildirim aldıysanız ancak uygulamayı açmak için uygulama simgesine dokunduysanız, burada bulunan kod yine de çalışmaya devam eder ve kullanıcının açmayı amaçlamadığı bir sayfayı açabilirsiniz.
Bao Lei

4
@ManuelM. Bu yöntem, uygulamanın arka plan modlarında bildirim merkezi ve uygulama simgesi aracılığıyla açılıp açılmadığını söylemez - uzaktan bildirim kontrol edilir. İşaretlenmediğinde yapar. Bu yazıdaki farkı belgeledim: stackoverflow.com/questions/32061897/…
Bao Lei

2
Bunun Google Cloud Messaging ile çalıştığını doğruladı.
CularBytes

127

geç ama belki yararlı

Uygulama çalışmadığında

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

denir ..

push bildirimini kontrol etmeniz gereken yerlerde

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

2
Yukarıdaki snippet'te bildirimin (UILocalNotification *) olarak değil, (NSDictionary *) olarak bildirilmesi gerektiğini unutmayın
cosmix

1
Bu şekilde, çalışma sırasında uygulama için herhangi bir bildirim olup olmadığını görebilirsiniz! Soru, uygulamanın bir bildirimden açılıp açılmadığı nasıl tespit edileceğiydi. Bu durumda, uygulama hiç çalışmıyor olsa bile didReceiveRemoteNotification çağrılır. - Cevabınızı seviyorum, çünkü birçok vaka için oldukça önemli, ancak sorunun doğru cevabı değil.
Axel Zehden

Cevabınız ve bu cevabınız aynı şeyi yapıyor mu?
Bal

38

Sahip olduğumuz sorun, uygulama başlatıldıktan sonra görünümü doğru bir şekilde güncellemektir. Burada kafa karıştırıcı olan karmaşık yaşam döngüsü yöntemleri dizileri vardır.

Yaşam Döngüsü Yöntemleri

İOS 10 testimiz, çeşitli durumlar için aşağıdaki yaşam döngüsü yöntemleri dizilerini ortaya çıkardı:

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

Sorun

Tamam, şimdi yapmamız gerekenler:

  1. Kullanıcının uygulamayı bir push'tan açıp açmadığını belirleme
  2. Görünümü push durumuna göre güncelleme
  3. Sonraki açılışların kullanıcıyı aynı konuma döndürmemesi için durumu temizleyin.

Zor bit, uygulama gerçekten aktif hale geldiğinde görünümün güncellenmesi gerektiğidir, bu da her durumda aynı yaşam döngüsü yöntemidir.

Çözümümüzün taslağı

İşte çözümümüzün ana bileşenleri:

  1. Bir notificationUserInfoörnek değişkeni AppDelegate'te depolayın.
  2. İkisini notificationUserInfo = nilde ayarlayın applicationWillEnterForegroundve didFinishLaunchingWithOptions.
  3. Set notificationUserInfo = userInfoiçindedidReceiveRemoteNotification:inactive
  4. Gönderen applicationDidBecomeActiveher zaman özel bir yöntemini çağırın openViewFromNotificationve pas self.notificationUserInfo. self.notificationUserInfoNil ise , erken dönün, aksi takdirde bulunan bildirim durumuna göre görünümü açın self.notificationUserInfo.

açıklama

Bir push didFinishLaunchingWithOptionsveya açmadan applicationWillEnterForegroundönce her zaman hemen çağrılır didReceiveRemoteNotification:inactive, bu yüzden öncelikle bu durumda bildirimUserInfo'yu sıfırlarız, böylece eski durum olmaz. Daha sonra, didReceiveRemoteNotification:inactiveçağrılırsa, bir itme işleminden açtığımızı biliyoruz, böylece kullanıcıyı doğru görünüme yönlendirmek için self.notificationUserInfoalıp ayarladık applicationDidBecomeActive.

Kullanıcının uygulama değiştirici içinde açık olması durumunda (uygulama ön planda iken ana ekran düğmesine iki kez dokunarak) ve ardından bir push bildirimi alırsa son bir durum vardır. Bu durumda sadece didReceiveRemoteNotification:inactiveçağrılır ve ne WillEnterForeground ne de didFinishLaunching çağrılmaz, bu durumda bu durumla başa çıkmak için özel bir duruma ihtiyacınız vardır.

Bu yardımcı olur umarım.


Sonunda işe yarayan bir şey, teşekkürler! Bir uygulama "appResuming" oluşturmak receiveve uygulama durumu etkin veya uygulama devam ederken yöntemlerde ekranı açmak istedim . Bu, uygulama hala etkin değilken VC'lerin değiştirilmesiyle ilgili sorunlara yol açabilir. Apple yaşam döngüsünü tekrar değiştirene kadar çözümünüz harika görünüyor.
shelll

İOS 9'a ne dersiniz, yaşam döngüsü yöntemleri aynı şekilde ve sırada mı adlandırılıyor? Zaten iOS 9 cihazım yok, bu yüzden bunu düzgün bir şekilde test edemiyorum.
shelll

2
Uygulama değiştirici dışında iki kenar durumu daha var. 1) Bildirim merkezi üstten çekildiğinde ve uygulamayı kapladığında 2) Wifi / BT / vb. Özellikli iOS paneli alttan çekildiğinde ve uygulamayı kapladığında. Her üç durumda da sadece applicationWillResignActivedenir ve sonra applicationDidBecomeActive. Yani applicationWillResignActiveçağrıldıktan sonra a applicationDidEnterBackgroundveya çağrılıncaya kadar alınan bildirimi kaydetmeyin applicationDidBecomeActive.
shelll

Bu kılıfları eklediğiniz için teşekkürler @shelll. Her zaman daha karmaşık hale gelir! İOS9'dan emin değilim. Aynı olduklarını varsaymanın muhtemelen güvenli olduğunu söyleyebilirim, ama kim bilir.
Eric Conner

Sadece aklınızda bulunsun. Bugün iOS 11 Beta 9'u test ediyordum ve uygulamanızı ön planda tuttuğunuzda, telefonu kilitledikten sonra kilit ekranından bir push bildirimi seçtiğimde, applicationWillEnterForeground yerine çağrı yapmadan önce didReceiveRemoteNotification: background çağırıyor iOS 10'da gördüğümüz, applicationWillEnterForeground ve ardından didReceiveRemoteNotification: inactive adını verdiği yerlerde görüyoruz - bu yüzden bu henüz ele alınmayan bir uç durum. Bence bu iOS kodunda bir hata, ancak iOS 11 sürümünün ne kadar yakın olduğu göz önüne alındığında, dikkat edilmesi gereken bir şey.
Roy

24

Bu iyi yıpranmış bir yazı ... ama yine de soruna gerçek bir çözüm eksik (çeşitli yorumlarda belirtildiği gibi).

Orijinal soru, uygulamanın bir push bildiriminden ne zaman başlatıldığını / açıldığını tespit etmektir , örneğin bir kullanıcı bildirime hafifçe vurur. Cevapların hiçbiri bu davayı kapsamıyor.

Nedeni, bir bildirim geldiğinde çağrı akışında görülebilir, application:didReceiveRemoteNotification...

bildirim alındığında çağrılan VE bildirim kullanıcı tarafından dokunulduğunda tekrar. Bu nedenle UIApplicationState, kullanıcının ona dokunup dokunmadığına bakarak söyleyemezsiniz .

Ayrıca, uygulamanın bir 'soğuk başlangıç' bir durumun üstesinden gelmek için artık ihtiyacımız application:didFinishLaunchingWithOptions...olarak application:didReceiveRemoteNotification...(belki 8 sıra) 9+ iOS'taki başlatılması sonra tekrar çağrılır.

Peki, kullanıcının hafifçe vurma olay zincirini başlattı olmadığını nasıl anlarsınız? Benim çözüm, uygulamanın arka plandan veya soğuk başlangıçtan çıkmaya başladığı zamanı işaretlemek ve ardından bu zamanı kontrol etmektir application:didReceiveRemoteNotification.... 0.1 saniyeden azsa, musluğun başlangıcı tetiklediğinden emin olabilirsiniz.

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

Hızlı 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)
      }
    }
}

Bunu her iki durumda da test ettim (arka planda uygulama, uygulama çalışmıyor) ve bir cazibe gibi çalışıyor. 0.1s de oldukça muhafazakardır, gerçek değer ~ 0.002s'dir, bu nedenle 0.01 de iyidir.


1
Bu, bildirime gerçekten dokunma ile durum çubuğunun uygulama üzerinde açılması arasında ayrım yapan tek çalışma çözümü gibi görünüyor.
liviucmg

4
Bu, StackOverflow'un tümünden tek çalışan çözümdür. Eklemek istediğim tek şey, iOS 10 ve üstünü desteklediğinizde UNNotificationCenterAPI'yı, özellikle UNNotificationCenterDelegate yöntemlerini kullanabilirsiniz. Bu API çağrısı func userNotificationCenter(UNUserNotificationCenter, didReceive: UNNotificationResponse, withCompletionHandler: @escaping () -> Void) yöntemi yalnızca kullanıcı gerçekten bildirime dokunduğunda.
DenHeadless

hızlı 3 nasıl görünüyor?
Jochen Österreicher

Bir uygulama etkin değilken (kullanıcı bildirim merkezini aşağı kaydırır veya kontrol merkezini hızlıca kaydırır) ve bir bildirim alırken çözüm çalışmaz. Kullanıcı bildirime dokunduğunda uygulama applicationWillEnterForeground çağrı almaz , sonuç olarak çözüm musluğu algılayamaz.
DevGansta

Eğer olarak sınıf eklediğinizde @DevGansta UNUserNotificationCenter.current().delegateiçinde application:didFinishLaunchingWithOptions, uygulama arayacak userNotificationCenter(didReceive response)size anlatılan durumda musluk sonra
Dorian Roy

22

Uygulama sona erdiğinde ve kullanıcı push bildirimine dokunduğunda

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

Uygulama arka planda olduğunda ve kullanıcı push bildirimine dokunduğunda

Kullanıcı uygulamanızı sistemde görüntülenen uyarıdan açarsa, uygulamanız ön plana girmek üzereyken sistem bu yöntemi tekrar çağırabilir , böylece kullanıcı arayüzünüzü güncelleyebilir ve bildirimle ilgili bilgileri görüntüleyebilirsiniz.

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

Uygulamanıza bağlı olarak, content-availableiçeride sessiz bir itme de gönderebilir aps, bu yüzden bunun da farkında olun :) Bkz. Https://stackoverflow.com/a/33778990/1418457


2
Sadece kirli bir kesmek gibi hissettirmeyen ve doğru cevap. Ne eksik uygulama arka planda ve kullanıcı elle açarsa, nasıl kontrol edilir? Hala soğuk başlatma ve arka plandan itme kontrol edebiliyorken.
Jochen Österreicher

1
@ JochenÖsterreicher Merhaba, burada özetlerim, lütfen medium.com/@onmyway133/…
onmyway133

19

Swift 2.0 'Çalışmıyor' Durumu için (Yerel ve Uzaktan Bildirim)

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
}

15

In application:didReceiveRemoteNotification:uygulama ön veya arka planda olduğunda çek bildirim aldık olsun.

Arka planda alındıysa, uygulamayı bildirimden başlatın.

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        NSLog(@"Notification received by running app");
    } else {
        NSLog(@"App opened from Notification");
    }
}

3
Kullanıcı farklı bir ekrandayken bildirim gönderilirse (örneğin, durum çubuğunu aşağı çekip uygulamanızdan bir bildirim alırsa) "Bildirimden açılan uygulama" nın yanlış bir pozitif olacağını unutmayın.
Kevin Cooper

4
@Kevin Tam olarak. Apple, bildirimleri ele alma sürecini tasarlamak için neden bir stajyer koyduğunu merak ediyor ...
Andreas

etkin durumda alınan bildirime dokunursak nasıl tespit edebiliriz
Mayank Jain

13

Hızlı için:

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

    }

}

4

Evet, appDelegate'te bu yöntemle tespit edebilirsiniz :

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

Yerel Bildirim için:

- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
         /* your Code*/
}

1
Uygulama çalışmıyorsa bu yöntem çağrılmaz. Burada sordu
Pfitz

Benim sorunum bildirimi işlememek değil, daha çok banner'ı (uygulama arka plandayken) tıkladığınızda açılmış olup olmadığını bilmek.
joao

3

birisi hızlı cevap 3 istiyorsa

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

Uygulama uygulaması sonlandırıldığında push bildirimi dokunarak açılırsa ama nasıl bilmek
user3804063

1
Birisi basmaya dokunduğunda, uygulama sonlandırılsın veya edilmesin açık olacaktır. ve .aktif dava çağırıyor
Hamid Shahsavari

1
Ben app itme bantlayarak açılır ve ilgili içeriğe gitmek istiyor bunu tespit instagram gördüm tespit etmek gerekir
user3804063

Yerel bildirimlere ne dersiniz?
Amir Shabani

3

Bunu Xamarin kullanıcıları için gönderiyor.

Uygulamanın push bildirimi ile başlatılıp başlatılmadığını tespit etmenin anahtarı AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options)yöntem ve iletilen seçenekler sözlüğüdür.

Yerel bir bildirim olmadığını seçenekleri Sözlük içinde bu anahtara sahip olacaktır: UIApplication.LaunchOptionsLocalNotificationKey.

Uzak bir bildirim ise, olacaktır UIApplication.LaunchOptionsRemoteNotificationKey.

Anahtar olduğunda LaunchOptionsLocalNotificationKey, nesne türündedir UILocalNotification. Daha sonra bildirime bakabilir ve hangi özel bildirimin olduğunu belirleyebilirsiniz.

Uzman ipucu: UILocalNotificationİçinde bir tanımlayıcı UNNotificationRequestyok , aynı şekilde . UserInfo içine bir requestId içeren bir sözlük anahtarı koyun, böylece test ederken UILocalNotification, bazı mantığı dayandıracak belirli bir requestId elde edersiniz.

Bulduğum bile iOS'ta 10+ cihazlar olduğunu kullanan konum bildirimlerini oluştururken UNUserNotificationCenter'ın AddNotificationRequest& UNMutableNotificationContentsöz konusu uygulama, (I öldürdü) çalışmadığı ve Sözlük hala içerdiğini, bildirim merkezinde bildirimi dokunarak başlatıldığında UILocalNotificaitonnesne.

Bu, bildirime dayalı başlatmayı kontrol eden kodumun iOS8 ve iOS 10+ cihazlarda çalışacağı anlamına gelir

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

2

Doğrudan dokümantasyondan

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

Uygulama çalışıyorsa ve bir uzaktan bildirim alırsa, uygulama bildirimi işlemek için bu yöntemi çağırır.

Bu yöntemi uygulamanız, bildirimi uygun bir işlem yapmak için kullanmalıdır.

Ve biraz sonra

Bir push bildirimi geldiğinde uygulama çalışmıyorsa, yöntem uygulamayı başlatır ve başlatma seçenekleri sözlüğünde uygun bilgileri sağlar.

Uygulama, bu push bildirimini işlemek için bu yöntemi çağırmaz.

Bunun yerine,

application:willFinishLaunchingWithOptions:

veya

application:didFinishLaunchingWithOptions:

yönteminin push bildirimi bilgi yükü verilerini alması ve uygun şekilde yanıtlaması gerekir.


2

Daha doğru bir şekilde görselleştirmek ve diğer tüm durumları dikkate almak için kendi kullanımım için oluşturduğum bir durum grafiğiyle başlayacağım: https://docs.google.com/spreadsheets/d/e/2PACX-1vSdKOgo_F1TZwGJBAED4C_7cml0bEATqeL3P9UKpBwASlT6ZkOdOzLOzLOzLOzLOzLOzLOzLOzLO ? GID = 0 ve tek = gerçek

Bu çizelgeyi kullanarak, neredeyse tüm olası kullanım durumlarında çalışan sağlam bir bildirim işleme sistemi geliştirmek için gerçekten neyin gerekli olduğunu görebiliriz.

Komple çözüm ↓

  • Mağaza bildirim payload didReceiveRemoteNotification
  • ApplicationWillEnterForeground ve didFinishLaunchingWithOptions içindeki depolanmış bildirimi temizle
  • Denetim Merkezi / Bildirim merkezinin çekildiği durumlarla başa çıkmak için, willResignActiveCalled işaretini kullanabilir ve başlangıçta false olarak ayarlayabilirsiniz , applicationWillResignActive yönteminde bunu true olarak ayarlayabilirsiniz ,
  • In didReceiveRemoteNotification yönteminde, willResignActiveCalled yanlıştır sadece bildirimler (userinfo) tasarruf.
  • Reset YANLıŞ olarak willResignActiveCalled içinde applicationDidEnterBackground ve applicationDidBecomeActive yöntemiyle.

Not: Eric'in cevabı hakkındaki yorumlarda da benzer bir cevap önerilmektedir, ancak durum sayfası uygulamamda yaptığım gibi tüm olası senaryoları bulmaya yardımcı olmaktadır.

Lütfen aşağıdaki kodun tamamını bulun ve herhangi bir özel durum ele alınmadıysa aşağıya yorum yapın:

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 : Bu, tüm kodlarınızı uygulamanın farklı bölümlerine gitmek, Veritabanlarını (CoreData / Realm) işlemek ve bir bildirim alındığında yapılması gereken diğer tüm şeyleri yapmak için yazabileceğiniz yerdir.

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

daha iyi bir yorum olarak koymak daha iyi çünkü bu cevap değil.
Maddy

@Maddy Öneri için teşekkürler, Cevabı tüm detaylarla güncelledi
chetan anand

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

1

Yalnızca bir güvenilir yol vardır ve yalnızca iOS 10+ için çalışır :

UNUserNotificationCenterUygulamak UNUserNotificationCenterDelegateyöntemi kullanarak :

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

0

Kullanabilirsiniz:

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

uzaktan push bildirimlerini işlemek için.

Buradaki belgelere bakın



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

Ancak uygulama kapatılırsa (sonlandırılırsa). Twitter veya Instagram gibi bir şekilde algılar ve uygulama kapalıysa sizi yeni
gönderiye

0

Bu sorudaki sorun, uygulamanın "açılmasının" iyi tanımlanmamış olmasıdır. Bir uygulama, çalışmayan bir durumdan soğuk başlatılır veya etkin olmayan bir durumdan yeniden etkinleştirilir (örneğin, başka bir uygulamadan bu uygulamaya geri dönerek). İşte tüm bu olası durumları ayırt etmek için benim çözümüm:

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

Ve MXDefaultssadece küçük bir sarıcı NSUserDefaults.


0

İçin 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)")

    }
}

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

0

İOS 10+ için, uygulamanın durumuna bakılmaksızın bildiriminizin ne zaman tıklandığını bilmek için bu yöntemi kullanabilirsiniz.

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

    //Notification clicked
    completionHandler()
}

0

M.Othman cevabı içermeyen uygulamalar için doğru sahne temsilci için Sahne Delege Uygulamalar Bu benim için çalıştı iOS 13

İşte senaryo bağlanacak yazılması gereken kod

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

Önceki sürümleri desteklemeye yönelik uygulama temsilcisinin kodu didFinishLaunchingWithOptions

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

            //Launched from push notification
        } else {

            //Launch from other source
        }

-1

Hızlı Kullanıcılar için:

Açma veya benzeri bir şeyle açılışta farklı bir sayfa başlatmak istiyorsanız, aşağıdaki gibi kontrol etmeniz gerekir didFinishLaunchingWithOptions:

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


1
AppDelegate.h dosyasında bir gezinme denetleyicisi oluşturun. Kullanıyorum ve işe yarıyor!
AAA

-1

SWIFT'TE:

Ben push Bildirimleri (arka plan getirme ile) çalıştırıyorum. Uygulamam arka planda olduğunda ve bir push bildirimi aldığımda, appDelegate'te didReceiveRemoteNotification'ın iki kez çağrılacağını buldum; bildirim alındığında bir kez ve kullanıcı bildirim uyarısını tıkladığında bir kez daha.

Bildirim uyarısının tıklanıp tıklanmadığını tespit etmek için, appDelegate'teki didReceiveRemoteNotification içindeki applicationState raw value == 1'in olup olmadığını kontrol edin.

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

Umarım bu yardımcı olur.


-1

Uygulama shanegao olarak arka planda olduğunda kullanabilirsiniz

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

Ancak uygulamayı başlatmak ve uygulama kapalıyken ve uygulamanızda hata ayıklamak istiyorsanız Düzen Düzenleme'ye gidebilir ve soldaki menüden Çalıştır'ı seçebilir ve ardından başlatma sırasında Yürütülebilir dosyanın başlatılmasını bekle'yi ve ardından push bildirimine tıklayın

Düzeni Düzenle> Çalıştır> Yürütülebilir dosyanın başlatılmasını bekleyin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.