iosswiftapple-push-notifications

Get a push PAYLOAD, after user tap-on-notification, actually in userNotificationCenter?


In your app delegate

import UserNotifications
class AppDelegate: ...  UNUserNotificationCenterDelegate {

If you:

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

    print("notification tapped to open app ....")

    completionHandler()
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
 willPresent notification: UNNotification,
 withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

    print("notification arrived while app in foreground!")

    completionHandler(.alert)
}

When you

and indeed the

then

and

and you will see 'notification tapped to open app ...' on the console.

But in those functions,

how the heck do you get the actual push PAYLOAD?

(That is to say the .data value ...... or indeed any part of the payload. For example, if you're using the excellent github.com/AndrewBarba/apns2 you'd want precisely where it has the example data: { ... )

How the heck do you get the notification (payload) in the UserNotifications delegate functions?!

Again this is when the user ***has actually opened the app, simply by tapping (ie, "slide, open") on a notification.

I am NOT discussing the difficult issue of waking an app in background (say, to download a file etc).

How the heck do you get the payload?


Solution

  • For 2024 we've found the best library to use for APNS is

    https://github.com/parse-community/node-apn

    It works. There's no support, nobody answers on the github issues, but it works fine.

    Be aware that the older https://github.com/node-apn/node-apn is completely broken, (doesn't work at all) and is abandoned, but nobody bothered clicking delete. Every bit of documentation, functionality, syntax etc is identical on the new "@parse" one, there is nothing to do to swap over. If you used the old one which is now broken it's just

    ] npm uninstall apn
    ] npm install @parse/node-apn
    

    and you're done.

    Some random sample code ..

    var apn = require('@parse/node-apn')
    

    ...

    async function sendNotifsSilent() { // silent bg type
    
        for (const aBase64Token of global.known_apns_tokens) {
    
            console.log(`try SILENT APN for ${aBase64Token}`)
    
            var note = new apn.Notification()
            const hours = 8
            note.expiry = Math.floor(Date.now() / 1000) + (hours * 60 * 60)
    
            //note.payload = { 'examplePayloadItem': 'some payload itemn value' }
    
            note.pushType = 'background'
            note.contentAvailable = 1
    
            note.topic = "you.com.yourapp"
            const aTokenData = Buffer.from(aBase64Token, 'base64').toString('hex')
    
            apnProvider.send(note, aTokenData).then((result) => {
                console.log("result apn")
                console.log(result)
                console.log(result.failed)
                console.log(result.failed.response)
            })
    
            apnProvider_sandbox.send(note, aTokenData).then((result) => {
                console.log("result apn sandbox")
                console.log(result)
                console.log(result.failed)
                console.log(result.failed.response)
            })
        }
    }
    

    ...

    async function sendNotifs() { // normal push notification
    
        for (const aBase64Token of global.known_apns_tokens) {
    
            var note = new apn.Notification()
            const hours = 8
            note.expiry = Math.floor(Date.now() / 1000) + (hours * 60 * 60)
            // note.badge = 3
            note.sound = "ping.aiff"
            note.alert = {
                title: "Some News", body: "Something happened."
            }
            // or just note.alert = "string"
    
            note.payload = { 'examplePayloadItem': 'some payload item value' }
    
            note.topic = "you.com.yourapp"
            const aTokenData = Buffer.from(aBase64Token, 'base64').toString('hex')
    
            apnProvider.send(note, aTokenData).then((result) => {
                console.log("result apn")
                console.log(result)
                console.log(result.failed)
                console.log(result.failed.response)
            })
            apnProvider_sandbox.send(note, aTokenData).then((result) => {
                console.log("result apn sandbox")
                console.log(result)
                console.log(result.failed)
                console.log(result.failed.response)
            })
        }
    }
    

    setup

    const p8key = `-----BEGIN PRIVATE KEY-----
    MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkw666666666666666666666666
    H2auA793mqBtW6EnOHyYdzssduKgCgYIKoZIzj0D666666666666666666666666
    ZTY3g/tduKhcWUvVTvAQyItLaKqHmE5bMmDjhQ7t666666666666666666666666
    ExQwdo3d
    -----END PRIVATE KEY-----`
    var apn_options = {
        token: {
            key: p8key,
            keyId: "PL7aKVBLAH",
            teamId: "EGW16TBLAH"
        },
        production: true
    }
    var apn_options_sandbox = {
        token: {
            key: p8key,
            keyId: "PL7aKVBLAH",
            teamId: "EGW16TBLAH"
        },
        production: false
    }
    
    var apnProvider = new apn.Provider(apn_options)
    var apnProvider_sandbox = new apn.Provider(apn_options_sandbox)
    

    Older option ...

    Answer kindly provided by the crew at npm-apns2

    (Library currently has a bug .. setting .topic is broken!)

    For data like

    let bn = new BasicNotification(deviceToken, 'Teste', {
      data: {
        name: 'jack',
        street: 'jones'
      } })
    

    so ...

    func userNotificationCenter(_ center: UNUserNotificationCenter,
     didReceive response: UNNotificationResponse,
     withCompletionHandler completionHandler:
      @escaping () -> Void) {
        print("notification tapped, app opens")
        let userInfo = response.notification.request.content.userInfo
        
        let name: String? = userInfo["name"] as! String?
        let street: String? = userInfo["street"] as! String?
        let test3: String? = userInfo["typo"] as! String?
        print("> \(name)")      // optional 'jack'
        print("> \(street)")    // optional 'jones'
        print("> \(test3)")     // nil
        
        completionHandler()
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter,
     willPresent notification: UNNotification,
     withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        print("notification arrived while app in foreground (user has
                not 'tapped on notification' - you get this immediately)")
        
        let userInfo = notification.request.content.userInfo     // sic
        
        let name: String? = userInfo["name"] as! String?
        let street: String? = userInfo["street"] as! String?
        let test3: String? = userInfo["typo"] as! String?
        print("> \(name)")      // optional 'jack'
        print("> \(street)")    // optional 'main'
        print("> \(test3)")     // nil
        
        completionHandler(.alert)
    }
    

    and that's it.