iOS push bildirimi: Uygulama arka plandayken kullanıcının bildirime dokunup dokunmadığı nasıl tespit edilir?


116

Bu konuyla ilgili çok sayıda stackoverflow iş parçacığı var, ancak yine de iyi bir çözüm bulamadım.

Uygulama arka planda değilse, kontrol edebilirim launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]içinde application:didFinishLaunchingWithOptions:bir bildirimden açılmış olup olmadığını görmek için çağrı.

Uygulama arka plandaysa, tüm gönderiler application:didReceiveRemoteNotification:uygulamanın durumunu kullanmanızı ve kontrol etmenizi önerir . Ancak denediğim gibi (ve bu API'nin adından da anlaşılacağı gibi), bu yöntem, dokunulmak yerine bildirim alındığında çağrılıyor.

Yani sorun şu ki, uygulama başlatılırsa ve ardından arka planda çalışırsa ve sizden bir bildirim alındıysa application:didReceiveNotification( application:didFinishLaunchWithOptions:bu noktada tetiklenmez), kullanıcının bildirime dokunarak veya yalnızca simgesine dokunarak uygulamayı devam ettirip ettirmediğini nasıl anlarsınız? uygulama simgesi? Çünkü kullanıcı bildirime dokunduysa beklenti o bildirimde belirtilen sayfanın açılmasıdır. Aksi takdirde olmamalı.

handleActionWithIdentifierÖzel eylem bildirimleri için kullanabilirdim , ancak bu yalnızca özel bir eylem düğmesine dokunulduğunda tetikleniyor, kullanıcı bildirimin ana gövdesine dokunduğunda değil.

Teşekkürler.

DÜZENLE:

Aşağıdaki bir cevabı okuduktan sonra, bu şekilde sorumu netleştirebileceğimi düşündüm:

Bu 2 senaryoyu nasıl ayırt edebiliriz:

(A) 1. uygulama arka plana gider; 2. bildirim alındı; 3. kullanıcı bildirime dokunur; 4. uygulama ön plana giriyor

(B) 1. uygulama arka plana gider; 2. bildirim alındı; 3. kullanıcı bildirimi görmezden gelir ve daha sonra uygulama simgesine dokunur; 4. uygulama ön plana giriyor

Çünkü application:didReceiveRemoteNotification:her iki durumda da 2. adımda tetiklenir.

Veya, application:didReceiveRemoteNotification:yalnızca (A) için 3. adımda tetiklenmelidir, ancak uygulamamı bir şekilde yanlış yapılandırdım, bu yüzden 2. adımda görüyorum?


Yükünüz için özel bir sözlük değeri kullanın ve buna göre hareket edin. Gayet basit.
soulshined

@soulshined yükte bir sözlük kullanıcının bildirime dokunup dokunmadığını gösterebilir, değil mi? Örneğin, arkadaşınız A bir makale B yayınladı, uygulama arka plandayken yükte {kullanıcı: A, makale: B} diyebilirsiniz ve didReceiveRemoteNotification alırsınız. Uygulamanın ne zaman devam edeceğini, makaleyi görüntülemeniz gerekip gerekmediğini nasıl anlarsınız?
Bao Lei

2
@soulshined Belgeleri okudum ve kendimi ReceiveRemoteNotification'ın ne işe yaradığı konusunda eğittim. Gerçekten sorumu okudun mu? Apple'ın resmi belgelerine göre didReceiveRemoteNotification "temsilciye çalışan uygulamanın bir uzaktan bildirim aldığını söyler". Kullanıcının bir bildirime dokunup dokunmadığını anlamanın iyi bir yolunun ne olduğunu soruyorum. Bahsettiğiniz SO bağlantısı, uygulama yeni bir başlangıçtan itibaren başlatıldığında, senaryoyu uygulama arka planda olduğunda soruyorum.
Bao Lei


1
@soulshined Tamam belki yeterince net ifade etmedim. Demek istediğim, eğer uygulama arka planda değil de tamamen sonlandırılırsa, evet didFinishLaunching çağrılacak. Ancak, uygulamanızı başlatır ve ardından uygulamayı arka planda çalıştırırsanız ve şimdi bir bildirim gelir ve kullanıcı bildirime dokunur ve şimdi didFinishLaunching tekrar çağrılmayacaktır. Bunun yerine applicationWillEnterForeground ve applicationDidBecomeActive çağrılacaktır. Kullanıcı bildirime veya uygulama simgesine dokunduğu için uygulamanın ön plana girdiğini nasıl anlarsınız?
Bao Lei

Yanıtlar:


102

Tamam, sonunda anladım.

Hedef ayarlar ➝ Yetenekler sekmesinde ➝ Arka Plan Modları, "Uzaktan Bildirimler" i işaretlerseniz, application:didReceiveRemoteNotification:bildirim gelir gelmez tetiklenir (uygulama arka planda olduğu sürece) ve bu durumda olup olmadığını anlamanın bir yolu yoktur. kullanıcı bildirime dokunacaktır.

Bu kutunun işaretini kaldırırsanız, application:didReceiveRemoteNotification:yalnızca bildirime dokunduğunuzda tetiklenecektir.

Bu kutuyu işaretlemenin uygulama temsilcisi yöntemlerinden birinin davranışını değiştirmesi biraz garip. Bu kutunun işaretlenmesi daha güzel olur, Apple, bildirim alma ve bildirim dokunuşu için iki farklı delege yöntemi kullanır. Bence geliştiricilerin çoğu her zaman bir bildirime dokunulup dokunulmadığını bilmek istiyor.

Umarım bu, bu sorunla karşılaşan herkes için yararlı olacaktır. Apple da burada açıkça belgelemedi, bu yüzden anlamam biraz zaman aldı.

görüntü açıklamasını buraya girin


6
Arka Plan Modlarım tamamen "KAPALI" olarak ayarlandı, ancak yine de uygulamayla arka plan modunda bir bildirim geldiğinde bildirim alıyorum.
Gottfried

5
Harika! Bu bana yardımcı oldu. Ne yazık ki uzaktan bildirimleri kapatmam gerekiyor. Bir push bildirimi geldiğinde VE kullanıcının dokunuşunu algıladığında verileri önceden getirmek istiyorum. Bunu başarmanın bir yolunu bulamıyorum.
Peter Fennema

1
Arka Plan modunu "AÇIK" moduna ayarlıyorum ve uzaktan bildirimleri etkinleştiriyorum. Hala bildirim olayını tespit edemiyor.
kalim sayyad

1
Aynı sorunu yaşıyorum Arka plan modu "AÇIK" olarak ayarlandı ve uzaktan bildirim etkinleştirildi, ancak arka plan modunda uygulamaya bildirim geldiğinde hala bildirim
almıyor

@Bao - Bu seçenek temelde bildirimle ilgili içeriği arka planda indirmek için kullanıldığından, Appstore'da reddedilmeye neden olacağını düşünüyorum. Dolayısıyla, herhangi bir içerik indirmezseniz, Apple uygulamanızı reddedebilir. developer.apple.com/library/ios/documentation/iPhone/Conceptual/…
niks

69

Sizinle aynı şeyi arıyordum ve aslında uzaktan bildirimin işaretlenmesini gerektirmeyen bir çözüm buldum.

Kullanıcının dokunduğunu veya uygulamanın arka planda olup olmadığını veya etkin olup olmadığını kontrol etmek için, uygulamadaki durumunu kontrol etmeniz yeterlidir.

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{

    if(application.applicationState == UIApplicationStateActive) {

        //app is currently active, can update badges count here

    }else if(application.applicationState == UIApplicationStateBackground){

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

    }else if(application.applicationState == UIApplicationStateInactive){

        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here

    }

Daha fazla bilgi için kontrol edin:

UIKit Çerçeve Başvurusu> UIApplication Sınıf Başvurusu> UIApplicationState


10
Uygulama ekrandayken kullanıcının Bildirim merkezi (yukarıdan kaydırın) veya Kontrol merkezi (aşağıdan kaydırın) ile etkileşime girmesinin bir sonucu olarak uygulamanın UIApplicationStateInactive olmasına ne dersiniz? Görünüşe göre APNS'nin Devre Dışı durumda mı alındığını veya kullanıcının gerçekten ona dokunduğunu anlamanın bir yolu yok.
Kostia Kim

1
@KostiaKim Haklısın, ama bu süper uç bir durum ... onun dışında, bu cevap, ön plandaki uygulamayı ayırmak açısından en geçerli ... kullanıcı dokunması ... arka planda uygulama
Honey

Teşekkürler, bu tür her şeyi aydınlatıyor. Temsilci yönteminin uygulama arka plandayken çağrılabilmesi için push bildiriminin content-availableanahtarı içermesi gerektiğini , ancak resmi belgelerde belirtildiği gibi bildirimin sessiz (yani bir ses veya rozet içermemesi) gerektiğini unutmayın . .
Nickkk

1
@KostiaKim Aslında, kontrol merkezinin açık olup olmadığını bilmeme sorununu çözebildim veya kullanıcının gerçekten bildirime dokunduğunu, bu uygulamada doğru func applicationDidEnterBackground(_ application: UIApplication)ve yanlış olarak ayarlanmış bir boole ekleyerek func applicationDidBecomeActive(_ application: UIApplication)uygulamada göstermeme izin verdi kontrol merkezi veya bildirimler listesi nedeniyle uygulama etkin olmadığında bildirimler
DatForis

3
Apple'ın neden farklı bir etkinlik sunmadığı ya da kullanıcının bildirimle gerçekten etkileşime girdiğini belirtmek için meta verilere bir bayrak eklemesi aklımı karıştırıyor. Kullanıcının uygulama durumu hakkındaki ortam bilgisine dayalı olarak bir işlem yapıp yapmadığını 'çıkarmak' zorunda olmak, kullanıcının uygulama davranışı beklentisini etkileyen önemli bir bilgi parçası için oldukça mantıksızdır. Belki de yapılacak tek şey, uygulamayı bu bilgilerle açmak için özel bir eylem oluşturmaktır?
Allan Nienhuis

20

Göre iOS / XCode: bilmek söz konusu uygulama bildirimini veya sıçrama tahtası uygulama simgesinde bir tıklama ile başlatıldı? didReceiveLocalNotification'daki uygulama durumunu şu şekilde kontrol etmeniz gerekir:

if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive)
{
    // user has tapped notification
}
else
{
    // user opened app from app icon
}

Bana tamamen mantıklı gelmese de işe yarıyor gibi görünüyor.


1
Bu senaryoda işe yaramaz. Bunu daha önce denedim. Bu onay kutusu işaretlendiğinde (ayrıntılar için kabul ettiğim cevaba bakın), bildirim geldiğinde, kullanıcı bildirime dokunmamış olsa bile "// kullanıcı bildirime dokundu" yorumlu satırınız girilecektir (bildirim yeni geldi ).
Bao Lei

3
Katılmıyorum. Arka plan yeteneklerimde "Uzaktan bildirimler" i işaretledim ve cevabımda açıklanan şekilde çalışıyor. "Arka planda getirme" seçeneğini de işaretledim. Belki bu değişikliğe neden olur?
Werner Kratochwil

cevabımı + 1'leyebilir misin lütfen? ;-) Stackoverflow'a daha fazla katılmak için hala bazı oylara ihtiyacım var. Çok teşekkürler
Werner Kratochwil

Yupe, çözüm bu. tnx.
Afshin

Bildirim, kullanıcı farklı bir ekrandayken gönderilirse (örneğin, durum çubuğunu aşağı çekip uygulamanızdan bir bildirim alırsa) bunun yanlış bir pozitif olacağını unutmayın.
Kevin Cooper

16

Biri hızlı 3.0'da istiyorsa

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
    }

hızlı 4 için

switch UIApplication.shared.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
}

Bu kodu hangi tetikleyiciye eklemeliyiz, didReceiveRemoteNotification veya didFinishLaunchingWithOptions?
Dashrath

2
DidReceiveRemoteNotification
Hamid Shahsavari

@Hamid sh ,,,, Her durumda, yani uygulama ön planda olduğunda, arka planda, kapatıldığında (sonlandırıldığında) push bildirimi aldım ..! ancak benim sorunum, uygulama arka plan durumundayken ve kapatma (sonlandırma) durumundayken rozet sayısının nasıl artırılacağıdır ???? Lütfen bana bunu nasıl yaptığımı ayrıntılı olarak anlatın ....? uygulama rozet sayım yalnızca uygulama zemin durumundayken artar .....? mümkünse lütfen kısaca söyleyin .......!
Kiran jadhav

9

Ben de bu problemle karşılaştım - ancak iOS 11'de yeni UserNotificationsÇerçeve ile.

İşte benim için şöyle:

  • Yeni Lansman: application:didFinishLaunchingWithOptions:
  • Bir sonlandırma durumundan alındı: application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
  • Ön Planda Alındı: userNotificationCenter(_:willPresent:withCompletionHandler:)
  • Arka Planda Alınan: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:

Bunu iOS 11 + 'da yapmanın yolu budur
OhadM

Bu çok karmaşık 🤦‍♂️
Zorayr

8

"Arka Plan Modları"> "Uzaktan bildirimler" işaretliyse == EVET, bildirim olayına hafifçe vurun:

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

Bana yardımcı oldu. Zevk alın :)


Apple'ın bunu eklediğini gördüm, ancak bildirimin özel yükünü bu şekilde nasıl alacağımı bulamadım.
sudo

Bu işlev, uygulama bir arka plan durumundayken ve etkin olduğunda ve ayrıca uygulama,
kapatılan

@NikhilMuskur sadece "uzaktan bildirimler" etkinse evet?
Zorayr

@Zorayr evet doğru
Nikhil Muskur

4

Benim durumumda, OFF arka plan modu herhangi bir fark yaratmadı. Ancak, uygulama askıya alındığında ve kullanıcı bildirime dokunduğunda, durumu şu geri arama yöntemiyle halledebilirdim:

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

}

Apple'ın söylediği resmi yol budur. Apple'ın belgesine göre, kullanıcı push bildirimi kullanıcı arayüzüyle etkileşime girdiğinde çağrılacaktır. Uygulama arka planda değilse, uygulamayı arka plan modunda başlatır ve bu yöntemi çağırır.
Ryan

3

İOS 10 ve üstü için bunu AppDelegate'e koyun, bildirimlere dokunulduğunu öğrenmek için (uygulama kapalı veya açık olsa bile çalışır)

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
print("notification tapped here")
}

1
Bu, iOS 10+ için doğru cevaptır. Burada başka bir ileti dizisinde tam açıklama sağlanmıştır: stackoverflow.com/a/41783666/1761357 .
dead_can_dance

2

Sınıf içinde PushNotification alınan tanıtıcı için iki Func vardır PushNotificationManager:

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate{

}

Bildirim gelir gelmez ilk tetikleyiciyi test ettiğimde

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

    completionHandler(UNNotificationPresentationOptions.alert)

    //OnReceive Notification
    let userInfo = notification.request.content.userInfo
    for key in userInfo.keys {
         Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler([])

}

Ve ikincisi Bildirime Dokunulduğunda:

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

    //OnTap Notification
    let userInfo = response.notification.request.content.userInfo
    for key in userInfo.keys {
        Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler()
}

Ayrıca Uzaktan Bildirimin hem AÇIK hem de KAPALI durumlarıyla test ettim (Arka Plan Modlarında)


1

SWIFT 5.1

UIApplication.State benim için çalışmadı, çünkü uygulamamda parmak izini (modal gösterilir) okuduktan sonra, bildirim üst çubukta da atılıyor ve kullanıcının tıklaması gerekiyor.

Ben yarattım

public static var isNotificationFromApp: Bool = false

içinde AppDelegateve truebaşlangıçta viewControllerve sonra bildirimde ayarlıyorum storyboard/ viewControllersadece kontrol ediyorum :)

Umarım işe yarayabilir


-7

application:didReceiveRemoteNotification:fetchCompletionHandler:Uygulama arka planda olduğunda uygulama temsilcisinin yöntemini çağırmak için push bildiriminizin yükünü yapılandırabilirsiniz . Burada bir bayrak ayarlayabilirsiniz, böylece kullanıcı uygulamanızı bir sonraki sefer başlattığında işleminizi gerçekleştirebilirsiniz.

Apple'ın belgelerinden, push bildirimiyle ilişkili yeni içeriği indirmek için bu yöntemleri kullanmalısınız. Ayrıca işe bunun için de, içermelidir Arkaplan modları ve itme bildirim yükünden Uzaktan bildirim etkinleştirmek zorunda content-availableelma doktordan bir İndirme Bölümü Başlatacak itin Bildirimler kullanma bakın daha fazla bilgi Dan 1'e değeri seti ile anahtar burada .

Başka bir yol da push bildirim yükünde rozet sayısına sahip olmaktır. Böylece, uygulamanızın bir sonraki açılışında başvuru rozet sayısını kontrol edebilirsiniz. Sıfırdan büyükse, işleminizi yapın ve sunucudan sıfır / temiz rozet sayımı yapın.

Umarım bu size yardımcı olur.


@bhusan sorumun detaylarını okudunuz mu? Bildirim henüz geldiğinde (kullanıcı dokunmadan önce) didReceiveRemoteNotification'ın çağrıldığını görüyorum. Kullanıcının dokunup dokunmadığını öğrenmek istedim.
Bao Lei

OP'nin sorusuna cevap vermedin. Sadece bir bildirim olduğunu bilmek istemiyor. Kullanıcının bu uzak bildirime dokunarak Uygulamayı açıp açmadığını bilmek istiyor.
Joe C
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.