Pemberitahuan push iOS: bagaimana cara mendeteksi jika pengguna mengetuk pemberitahuan ketika aplikasi berada di latar belakang?

116

Ada banyak utas stackoverflow mengenai topik ini, tetapi saya masih belum menemukan solusi yang baik.

Jika aplikasi tidak di latar belakang, saya dapat memeriksa launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]di application:didFinishLaunchingWithOptions:panggilan untuk melihat apakah itu dibuka dari pemberitahuan.

Jika aplikasi berada di latar belakang, semua posting menyarankan untuk menggunakan application:didReceiveRemoteNotification:dan memeriksa status aplikasi. Namun saat saya bereksperimen (dan juga seperti yang disarankan oleh API ini), metode ini dipanggil saat notifikasi diterima, bukan disadap.

Jadi masalahnya adalah, jika aplikasi diluncurkan dan kemudian di-background, dan Anda tahu pemberitahuan diterima dari application:didReceiveNotification( application:didFinishLaunchWithOptions:tidak akan memicu saat ini), bagaimana Anda tahu jika pengguna melanjutkan aplikasi dari dengan mengetuk pemberitahuan atau hanya mengetuk ikon aplikasi? Karena jika pengguna menge-tap notifikasi tersebut, harapannya adalah membuka halaman yang disebutkan dalam notifikasi tersebut. Kalau tidak, seharusnya tidak.

Saya dapat menggunakan handleActionWithIdentifieruntuk pemberitahuan tindakan kustom, tetapi ini hanya akan dipicu ketika tombol tindakan kustom diketuk, bukan saat pengguna mengetuk bagian utama pemberitahuan.

Terima kasih.

EDIT:

setelah membaca satu jawaban di bawah ini, saya berpikir dengan cara ini saya dapat menjelaskan pertanyaan saya:

Bagaimana kita bisa membedakan 2 skenario ini:

(A) 1.app pergi ke latar belakang; 2. pemberitahuan diterima; 3. pengguna mengetuk notifikasi; 4. aplikasi memasuki latar depan

(B) 1.app pergi ke latar belakang; 2. pemberitahuan diterima; 3. pengguna mengabaikan notifikasi dan mengetuk ikon aplikasi nanti; 4. aplikasi memasuki latar depan

Karena application:didReceiveRemoteNotification:dipicu dalam kedua kasus di langkah 2.

Atau, harus application:didReceiveRemoteNotification:dipicu di langkah 3 hanya untuk (A), tetapi entah bagaimana saya salah mengonfigurasi aplikasi sehingga saya melihatnya di langkah 2?

Bao Lei
sumber
Gunakan nilai kamus khusus untuk payload Anda dan lakukan tindakan yang sesuai. Cukup mudah.
Soulshined
@soulshined kamus dalam payload dapat mewakili apakah pengguna mengetuk notifikasi, bukan? mis. teman Anda A memposting artikel B, Anda dapat mengatakan {pengguna: A, artikel: B} di payload, saat aplikasi berada di latar belakang dan Anda mendapatkan didReceiveRemoteNotification. Bagaimana Anda tahu kapan aplikasi dilanjutkan, apakah Anda harus menampilkan artikel?
Bao Lei
2
@soulshined Saya membaca dokumentasi dan saya mendidik diri saya sendiri tentang apa yang dilakukan didReceiveRemoteNotification. Apakah Anda benar-benar membaca pertanyaan saya? Sesuai dengan dokumentasi resmi Apple, didReceiveRemoteNotification "memberi tahu delegasi bahwa aplikasi yang berjalan menerima notifikasi jarak jauh". Saya bertanya apa cara yang baik untuk mengetahui jika pengguna mengetuk notifikasi. Tautan SO yang Anda rujuk adalah saat aplikasi diluncurkan dari awal yang baru, saya menanyakan skenario saat aplikasi berada di latar belakang.
Bao Lei
1
@soully OK mungkin saya tidak menyatakannya dengan cukup jelas. Maksud saya, jika aplikasi benar-benar ditutup, bukan di latar belakang, ya didFinishLaunching akan dipanggil. Namun jika Anda meluncurkan aplikasi, lalu melatarbelakangi aplikasi, dan sekarang pemberitahuan masuk, dan pengguna mengetuk pemberitahuan, dan sekarang didFinishLaunching tidak akan dipanggil lagi. Sebagai gantinya applicationWillEnterForeground dan applicationDidBecomeActive akan dipanggil. Bagaimana Anda tahu bahwa aplikasi memasuki latar depan karena pengguna mengetuk notifikasi atau ikon aplikasi?
Bao Lei

Jawaban:

102

OK akhirnya saya tahu.

Di setelan target ➝ tab Capabilities ➝ Mode Latar Belakang, jika Anda mencentang "Notifikasi Jarak Jauh", application:didReceiveRemoteNotification:akan dipicu segera setelah pemberitahuan tiba (selama aplikasi berada di latar belakang), dan dalam hal ini tidak ada cara untuk mengetahui apakah pengguna akan mengetuk notifikasi.

Jika Anda tidak mencentang kotak itu, hanya application:didReceiveRemoteNotification:akan dipicu saat Anda mengetuk pemberitahuan.

Agak aneh bahwa mencentang kotak ini akan mengubah perilaku salah satu metode delegasi aplikasi. Akan lebih baik jika kotak itu dicentang, Apple menggunakan dua metode delegasi yang berbeda untuk penerimaan pemberitahuan dan ketuk pemberitahuan. Saya pikir sebagian besar pengembang selalu ingin tahu apakah ada pemberitahuan yang disadap atau tidak.

Semoga ini bermanfaat bagi siapa pun yang mengalami masalah ini. Apple juga tidak mendokumentasikannya dengan jelas di sini, jadi saya butuh beberapa saat untuk mengetahuinya.

masukkan deskripsi gambar di sini

Bao Lei
sumber
6
Saya menyetel Mode Latar Belakang ke "NONAKTIF" sepenuhnya, tetapi masih mendapat pemberitahuan ketika ada pemberitahuan datang dengan aplikasi dalam mode latar belakang.
Gottfried
5
Bagus! Ini membantu saya. Namun sayang sekali saya harus mematikan notifikasi jarak jauh. Saya ingin mengambil data lebih dulu ketika pemberitahuan push tiba DAN mendeteksi ketukan pengguna. Saya tidak dapat menemukan cara untuk mencapai ini.
Peter Fennema
1
Saya menyetel mode Latar Belakang ke mode "ON" dan mengaktifkan notifikasi jarak jauh. Masih tidak dapat mendeteksi acara notifikasi.
kalim sayyad
1
Saya memiliki masalah yang sama Mode latar belakang disetel ke "ON" dan mengaktifkan notifikasi jarak jauh, tetapi masih belum mendapat notifikasi saat notifikasi masuk ke aplikasi dalam mode latar belakang
Swapnil Dhotre
@Bao - Saya pikir ini akan menyebabkan penolakan di Appstore, karena opsi ini pada dasarnya digunakan untuk mengunduh konten yang terkait dengan pemberitahuan di latar belakang. Jadi jika Anda tidak mengunduh konten apa pun, Apple dapat menolak aplikasi Anda. developer.apple.com/library/ios/documentation/iPhone/Conceptual/…
niks
69

Saya telah mencari hal yang sama seperti Anda dan benar-benar menemukan solusi yang tidak memerlukan notifikasi jarak jauh untuk dicentang.

Untuk memeriksa apakah pengguna telah mengetuk, atau aplikasi di latar belakang atau aktif, Anda hanya perlu memeriksa status aplikasi di

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

    }

Untuk info lebih lanjut, periksa:

Referensi Kerangka Kerja UIKit> Referensi Kelas Aplikasi UIA> UIApplicationState

Dennism
sumber
10
Bagaimana dengan aplikasi menjadi UIApplicationStateInactive sebagai hasil dari interaksi pengguna dengan Pusat notifikasi (geser dari atas) atau Pusat kontrol (geser dari bawah) saat aplikasi berada di layar. Rupanya, tidak ada cara untuk mengetahui apakah APNS diterima dalam status Tidak aktif atau pengguna benar-benar mengetuknya.
Kostia Kim
1
@KostiaKim Anda benar, tapi itu kasus super edge ... selain itu, jawaban ini adalah yang paling valid dalam hal memisahkan antara aplikasi di latar depan ... pengguna mengetuk ... aplikasi di latar belakang
Honey
Terima kasih, jenis ini mengungkap segalanya. Ingatlah bahwa agar metode delegasi dipanggil saat aplikasi berada di latar belakang, notifikasi push harus menyertakan content-availablekunci, tetapi kemudian notifikasi tersebut harus senyap (yaitu tidak menyertakan suara atau lencana) seperti yang dinyatakan dalam dokumen resmi .
Nickkk
1
@KostiaKim Saya sebenarnya dapat memperbaiki masalah tidak mengetahui apakah pusat kendali terbuka atau jika pengguna benar-benar mengetuk pemberitahuan dengan menambahkan boolean yang disetel ke true di func applicationDidEnterBackground(_ application: UIApplication)dan salah di func applicationDidBecomeActive(_ application: UIApplication)ini memungkinkan saya untuk menampilkan dalam aplikasi pemberitahuan ketika aplikasi tidak aktif karena pusat kendali atau daftar pemberitahuan
DatForis
3
itu mengejutkan saya mengapa Apple tidak menyajikan acara yang berbeda atau hanya menambahkan bendera di metadata untuk menunjukkan bahwa pengguna benar-benar berinteraksi dengan pemberitahuan tersebut. Harus 'menyimpulkan' apakah pengguna mengambil tindakan berdasarkan informasi ambien tentang status aplikasi cukup tidak masuk akal untuk sedikit informasi penting yang memengaruhi ekspektasi pengguna terhadap perilaku aplikasi. Mungkin satu-satunya yang harus dilakukan adalah membuat tindakan kustom untuk membuka aplikasi dengan informasi tersebut?
Allan Nienhuis
20

Menurut iOS / XCode: bagaimana cara mengetahui bahwa aplikasi telah diluncurkan dengan klik pada notifikasi atau ikon aplikasi springboard? Anda harus memeriksa status aplikasi di didReceiveLocalNotification seperti ini:

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

Meskipun tidak masuk akal bagi saya, ini tampaknya berhasil.

Werner Kratochwil
sumber
1
Itu tidak akan berhasil dalam skenario ini. Saya mencobanya sebelumnya. Ketika kotak centang itu dicentang (lihat jawaban saya yang diterima untuk detailnya), ketika pemberitahuan tiba, baris Anda dengan komentar "// pengguna telah mengetuk pemberitahuan" akan dimasukkan, meskipun pengguna tidak mengetuk pemberitahuan (pemberitahuan baru saja tiba ).
Bao Lei
3
Saya tidak setuju. Saya telah memeriksa "Notifikasi jarak jauh" di kemampuan latar belakang saya dan berfungsi seperti yang dijelaskan dalam jawaban saya. Saya juga telah memeriksa "Pengambilan latar belakang". Mungkinkah itu yang menyebabkan perubahan?
Werner Kratochwil
bisakah Anda memberi jawaban saya +1? ;-) Saya masih membutuhkan beberapa suara untuk berpartisipasi lebih banyak dalam stackoverflow. Terima kasih banyak
Werner Kratochwil
Yupe, ini solusinya. tnx.
Afshin
Perhatikan bahwa ini akan menjadi positif palsu jika notifikasi dikirim saat pengguna berada di layar yang berbeda (misalnya, jika mereka menurunkan bilah status dan kemudian menerima notifikasi dari aplikasi Anda).
Kevin Cooper
16

Jika seseorang menginginkannya di 3.0 cepat

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
    }

untuk cepat 4

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
}
Hamid Shahsavari
sumber
Di pemicu mana kita harus menambahkan kode ini, didReceiveRemoteNotification atau didFinishLaunchingWithOptions?
Dashrath
2
Pada didReceiveRemoteNotification
Hamid Shahsavari
@Hamid sh ,,,, Saya menerima pemberitahuan push di semua negara bagian yaitu ketika aplikasi di forground, background, close (terminated) ..! tetapi masalah saya adalah bagaimana cara menambah jumlah lencana ketika aplikasi dalam keadaan latar belakang dan menutup (menghentikan) keadaan ???? Tolong beritahu saya secara rinci bagaimana saya melakukannya ....? jumlah lencana aplikasi saya hanya meningkat ketika aplikasi dalam keadaan latar belakang .....? jika memungkinkan tolong beritahu saya secara singkat .......!
Kiran jadhav
8

Jika Anda memiliki "Mode Latar Belakang"> "Pemberitahuan jarak jauh" dicentang == YA, ketuk acara pemberitahuan akan tiba dalam:

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

Itu membantu saya. Nikmatilah :)

Aleks Osipov
sumber
Saya melihat bahwa Apple menambahkan ini tetapi tidak tahu bagaimana cara mendapatkan muatan khusus pemberitahuan dengan cara ini.
sudo
Ini adalah fungsi yang dipanggil ketika aplikasi dalam keadaan latar belakang dan menjadi aktif dan juga ketika aplikasi dimulai dari keadaan terbunuh
Nikhil Muskur
@NikhilMuskur hanya jika "notifikasi jarak jauh" diaktifkan ya?
Zorayr
@Zorayr ya itu benar
Nikhil Muskur
8

Saya mengalami masalah ini juga - tetapi di iOS 11 dengan UserNotificationsFramework baru .

Di sini bagi saya seperti ini:

  • Peluncuran Baru: application:didFinishLaunchingWithOptions:
  • Diterima dari keadaan berhenti: application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
  • Diterima di Foreground: userNotificationCenter(_:willPresent:withCompletionHandler:)
  • Diterima di Latar Belakang: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:
pra
sumber
Ini adalah cara untuk melakukannya di iOS 11 +
OhadM
Ini sangat rumit 🤦‍♂️
Zorayr
4

Dalam kasus saya, mode background OFF tidak ada bedanya. Namun, saat aplikasi ditangguhkan dan pengguna mengetuk notifikasi, saya dapat menangani kasus tersebut dalam metode callback ini:

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

}
DoruChidean
sumber
Ini adalah cara resmi yang dikatakan Apple. Menurut dokumen Apple, itu akan dipanggil setiap kali pengguna berinteraksi dengan UI notifikasi push. Jika aplikasi tidak ada di latar belakang, itu akan meluncurkan aplikasi dalam mode latar belakang dan memanggil metode ini.
Ryan
3

Untuk iOS 10 dan di atasnya, letakkan ini di AppDelegate, untuk mengetahui pemberitahuan disadap (berfungsi bahkan aplikasi ditutup atau terbuka)

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
print("notification tapped here")
}
Yatin Arora
sumber
1
Ini adalah jawaban yang benar untuk iOS 10+. Penjelasan lengkap diberikan di utas lain di sini: stackoverflow.com/a/41783666/1761357 .
dead_can_dance
2

Ada dua Fungsi untuk pegangan yang diterima PushNotification di dalam PushNotificationManagerkelas:

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate{

}

Saat saya menguji pemicu pertama segera setelah Pemberitahuan tiba

@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([])

}

Dan yang kedua saat Mengetuk Notifikasi:

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

Saya juga mengujinya dengan status ON dan OFF dari Remote Notification (dalam Mode Latar Belakang)

Saeid
sumber
1

SWIFT 5.1

UIApplication.State tidak berfungsi untuk saya, karena setelah saya membaca sidik jari (modal ditampilkan) di aplikasi saya, notifikasi juga ditampilkan di bilah atas dan pengguna harus mengkliknya.

Saya telah membuat

public static var isNotificationFromApp: Bool = false

masuk AppDelegatedan saya mengaturnya truedi awal saya viewControllerdan kemudian di pemberitahuan saya storyboard/ viewControllersaya hanya memeriksa itu :)

Semoga bisa berguna

Hourglasser
sumber
-7

Anda bisa mengonfigurasi payload push notification untuk memanggil application:didReceiveRemoteNotification:fetchCompletionHandler:metode delegasi aplikasi saat aplikasi berjalan di latar belakang. Anda dapat menyetel beberapa tanda di sini sehingga saat pengguna meluncurkan aplikasi Anda di lain waktu, Anda dapat melakukan operasi Anda.

Dari dokumentasi apple, Anda harus menggunakan metode ini untuk mendownload konten baru yang terkait dengan notifikasi push. Juga agar ini berfungsi, Anda harus mengaktifkan Notifikasi jarak jauh dari mode Latar Belakang dan payload notifikasi push Anda harus berisi content-availablekunci dengan nilainya disetel ke 1. Dari info lebih lanjut silakan lihat bagian Menggunakan Notifikasi Push untuk Memulai Download dari apple doc di sini .

Cara lain adalah memiliki jumlah lencana dalam payload pemberitahuan push. Jadi, saat aplikasi Anda diluncurkan, Anda dapat memeriksa jumlah lencana aplikasi. Jika parutannya lebih dari nol, lakukan operasi Anda dan nol / hapus lencana dari server juga.

Semoga ini bisa membantu Anda.

Ameet Dhas
sumber
@bhusan apakah Anda sudah membaca detail pertanyaan saya? Saya melihat didReceiveRemoteNotification dipanggil saat pemberitahuan baru saja tiba (sebelum pengguna mengetuknya). Saya ingin mengetahui apakah pengguna mengetuknya.
Bao Lei
Anda tidak menjawab pertanyaan OP. Dia tidak hanya ingin tahu kalau sudah ada notifikasi. Dia ingin tahu apakah pengguna membuka Aplikasi dengan mengetuk notifikasi jarak jauh itu.
Joe C