Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get data from push notification response Swift 3/iOS

I am using the following library to generate push notifications.

https://github.com/edamov/pushok

I got the push notifications working but I don't know how to extract the response in Swift 3.

Here is what I have.

// Push notification received
    func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
        // Print notification payload data
        print("Push notification received: \(data)")

        let aps = data[AnyHashable("aps")]!

        print(aps)
    }

I can create the push notifications and the console message works but prints out this...

Push notification received: [AnyHashable("samplekey"): samplevalue, AnyHashable("aps"): {
    alert =     {
        body = hey;
        title = "Hello!";
    };
    sound = default;
}]
{
    alert =     {
        body = hey;
        title = "Hello!";
    };
    sound = default;
}

So my question is how do I access the data inside of alert for the 'body' and 'title'?

I tried accessing the variables but I keep getting errors because I'm not sure how I'm supposed to access it and could not find any documentation on this subject in any tutorials.

like image 612
Joseph Astrahan Avatar asked Mar 23 '17 20:03

Joseph Astrahan


4 Answers

Okay I found out the answer. You do it like below.

let aps = data[AnyHashable("aps")]! as! NSDictionary        
let alert = aps["alert"]! as! NSDictionary
let body = alert["body"] as! String
let title = alert["title"] as! String

If someone has a more safe answer I'd appreciate them editing this or posting it.

like image 147
Joseph Astrahan Avatar answered Nov 15 '22 23:11

Joseph Astrahan


I think this is a safer way to do the way Joseph found.

guard
    let aps = data[AnyHashable("aps")] as? NSDictionary,
    let alert = aps["alert"] as? NSDictionary,
    let body = alert["body"] as? String,
    let title = alert["title"] as? String
    else {
        // handle any error here
        return
    }

print("Title: \(title) \nBody:\(body)")
like image 43
ffabri Avatar answered Nov 16 '22 00:11

ffabri


I would eager you to try to find a way to avoid using force unwrapping. When you do to the following:

 let alert = aps["alert"]! as! NSDictionary
 let body = alert["body"] as! String
 let title = alert["title"] as! String

the application will crash, when any of the above values are missing.

Instead, first lets introduce a notification model.

class MTNotification {
    let alert: [String: AnyHashable]
    var title: String?
    var body: String?

    init(alert: [String: AnyHashable]) {
        self.alert = alert
    }
}

Use something to track the errors what could occur while handling the raw notification data. The better if you make it conform to the Error protocol.

enum MTError: Error {
    // Observe your transformation and extend error cases
    case missingProperty(id: String)
}

Use a helper class not to pollute the app delegate, where you can handle the transformation of the data to notifications.

class MTNotificationBuilder {

     /// Build a notification from raw data
     ///
     /// - Parameter data: Classic notification payload, received from app delegate
     /// - Returns: customized MTNotification
     /// - Throws: error while building a valid MTNotification object
    static func build(from data: [AnyHashable : Any]) throws -> MTNotification {
        guard let aps = data["aps"] as? [String: AnyHashable] else {
            // Do some error handlig
            throw MTError.missingProperty(id: "aps")
        }

        guard let alert = aps["alert"] as? [String: AnyHashable] else {
            // Do some error handlig
            throw MTError.missingProperty(id: "aps")
        }

        let notification = MTNotification(alert: alert)
        // Assign values read as optionals from alert dictionary
        notification.title = alert["title"] as? String
        notification.body = alert["body"] as? String

        return notification
    } 
}

And all you need to do at the end is to call the builder function and see the result. You can be strict and introduce errors for any of the cases, also using will help maintainability later.

func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {

    do {
        let notification = try MTNotificationBuilder.build(from: data)
        print(notification.alert)
    } catch let error {
        print(error)
    }
}
like image 39
dirtydanee Avatar answered Nov 16 '22 00:11

dirtydanee


Make sure you turned 'ON' Background Modes in Project 'capabilities' and checked 'Remote Notifications'. Add following method in AppDelegate class. This method will call at the time of presenting notification.

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        print(notification.request.content.userInfo)
        completionHandler([ .alert,.badge, .sound])

}
like image 38
Pranit Avatar answered Nov 15 '22 22:11

Pranit