3

I have been trying to use a Firebase listener to trigger local notifications. I have found a post that addresses exactly what I am trying to do with much of it explained, however I do not have the reputation to comment on the post and there seems to be no indication of how to accomplish what I want anywhere else.

The original poster says this.

I figured it out! I had to use a different approach but i was able to get my Firebase Database observer to trigger notifications in the background.

As long as the object containting the database observer is not deallocated from memory it will continue to observe and trigger. So I created a global class which contains a static database object property like this:

class GlobalDatabaseDelegate {
static let dataBase = DataBase()
 }

This is where I am confused as to what to do for my own project. It is my understanding that I have to create a class similar to DataBase() which contains my database reference. The problem is I do not understand how to create class object that will contain the database listener.

say for example my reference is :

let userRef = FIRDatabase.database.reference().child("users")

And I want to observe any users added to the database and then trigger a local notification. I am able to write the code to do so, just not sure how to contain it in an object class of its own and then make it static.

Forgive me for being a little slow. Any help would be very much appreciated.

The rest of the post follows :

I also extended the DataBase class to be the UNUserNotificationCenterDelegate so it can send the push notitications like this:

    extension DataBase: UNUserNotificationCenterDelegate {

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

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        print("Notification being triggered")
        completionHandler( [.alert,.sound,.badge])
    }

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

In essence I am trying to keep a firebase listener in memory when the app is in background.

Community
  • 1
  • 1
Abishek Gokal
  • 186
  • 2
  • 13

1 Answers1

3

So the original post that I have linked in has the answer but it is a matter of understanding it. I have also implemented my code in a slightly different approach.

I found another post detailing the technique needed to run a custom data service class. Custom Firebase Data Service Class : Swift 3

To set keep the firebase listener in memory there are few steps.

1.Create a firebase data service class. In that class I have a static variable that is of the same class

class FirebaseAPI {
    var isOpen = false

static let sharedInstance = FirebaseAPI()

//  I added functions for firebase reference in this class

func observeNotifications(){

//firebase call here
 }

}

2.Set up notification settings in app delegate. This is where my set up differs from the original post.

 let notificationSettings = UIUserNotificationSettings(types: [.badge, .alert, .sound], categories: nil)
    UIApplication.shared.registerUserNotificationSettings(notificationSettings)

3.Create a reference to the firebase class in a viewcontroller of your choice, it works in app delegate but not advisable.

let sharedInstance = FirebaseAPI.sharedInstance

4.Call functions to setup observer

self.sharedInstance.observeNotifications()

You can then trigger fire a local notification using a completion handler with the function or fire off notifications within the firebase function.

Update: Apple have implemented updates in regards to background modes which have stopped this method from working . Currently the only method is to use APNS

Abishek Gokal
  • 186
  • 2
  • 13
  • this does not keep the listener in memory – Sente Sep 16 '17 at 02:32
  • @Sente apologies there have been updates by Apple which have stopped this working , I ran into the same problem a couple of days ago . I have now updated the post to reflect that it is no longer working . – Abishek Gokal Sep 16 '17 at 02:40
  • it was worth a shot. I'm just going to have to learn to use Firebase push notifications – Sente Sep 16 '17 at 03:30
  • @Sente https://firebase.google.com/docs/functions/use-cases#notify_users_when_something_interesting_happens seems to be a good place to start. There is working demo code available. – Abishek Gokal Sep 16 '17 at 04:00