简体   繁体   中英

iOS not receiving background push notification using apn nodejs

My device is not receiving background push notifications. I'm at wits end, I've tried every tutorial I can find and searched through Stack Overflow.

  • Device and APN are set to debug/development
  • I can successfully register device token
  • I have an active .p8 key with push notification services
  • APN says the push message was sent successfully
  • didReceiveRemoteNotification doesn't fire
  • Tried with app in background and foreground
  • using AWS: inbound - port 22, outbound - all ports

This is the response:

{"sent":[{"device":"cc7ec9a821cf232f9510193ca3ffe7d13dd756351794df3f3e44f9112c037c2a"}],"failed":[]}

Here is my code:

AppDelegate.swift

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        if #available(iOS 10, *) {
            let center  = UNUserNotificationCenter.current()
            center.delegate = self
            center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
                if error == nil {
                  UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {            
        var deviceTokenString: String = ""
        for i in 0..<deviceToken.count {
            deviceTokenString += String(format: "%02.2hhx", deviceToken[i] as CVarArg)
        }
        UserDefaults.standard.set(deviceTokenString, forKey: "push_token")
    }


    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter,  willPresent notification: UNNotification, withCompletionHandler   completionHandler: @escaping (_ options:   UNNotificationPresentationOptions) -> Void) {
        print("Handle push from foreground")
        print("\(notification.request.content.userInfo)")
        completionHandler([.alert, .badge, .sound])
    }

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print("Handle push from background or closed")
        // if you set a member variable in didReceiveRemoteNotification, you  will know if this is from closed or background
        print("\(response.notification.request.content.userInfo)")
        completionHandler()
    }
}

XCode:

在此输入图像描述 在此输入图像描述

Node.js

.p8 key is from Developer Console: Keys > All

var apn = require('apn');

var apnProvider = new apn.Provider({
    token: {
        key: "/path/to/AuthKey_1234ABCD.p8",
        keyId: "1234ABCD",
        teamId: "1234ABCD"
    },
    production: false
});

var note = new apn.Notification();
note.topic = "com.company.app";
note.payload = {
    aps: {
        "content-available" : 1
    },
    custom_field: {}
};

apnProvider.send(note, push_token).then(result => {
            console.log('result: ', result);
            console.log("sent:", result.sent.length);
            console.log("failed:", result.failed.length);
});

I appreciate everyone's input, I figured out the issue.

'aps' does not belong in the payload field, but instead should be in the Notification constructor.

Node.js:

var note = new apn.Notification({
    aps: {
        "content-available" : 1
    }
});

note.payload = {
    custom_field_1: {},
    custom_field_2: ''
};

I'm not sure if this is the case as your server is using this APN node module and I never used it, but I use Firebase and everytime I tried using content_available : 1 , it didn't work. What did work was content_available : true .

Hope this works for you.

You wrote this on your AppDelegate

 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("Silent push notification received: \\(userInfo)") } 

But then you also wrote:

 center.delegate = notificationDelegate 

which means you're AppDelegate isn't the notificationCenter's delegate.

either change that to

 center.delegate = self 

Or just remove that function to the class that adopts it ie your UYLNotificationDelegate

You seem to have it all right. Though I don't know how to read node.js so you may have configured your payload incorrect. Also sometimes if the server isn't managing multiple device tokens correctly you may not get a silent notification at all or another issue we have with our backend was that they were redirecting the notifications server to their local machine while we're testing the notifications, obviously they weren't coming in!

A sample payload from Apple should look like this:

 { "aps" : { "content-available" : 1 }, "acme1" : "bar", "acme2" : 42 } 

Are you sure your generated payload has a similar format?!

  • I wrongly suggested to that you should change center.delegate = notificationDelegate to center.delegate = self but if I was that desperate I'd give that a try :D.

  • Make sure background App Refresh is enabled (though still without that enabled you should receive in foreground

  • If this doesn't work, then try sending it with an alert/badge and see if that works. Likely it won't work :/

  • Delete the app and then install it again. Sometimes the authorizations don't work correct if you just reinstall.
  • clean derived data, clean build, restart Xcode.

After your EDIT:

You shouldn't have deleted the didReceive Remote Notification <-- this is for retrieving any push notification that has content-available : 1 .

  • The willPresent is callback for what to do if app is in FOREGROUND. Only applicable if payload has alert or badge or sound in payload.
  • The didReceiveNotificationResponse is NOT what you think it is. It's for handling managing what action the user chose from the notification eg your notification has two actions (Snooze, delete) to click like below: 在此输入图像描述

You handle the Response to the notification using this callback.

So technically speaking if you just have a silent notification you would only get the third callback and not the first two.

If you had an app in the foreground and the payload had: content-available :1 which also had actions and the user tapped on the action then you would first get the the 3rd callback, then the 1st callback and then the 2nd callback.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM