Mendeteksi jika aplikasi diluncurkan / dibuka dari pemberitahuan push

172

Apakah mungkin untuk mengetahui apakah aplikasi diluncurkan / dibuka dari pemberitahuan push?

Saya kira acara peluncuran dapat ditangkap di sini:

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

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

    }
}

Namun, bagaimana saya bisa mendeteksi itu dibuka dari pemberitahuan push ketika aplikasi di latar belakang?

joao
sumber
6
Ini adalah pos lama, tetapi sangat bermanfaat. Sayangnya jawaban teratas tidak menyelesaikan masalah yang sebenarnya (seperti yang ditunjukkan oleh komentar). Harap pertimbangkan menandai jawaban baru sebagai 'diterima' karena jawaban saat ini tidak lengkap.
MobileVet
1
Pertanyaan ini memiliki 100k + tampilan tetapi jawaban yang dipilih salah atau lengkap. Untuk pengunjung, pertimbangkan untuk menyortir berdasarkan Aktif alih-alih dengan Memilih untuk menemukan solusi modern.
Albert Renshaw

Jawaban:

187

Lihat kode ini:

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

sama dengan

-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification
shanegao
sumber
19
@ManuelM. Ini adalah jawaban yang bagus karena menunjukkan cara mendeteksi ketika aplikasi di latar belakang dibawa ke latar depan dari pemberitahuan push. Karena ketika aplikasi tidak berjalan, Anda memerlukan jawaban M.Othman di bawah ini.
OpenUserX03
6
Saya mendapatkan panggilan ke aplikasi: didReceiveRemoteNotification: setelah mengetuk pemberitahuan terlepas dari apakah aplikasi tersebut hanya di latar belakang atau tidak berjalan sama sekali sehingga jawaban ini sesuai dengan kebutuhan saya dengan sempurna. Diuji pada iOS 7 & 8
Newtz
16
Seperti yang ditunjukkan beberapa orang lainnya, ini tidak mendeteksi "diluncurkan / dibuka dari pemberitahuan push". Ini disebut ketika notifikasi diterima, bukan ketika notifikasi dibuka. Jadi jika Anda menerima pemberitahuan di bg tetapi mengetuk ikon aplikasi untuk membuka aplikasi, kode yang Anda miliki di sini masih akan berjalan, dan Anda mungkin membuka halaman yang tidak ingin dibuka oleh pengguna.
Bao Lei
4
@ManuelM. metode ini tidak memberi tahu apakah aplikasi dibuka melalui pusat notifikasi vs ikon aplikasi jika mode latar belakang - notifikasi jarak jauh dicentang. Itu terjadi ketika tidak dicentang. Saya telah mendokumentasikan perbedaan dalam posting ini: stackoverflow.com/questions/32061897/…
Bao Lei
2
Dikonfirmasi bahwa ini berfungsi dengan Google Cloud Messaging.
CularBytes
127

terlambat tapi mungkin bermanfaat

Saat aplikasi tidak berjalan

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

disebut ..

di mana Anda perlu memeriksa pemberitahuan push

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
sumber
2
Perhatikan bahwa dalam cuplikan di atas, pemberitahuan tidak boleh dinyatakan sebagai (UILocalNotification *) tetapi (NSDictionary *)
cosmix
1
Dengan cara ini Anda dapat melihat apakah ada pemberitahuan untuk aplikasi, saat tidak berjalan! Pertanyaannya adalah, bagaimana cara mendeteksi apakah aplikasi dibuka dari notifikasi. Dalam hal ini didReceiveRemoteNotification disebut, bahkan jika aplikasi tidak berjalan sama sekali. - Saya suka jawaban Anda, karena itu cukup penting untuk banyak kasus, tetapi bukan jawaban yang benar untuk pertanyaan itu.
Axel Zehden
Apakah jawaban Anda dan jawaban ini sama-sama melakukan hal yang sama?
Sayang
38

Masalah yang kami miliki adalah memperbarui tampilan dengan benar setelah aplikasi diluncurkan. Ada urutan rumit dari metode siklus hidup di sini yang membingungkan.

Metode Siklus Hidup

Pengujian kami untuk iOS 10 mengungkapkan urutan metode siklus hidup berikut untuk berbagai kasus:

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

Masalah

Ok, jadi sekarang kita perlu:

  1. Tentukan apakah pengguna membuka aplikasi dari dorongan
  2. Perbarui tampilan berdasarkan pada kondisi push
  3. Kosongkan status sehingga pembukaan berikutnya tidak mengembalikan pengguna ke posisi yang sama.

Yang sulit adalah bahwa memperbarui tampilan harus terjadi ketika aplikasi benar-benar menjadi aktif, yang merupakan metode siklus hidup yang sama dalam semua kasus.

Sketsa solusi kami

Berikut adalah komponen utama dari solusi kami:

  1. Simpan notificationUserInfovariabel instan pada AppDelegate.
  2. Atur notificationUserInfo = nilkeduanya applicationWillEnterForegrounddan didFinishLaunchingWithOptions.
  3. Set notificationUserInfo = userInfoindidReceiveRemoteNotification:inactive
  4. Dari applicationDidBecomeActiveselalu memanggil metode khusus openViewFromNotificationdan lulus self.notificationUserInfo. Jika self.notificationUserInfonihil maka kembali lebih awal, jika tidak buka buka berdasarkan status notifikasi yang ditemukan di self.notificationUserInfo.

Penjelasan

Saat membuka dari push didFinishLaunchingWithOptionsatau applicationWillEnterForegroundselalu dipanggil segera sebelumnya didReceiveRemoteNotification:inactive, jadi kami atur ulang notificationUserInfo dalam metode ini sehingga tidak ada status basi. Kemudian, jika didReceiveRemoteNotification:inactivedipanggil, kami tahu kami membuka dari sebuah push jadi kami mengatur self.notificationUserInfoyang kemudian diambil oleh applicationDidBecomeActiveuntuk meneruskan pengguna ke tampilan yang benar.

Ada satu kasus terakhir yaitu jika pengguna membuka aplikasi di dalam pengalih aplikasi (yaitu dengan mengetuk dua kali tombol beranda saat aplikasi berada di latar depan) dan kemudian menerima pemberitahuan push. Dalam hal ini hanya didReceiveRemoteNotification:inactivedipanggil, dan baik WillEnterForeground maupun didFinishLaunching tidak dipanggil sehingga Anda memerlukan kondisi khusus untuk menangani kasus itu.

Semoga ini membantu.

Eric Conner
sumber
Akhirnya sesuatu berhasil, terima kasih! Saya ingin membuat bendera "appResuming" dan membuka layar dalam receivemetode ketika keadaan aplikasi aktif atau aplikasi melanjutkan. Itu bisa menyebabkan masalah dengan mengubah VC ketika aplikasi masih tidak aktif. Solusi Anda tampak hebat, sampai Apple mengubah siklus hidup lagi.
shelll
Bagaimana dengan iOS 9, apakah metode siklus hidup disebut dengan cara dan urutan yang sama? Saya sudah tidak memiliki perangkat iOS 9 sehingga saya tidak dapat menguji ini dengan benar.
shelll
2
Ada dua lagi kasus tepi kecuali pengalih aplikasi. 1) Ketika pusat notifikasi ditarik dari atas dan overlay aplikasi 2) Ketika panel iOS dengan wifi / BT / dll ditarik dari bawah dan overlay aplikasi. Dalam ketiga kasus hanya applicationWillResignActivedipanggil dan kemudian applicationDidBecomeActive. Jadi setelah applicationWillResignActivedipanggil jangan simpan notifikasi yang diterima sampai applicationDidEnterBackgroundatau applicationDidBecomeActivedipanggil.
shelll
Terima kasih telah menambahkan case ini @shelll. Itu selalu menjadi lebih rumit! Saya tidak yakin tentang iOS9. Saya pikir mungkin aman untuk menganggap mereka sama, tetapi siapa yang tahu.
Eric Conner
Hanya kepala. Saya menguji iOS 11 Beta 9 hari ini dan menemukan bahwa dalam kasus di mana Anda memiliki aplikasi di latar depan, mengunci ponsel, dan kemudian memilih pemberitahuan push dari layar kunci, ia memanggil didReceiveRemoteNotification: latar belakang sebelum memanggil applicationWillEnterForeground daripada apa yang kita lihat di iOS 10 di mana ia memanggil applicationWillEnterForeground dan kemudian didReceiveRemoteNotification: tidak aktif - jadi ini adalah kasus tepi yang belum dibahas. Menurut pendapat saya ini adalah bug dalam kode iOS, tetapi mengingat seberapa dekat rilis iOS 11, itu adalah sesuatu yang harus diperhatikan.
Roy
24

Ini adalah posting yang sudah usang ... tetapi masih belum ada solusi aktual untuk masalah ini (seperti yang ditunjukkan dalam berbagai komentar).

Pertanyaan aslinya adalah tentang mendeteksi kapan aplikasi diluncurkan / dibuka dari pemberitahuan push, misalnya pengguna mengetuk pemberitahuan tersebut. Tidak ada jawaban yang benar-benar membahas kasus ini.

Alasannya dapat dilihat dalam aliran panggilan ketika pemberitahuan tiba, application:didReceiveRemoteNotification...

dipanggil saat pemberitahuan diterima DAN lagi ketika pemberitahuan diketuk oleh pengguna. Karena itu, Anda tidak dapat mengetahui hanya dengan melihat UIApplicationStateapakah pengguna mengetuknya.

Selain itu, Anda tidak perlu lagi menangani situasi 'permulaan yang dingin' dari aplikasi application:didFinishLaunchingWithOptions...seperti application:didReceiveRemoteNotification...yang dipanggil lagi setelah diluncurkan di iOS 9+ (mungkin 8 juga).

Jadi, bagaimana Anda bisa tahu jika pengguna mengetuk rantai kejadian? Solusi saya adalah dengan menandai waktu di mana aplikasi mulai keluar dari latar belakang atau mulai dingin dan kemudian memeriksa waktu masuk application:didReceiveRemoteNotification.... Jika kurang dari 0,1, maka Anda dapat yakin keran memicu startup.

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

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

Saya telah menguji ini untuk kedua kasus (aplikasi di latar belakang, aplikasi tidak berjalan) di iOS 9+ dan itu berfungsi seperti pesona. 0,1s juga cukup konservatif, nilai sebenarnya adalah ~ 0,002s jadi 0,01 juga baik-baik saja.

MobileVet
sumber
1
Tampaknya ini adalah satu-satunya solusi yang berfungsi yang membedakan antara benar-benar mengetuk notifikasi, dan membuka bilah status di aplikasi.
liviucmg
4
Ini adalah satu-satunya solusi yang berfungsi dari semua StackOverflow. Satu-satunya hal yang ingin saya tambahkan, adalah ketika Anda mendukung iOS 10 dan lebih tinggi, Anda cukup menggunakan UNNotificationCenterAPI, khususnya metode UNNotificationCenterDelegate. userNotificationCenter(UNUserNotificationCenter, didReceive: UNNotificationResponse, withCompletionHandler: @escaping () -> Void) Metode panggilan API itu hanya bila pengguna benar-benar mengetuk notifikasi.
DenHeadless
bagaimana cara mencari swift 3?
Jochen Österreicher
Solusi tidak berfungsi saat aplikasi dalam keadaan tidak aktif (pengguna menggesek pusat notifikasi atau menggesek pusat kontrol) dan menerima pemberitahuan. Ketika pengguna mengetuk pemberitahuan, aplikasi tidak menerima applicationWillEnterForeground panggilan, sebagai hasilnya, solusi gagal mendeteksi keran.
DevGansta
@DevGansta Ketika Anda menambahkan kelas Anda seperti UNUserNotificationCenter.current().delegatepada application:didFinishLaunchingWithOptions, aplikasi akan memanggil userNotificationCenter(didReceive response)setelah keran dalam kasus yang Anda jelaskan
Dorian Roy
22

Saat aplikasi dihentikan, dan pengguna mengetuk notifikasi push

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

Ketika aplikasi di latar belakang, dan pengguna mengetuk pemberitahuan push

Jika pengguna membuka aplikasi Anda dari peringatan yang ditampilkan sistem, sistem dapat memanggil metode ini lagi ketika aplikasi Anda akan memasuki latar depan sehingga Anda dapat memperbarui antarmuka pengguna Anda dan menampilkan informasi yang berkaitan dengan notifikasi.

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

Bergantung pada aplikasi Anda, itu juga dapat mengirimkan Anda dorongan diam-diam dengan content-availabledi dalam aps, jadi waspadai hal ini juga :) Lihat https://stackoverflow.com/a/33778990/1418457

onmyway133
sumber
2
Hanya jawaban yang tidak terasa seperti hack kotor dan benar. Apa yang saya lewatkan adalah jika aplikasi di latar belakang dan pengguna membukanya secara manual, bagaimana cara memeriksanya? Sementara masih bisa memeriksa mulai dingin push dan mendorong dari latar belakang.
Jochen Österreicher
1
@ JochenÖsterreicher Hai, saya rangkum di sini, silakan periksa medium.com/@onmyway133/…
onmyway133
19

Swift 2.0 Untuk Status 'Tidak Berjalan' (Pemberitahuan Lokal & Jarak Jauh)

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
sumber
15

Di application:didReceiveRemoteNotification:cek apakah Anda telah menerima pemberitahuan ketika aplikasi Anda di latar depan atau latar belakang.

Jika diterima di latar belakang, luncurkan aplikasi dari notifikasi.

-(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
sumber
3
Perhatikan bahwa "Aplikasi dibuka dari Pemberitahuan" akan menjadi false positive jika pemberitahuan dikirim saat pengguna berada di layar yang berbeda (misalnya, jika mereka menurunkan bilah status dan kemudian menerima pemberitahuan dari aplikasi Anda).
Kevin Cooper
4
@Kevin Tepat. Itu membuat Anda bertanya-tanya mengapa apel tampaknya magang untuk merancang proses penanganan pemberitahuan ...
Andreas
bagaimana kita bisa mendeteksi jika kita mengetuk notifikasi yang diterima dalam keadaan aktif
Mayank Jain
13

Untuk cepat:

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

    }

}
LondonBeli
sumber
4

Ya, Anda dapat mendeteksi dengan metode ini di appDelegate :

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

Untuk Pemberitahuan lokal:

- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
{
         /* your Code*/
}
Mustahil
sumber
1
Metode ini tidak dipanggil jika aplikasi tidak berjalan. Itulah yang ditanyakan di sini
Pfitz
Masalah saya bukan menangani notifikasi, melainkan mengetahui apakah itu dibuka ketika Anda mengklik banner (ketika aplikasi di latar belakang).
joao
3

jika seseorang menginginkan jawabannya dengan cepat 3

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
sumber
tetapi bagaimana cara mengetahui apakah aplikasi dibuka dengan mengetuk notifikasi push ketika aplikasi diakhiri
user3804063
1
ketika seseorang mengetuk push, aplikasi akan terbuka, tidak peduli itu dihentikan atau tidak. dan kasus tidak aktif sedang memanggil
Hamid Shahsavari
1
saya perlu mendeteksi jika aplikasi dibuka dengan menekan tombol dan ingin menavigasi ke konten masing-masing saya melihat instagram melakukan itu
user3804063
Bagaimana dengan notifikasi lokal?
Amir Shabani
3

Posting ini untuk pengguna Xamarin.

Kunci untuk mendeteksi apakah aplikasi diluncurkan melalui pemberitahuan push adalah AppDelegate.FinishedLaunching(UIApplication app, NSDictionary options)metode, dan kamus opsi yang diteruskan.

The pilihan kamus akan memiliki kunci ini di dalamnya jika pemberitahuan lokal: UIApplication.LaunchOptionsLocalNotificationKey.

Jika itu notifikasi jarak jauh, itu akan menjadi UIApplication.LaunchOptionsRemoteNotificationKey.

Ketika kuncinya adalah LaunchOptionsLocalNotificationKey, objeknya bertipe UILocalNotification. Anda kemudian dapat melihat notifikasi dan menentukan notifikasi spesifik yang mana.

Pro-tip: UILocalNotificationtidak memiliki pengenal di dalamnya, seperti UNNotificationRequesthalnya. Masukkan kunci kamus di UserInfo yang berisi requestId sehingga saat menguji UILocalNotification, Anda akan memiliki requestId khusus yang tersedia untuk mendasarkan beberapa logika.

Saya menemukan bahwa bahkan pada iOS 10 + perangkat yang saat membuat pemberitahuan lokasi menggunakan UNUserNotificationCenter's AddNotificationRequest& UNMutableNotificationContent, bahwa ketika aplikasi tidak berjalan (saya membunuh itu), dan diluncurkan dengan menekan pemberitahuan di pusat pemberitahuan, bahwa kamus masih mengandung yang UILocalNotificaitonobjek.

Ini berarti bahwa kode saya yang memeriksa peluncuran berbasis pemberitahuan akan berfungsi pada perangkat iOS8 dan iOS 10+

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;
}
Wes
sumber
2

Langsung dari dokumentasi untuk

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

Jika aplikasi sedang berjalan dan menerima notifikasi jarak jauh, aplikasi memanggil metode ini untuk memproses notifikasi.

Implementasi Anda terhadap metode ini harus menggunakan notifikasi untuk mengambil tindakan yang sesuai.

Dan sedikit kemudian

Jika aplikasi tidak berjalan ketika pemberitahuan push tiba, metode meluncurkan aplikasi dan memberikan informasi yang sesuai dalam kamus opsi peluncuran.

Aplikasi tidak memanggil metode ini untuk menangani pemberitahuan push itu.

Sebaliknya, implementasi Anda terhadap

application:willFinishLaunchingWithOptions:

atau

application:didFinishLaunchingWithOptions:

metode perlu mendapatkan data payload pemberitahuan push dan merespons dengan tepat.

Pfitz
sumber
2

Saya akan mulai dengan bagan status yang saya buat untuk penggunaan saya sendiri untuk memvisualisasikannya dengan lebih akurat dan untuk mempertimbangkan semua status lainnya: https://docs.google.com/spreadsheets/d/e/2PACX-1vSdKOgo_F1TZwGJBAED4C_7cml0bEATqeL3P9UK9MzUdAgAcU ? gid = 0 & single = true

Dengan menggunakan bagan ini, kita dapat melihat apa yang sebenarnya diperlukan untuk mengembangkan sistem penanganan notifikasi yang kuat yang bekerja di hampir semua kasus penggunaan yang mungkin.

Solusi lengkap ↓

  • Simpan notifikasi muatan di didReceiveRemoteNotification
  • Hapus notifikasi tersimpan di applicationWillEnterForeground dan didFinishLaunchingWithOptions
  • Untuk mengatasi kasus di mana pusat kontrol / pusat pemberitahuan menarik, Anda dapat menggunakan flag willResignActiveCalled dan mengaturnya menjadi false pada awalnya, Setel ini ke true dalam metode applicationWillResignActive ,
  • Dalam metode didReceiveRemoteNotification , simpan pemberitahuan (userInfo) hanya ketika willResignActiveCalled salah.
  • Reset willResignActiveCalled ke false di applicationDidEnterBackground dan metode applicationDidBecomeActive .

Catatan: Jawaban yang serupa disarankan dalam komentar pada jawaban Eric, namun lembar negara membantu dalam menemukan semua skenario yang mungkin seperti yang saya lakukan di aplikasi saya.

Silakan temukan kode lengkap di bawah ini dan beri komentar di bawah ini jika ada kasus khusus yang tidak ditangani:

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 : Di sinilah Anda dapat menulis semua kode Anda untuk bernavigasi ke berbagai bagian aplikasi, menangani Database (CoreData / Realm) dan melakukan semua hal lain yang perlu dilakukan ketika pemberitahuan diterima.

   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
sumber
lebih baik meletakkan ini sebagai komentar karena ini bukan jawabannya.
Maddy
@Maddy Terima kasih atas sarannya, Memperbarui jawabannya dengan semua detail
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)
        }
    }
}
Hardik Bar
sumber
1

Hanya ada satu cara yang dapat diandalkan, dan hanya berfungsi untuk iOS 10+ :

Menggunakan metode UNUserNotificationCenterimplement 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
    }
    ...
}
Luten
sumber
0

Kamu bisa memakai:

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

untuk menangani notifikasi push jarak jauh.

Periksa dokumentasi di sini

sunkehappy
sumber
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
sumber
Tetapi bagaimana jika aplikasi ditutup (dihentikan). Seperti Twitter atau Instagram, entah bagaimana ia mendeteksi dan jika aplikasi bahkan ditutup itu mengarahkan Anda ke pos baru atau gambar atau profil Anda dll.
Tarvo Mäesepp
0

Masalah dengan pertanyaan ini adalah bahwa "pembukaan" aplikasi tidak didefinisikan dengan baik. Suatu aplikasi diluncurkan dengan dingin dari keadaan tidak berjalan, atau diaktifkan kembali dari keadaan tidak aktif (misalnya dari beralih kembali ke itu dari aplikasi lain). Inilah solusi saya untuk membedakan semua kemungkinan keadaan ini:

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

Dan MXDefaultshanya sedikit pembungkus NSUserDefaults.

Skensell
sumber
0

Untuk 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
sumber
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
sumber
0

Untuk iOS 10+, Anda dapat menggunakan metode ini untuk mengetahui kapan notifikasi Anda diklik terlepas dari keadaan aplikasi.

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

    //Notification clicked
    completionHandler()
}
manishsharma93
sumber
0

Jawaban M.Othman benar untuk aplikasi yang tidak mengandung delegasi adegan Untuk Aplikasi Delegasi Scene Ini berfungsi untuk saya di iOS 13

Berikut adalah kode untuk yang harus dituliskan akan menghubungkan adegan

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

Kode untuk delegasi aplikasi untuk mendukung versi sebelumnya didFinishLaunchingWithOptions

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

            //Launched from push notification
        } else {

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

Untuk Pengguna Swift:

Jika Anda ingin meluncurkan halaman berbeda pada pembukaan dari push atau sesuatu seperti itu, Anda perlu memeriksanya didFinishLaunchingWithOptionsseperti:

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
sumber
Delegate tidak memiliki anggota navigationController
Pablo Cegarra
1
Buat pengontrol navigasi dalam file AppDelegate.h. Saya menggunakannya dan berfungsi!
AAA
-1

DALAM SWIFT:

Saya menjalankan Pemberitahuan Push (dengan pengambilan latar belakang). Ketika aplikasi saya di latar belakang dan saya menerima pemberitahuan push, saya menemukan bahwa didReceiveRemoteNotification di appDelegate akan dipanggil dua kali; satu kali ketika notifikasi diterima dan lainnya ketika pengguna mengklik pada notifikasi notifikasi.

Untuk mendeteksi jika pemberitahuan notifikasi diklik, cukup periksa apakah nilai mentah applicationState == 1 di dalam didReceiveRemoteNotification di appDelegate.

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

Saya harap ini membantu.

Johnny5
sumber
-1

Ketika aplikasi di latar belakang sebagai shanegao dapat Anda gunakan

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

Tetapi jika Anda ingin meluncurkan aplikasi dan ketika aplikasi ditutup dan Anda ingin men-debug aplikasi Anda, Anda dapat pergi ke Edit Skema dan di menu kiri pilih Jalankan dan kemudian dalam peluncuran pilih Tunggu untuk dieksekusi akan diluncurkan dan kemudian Anda meluncurkan aplikasi ketika Anda klik pemberitahuan push

Edit Skema> Jalankan> Tunggu untuk dieksekusi akan diluncurkan

salmancs43
sumber