Прослушиватель Firebase, когда приложение работает в фоновом режиме

У меня есть прослушиватель событий Firebase childAdded для таблицы уведомлений в моем приложении, и я хотел бы запускать push-уведомления, когда приложение находится в фоновом режиме.

Вот слушатель:

@objc func observeNotificationsChildAddedBackground() {
    self.notificationsBackgroundHandler = FIREBASE_REF!.child("notifications/\(Defaults.userUID!)")
    self.notificationsBackgroundHandler!.queryOrdered(byChild: "date").queryLimited(toLast: 99).observe(.childAdded, with: { snapshot in
        let newNotificationJSON = snapshot.value as? [String : Any]
        if let newNotificationJSON = newNotificationJSON {
            let status = newNotificationJSON["status"]
            if let status = status as? Int {
                if status == 1 {
                    self.sendPushNotification()
                }
            }
        }
    })
}

func sendPushNotification() {
    let content = UNMutableNotificationContent()
    content.title = "Here is a new notification"
    content.subtitle = "new notification push"
    content.body = "Someone did something which triggered a notification"
    content.sound = UNNotificationSound.default()

    let request = UNNotificationRequest(identifier: "\(self.notificationBackgroundProcessName)", content: content, trigger: nil)
    NotificationCenter.default.post(name: notificationBackgroundProcessName, object: nil)
    UNUserNotificationCenter.current().delegate = self
    UNUserNotificationCenter.current().add(request){ error in
        if error != nil {
            print("error sending a push notification :\(error?.localizedDescription)")
        }
    }
}

Это отлично работает, когда приложение находится на переднем плане. Затем я добавляю фонового наблюдателя в свое приложение, которое делегирует applicationWillResignActive метод для наблюдения за ним в фоновом режиме:

func applicationWillResignActive(_ application: UIApplication) {
     NotificationCenter.default.addObserver(self, selector: #selector(MainNavViewController.observeNotificationsChildAdded), name: notificationBackgroundProcessName, object: nil)
}

Но обозреватель событий не запускается, когда приложение находится в фоновом режиме. Я заглянул в Firebase Cloud Messenger, чтобы решить эту проблему, и наткнулся на такие сообщения:

Можно ли отправлять Push-уведомления, используя Firebase Cloud Messaging (FCM) на специальный UDID прямо с устройства?

однако я не пытаюсь отправить push-уведомление от одного пользователя другому, я пытаюсь активировать UNNotificationRequest из прослушивателя базы данных.

Я также нашел это сообщение: Фоновые уведомления FCM не работают в iOS, но опять же, это отличается от моего варианта использования, потому что он используется в рамках FIRMessaging.

Итак, можно ли запустить этот прослушиватель базы данных, когда приложение работает в фоновом режиме? Если нет, могу ли я заставить Firebase Cloud Messenger отслеживать изменения в таблице и отправлять уведомление?


person Dustin Spengler    schedule 16.01.2017    source источник


Ответы (4)


У меня была такая же проблема, и я наткнулся на ваш пост несколько месяцев назад. Я наконец-то понял, что требуется для наблюдения за уведомлениями в фоновом режиме.

Я подробно описал решение, которое использую, в этом сообщении https://stackoverflow.com/a/42240984/7048719

Техника следующая

  1. использовать собственный класс обслуживания данных
  2. инициализировать sharedInstance класса обслуживания данных
  3. вызвать соответствующую функцию в классе службы данных sharedInstance из исходного контроллера представления.

Таким образом, наблюдатель остается в памяти

Обновление. Apple внедрила обновления в отношении фоновых режимов, которые остановили работу этого метода.

person Abishek Gokal    schedule 26.05.2017
comment
@DustinSpengler Спасибо, надеюсь, это полезно. Имейте в виду использование памяти наблюдателями firebase, но в остальном они уже некоторое время используют эту систему с большим успехом. - person Abishek Gokal; 26.05.2017

У устройств есть собственный способ управления фоновыми сетевыми вызовами, поэтому обработка таких фоновых push-уведомлений не будет работать на реальных устройствах. Наблюдатели удаляются из памяти вскоре после того, как приложение переходит в фоновый режим. Мне удалось решить эту проблему, создав сервер Node.js, который наблюдает за таблицей notifications и обрабатывает push-уведомления с использованием инфраструктуры Firebase-Messenger. На самом деле это было довольно просто. Я использовал это сообщение в блоге в качестве руководства: Отправка уведомлений между устройствами Android с базой данных Firebase и облачными сообщениями

Однако этот метод будет работать в симуляторе (но не на реальных устройствах) до тех пор, пока вы передадите объект, содержащий наблюдателя (в данном случае делегат приложения), вызову фонового потока следующим образом:

func applicationWillResignActive(_ application: UIApplication) {
     NotificationCenter.default.addObserver(self,
                                            selector: #selector(self.observeNotificationsChildAddedBackground),
                                            name: notificationBackgroundProcessName,
                                            object: self)
}
person Dustin Spengler    schedule 31.01.2017
comment
@MikeG, когда я тестировал этот метод на реальном устройстве, наблюдатель удалялся из памяти вскоре после того, как приложение перешло в фоновый режим. Не стесняйтесь проверить себя и поделиться своими результатами - person Dustin Spengler; 28.03.2020

Простым решением было бы использовать фоновую выборку. Вы также можете использовать фоновую выборку для периодической выборки таблицы для новых записей и отображения уведомления при добавлении новой строки.

Это не гарантирует немедленное получение уведомлений. Но реализация намного проще по сравнению с использованием APN.

person 2ank3th    schedule 24.04.2017
comment
Это определенно отличный вариант, на который я смотрел. Лично для меня это не сработало, потому что мне нужно было, чтобы уведомления были активными, а этот метод вызывает периодическую загрузку. - person Dustin Spengler; 25.04.2017

Вы можете добавить фоновую задачу в обозреватель firebase

@objc func observeNotificationsChildAddedBackground() {

      var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid

      backgroundTask = UIApplication.shared.beginBackgroundTask {
           [unowned self] in
           UIApplication.shared.endBackgroundTask(backgroundTask)
           backgroundTask = UIBackgroundTaskInvalid
      }
      assert(backgroundTask != UIBackgroundTaskInvalid)

      self.notificationsBackgroundHandler = FIREBASE_REF!.child("notifications/\(Defaults.userUID!)")

      self.notificationsBackgroundHandler!.queryOrdered(byChild: "date").queryLimited(toLast: 99).observe(.childAdded, with: { snapshot in

           let newNotificationJSON = snapshot.value as? [String : Any]

           if let newNotificationJSON = newNotificationJSON {

                   let status = newNotificationJSON["status"]

                   if let status = status as? Int {

                   if status == 1 {
                      self.sendPushNotification()
                   }
            }
         }
     })
}
person codaman    schedule 15.04.2019