I have an app with oneSignal as push provider. I can receive push notifications, that work good. But if I try to access push payload I get nothing as didReceiveRemoteNotification not called.
I have following code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if application.applicationState != UIApplicationState.Background {
let preBackgroundPush = !application.respondsToSelector("backgroundRefreshStatus")
let oldPushHandlerOnly = !self.respondsToSelector("application:didReceiveRemoteNotification:fetchCompletionHandler:")
var pushPayload = false
if let options = launchOptions {
pushPayload = options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil
}
}
if application.respondsToSelector("registerUserNotificationSettings:") {
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
let types : UIRemoteNotificationType = [.Badge, .Alert, .Sound]
application.registerForRemoteNotificationTypes(types)
}
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
if userInfo["d"] as! String == "t" {
print("key was received")
}
print(userInfo)
print("PREVED")
}
Problem is that nothing prints out when I receive push. What am I doing wrong ?
try once your delegete method in this place
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
call this one
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print("Recived: \(userInfo)")
completionHandler(.NewData)
}
Swift 4.2 - call this
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
debugPrint("Received: \(userInfo)")
completionHandler(.newData)
}
Use this code for Swift 3.0
//MARK: Push notification receive delegates
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
{
print("Recived: \(userInfo)")
completionHandler(.newData)
}
Hey #Alexey make sure your app provisioning file has enabled for Push Notification Service
Pretty old post but solutions can be found here in my post Push Notifications are delivered but didReceiveRemoteNotification is never called Swift or here didReceiveRemoteNotification function doesn't called with FCM notification server.
Check for this parameter: "content_available": truein your notification definition or push notification service. With underscore is how it should be set.
Related
I've used apple push notification service in my app and I received certificates and it works well But now my problem is that when I use Firebase rest API for sending message as notification I won’t receive any notification in my iPhone until I run the app But when I use Firebase it will be working, well here is my codes:
import UIKit
import Firebase
import FirebaseMessaging
import FirebaseInstanceID
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
NotificationCenter.default.addObserver(self, selector: #selector(self.refreshToken(notification:)), name: NSNotification.Name.InstanceIDTokenRefresh, object: nil)
Messaging.messaging().isAutoInitEnabled = true
FirebaseApp.configure()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert , .badge , .sound]) { (success, error) in
}
} else {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
// Fallback on earlier versions
}
application.registerForRemoteNotifications()
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
#if PROD_BUILD
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: .prod)
#else
InstanceID.instanceID().setAPNSToken(deviceToken, type: .sandbox)
#endif
Messaging.messaging().subscribe(toTopic: "global")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
Messaging.messaging().subscribe(toTopic: "global")
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
Messaging.messaging().appDidReceiveMessage(userInfo)
if Messaging.messaging().fcmToken != nil {
Messaging.messaging().subscribe(toTopic: "global")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
func applicationDidEnterBackground(_ application: UIApplication) {
Messaging.messaging().shouldEstablishDirectChannel = false
}
func applicationDidBecomeActive(_ application: UIApplication) {
FBHandler()
}
#objc func refreshToken(notification : NSNotification) {
let refreshToken = InstanceID.instanceID().token()!
print("***\(refreshToken)")
FBHandler()
}
func FBHandler() {
Messaging.messaging().shouldEstablishDirectChannel = true
}
}
For APNS to work in background you need to enable background modes in capabilities section and tick remote notification.
Once you done add/check this delegate method in AppDelegate class
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print("APNS USER INFO: \(userInfo)")
}
This method fires when app is in background and APNS comes.
More Info: How to handle push notification in background in ios 10?
UPDATE:
Add this one also and let see if it works
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
print("APNS: \(response.notification.request.content.userInfo)")
}
I've searched in all questions here but no solution worked.
I scheduled localNotifications with a userInfo option.
When app is in foreground, the notification arrived and a can handle perfectly with this function that system calls by itself.
For local notifications
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
if application.applicationState == .active {
return
}
//My implementation
}
For remote notifications
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
if application.applicationState == .active {
return
}
//My implementation
}
But the problem is, when app is closed, this functions are not called and I can't handle the data that I need.
I've tried get userInfo in that function in appDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let localUserInfo = launchOptions?[UIApplicationLaunchOptionsKey.localNotification] as? [AnyHashable: Any] {
// My implementation
} else if let remoteUserInfo = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [AnyHashable: Any] {
// My implementation
}
return true
}
But.. Didn't work...
Someone could help me please?
Thanks in advance.
Have you registered for notifications?
In didFinishLaunchingWithOptions():
// Register Notifications
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: { granted, error in
if granted {
print("User notifications are allowed")
} else {
print("User notifications are NOT allowed")
}
})
application.registerForRemoteNotification()
UNUserNotificationCenter.current().delegate = self
Then you should catch local notifications in UNUserNotificationCenterDelegate method:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
completionHandler()
}
}
You will get the notification in didFinishLaunchingWithOptions if the user clicks it whether it's local or remote , otherwise you won't know except if store them in server and pull them every time you open the app
I am downloading my events in background mode, for that I will receive a push and a silent Notification. As I have to download data when my app is in background mode, so I am using silent notification for downloading data through a web service and before that I am updating applicationIconBadgeNumber based on an increment value. When I am updating applicationIconBadgeNumber with my auto increased value all my push notifications are getting cleared in notification center. If I am not setting any applicationIconBadgeNumber they are remaining same. As I have posted my code below, please do let me know if I am missing out something.
var autoIncrementForNotification:Int = 0
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.setMinimumBackgroundFetchInterval(60)
if #available(iOS 10, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {(accepted, error) in
if !accepted {
print("Notification access denied.")
} else {
application.registerForRemoteNotifications()
}
}
} else {
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
UserDefaults.standard.removeObject(forKey: "Device_Token")
UserDefaults.standard.setValue(deviceTokenString, forKey: "Device_Token")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Swift.Void){
let aps = userInfo["aps"] as! [String: AnyObject]
if ((aps["content-available"] as? NSString)?.integerValue == 1)
{
let type = (aps["type"] as? NSString)
if(type == Constants.action_type_Events)
{
if (application.applicationState == .inactive || application.applicationState == .background)
{
autoIncrementForNotification += 1
application.applicationIconBadgeNumber = autoIncrementForNotification
// Firing my Web service
completionHandler(UIBackgroundFetchResult.newData)
}
}
}
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void){
completionHandler(UIBackgroundFetchResult.newData)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("i am not available in simulator \(error)")
}
func applicationDidBecomeActive(_ application: UIApplication) {
application.applicationIconBadgeNumber = 0
autoIncrementForNotification = 0
}
Please try the following :
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void){
var contentAvailable: Int
let aps = userInfo["aps"] as! [String: AnyObject]
if let content = aps["content-available"] as? String {
contentAvailable = Int(content)!
} else {
contentAvailable = aps["content-available"] as! Int
}
if (contentAvailable == 1)
{
let type = (aps["type"] as? NSString)
if(type == Constants.action_type_Events)
{
if (application.applicationState == .inactive || application.applicationState == .background)
{
autoIncrementForNotification += 1
application.applicationIconBadgeNumber = autoIncrementForNotification
// Firing my Web service
completionHandler(UIBackgroundFetchResult.newData)
}
}
}
}
Reason :
If your Payload file is like this {"aps":{"content-available":1}} below condition is not satisfying, so everytime applicationIconBadgeNumber is becoming 0
if ((aps["content-available"] as? NSString)?.integerValue == 1)
If your Payload file is like this {"aps":{"content-available":"1"}} then your code will work fine.
I include google firebase in my app - create google account, create google app, upload APNS certifications (.pem and in work in another service), and send push notifications from console, and my app not receive it. In Firebase console i see status complete but Approximate number of devices is "-"
Of course I updated provisions profiles and APNS cert
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Register for remote notifications
if #available(iOS 8.0, *) {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
// Fallback
let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
application.registerForRemoteNotificationTypes(types)
}
FIRApp.configure()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.tokenRefreshNotificaiton),
name: kFIRInstanceIDTokenRefreshNotification, object: nil)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print(userInfo)
}
func tokenRefreshNotificaiton(notification: NSNotification) {
if let refreshedToken = FIRInstanceID.instanceID().token() {
print("InstanceID token: \(refreshedToken)")
User.sharedUser.googleUID = refreshedToken
}
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
print(userInfo)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Prod)
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
print(userInfo)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
print(userInfo)
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
print("ошибка")
print(error)
print(error.description)
}
The first thing I see is there's no call to connect to FIRMessaging. Try adding this to your AppDelegate:
func applicationDidBecomeActive(application: UIApplication) {
FIRMessaging.messaging().connectWithCompletion { error in
print(error)
}
}
Use the following code.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
if #available(iOS 10.0, *)
{
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.currentNotificationCenter().delegate = self
UNUserNotificationCenter.currentNotificationCenter().requestAuthorizationWithOptions([.Badge, .Sound, .Alert]) { (granted, error) in
if granted
{
//self.registerCategory()
}
}
// For iOS 10 data message (sent via FCM)
FIRMessaging.messaging().remoteMessageDelegate = self
}
else
{
let settings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert,.Badge,.Sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
//Configuring Firebase
FIRApp.configure()
// Add observer for InstanceID token refresh callback.
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.tokenRefreshNotification), name: kFIRInstanceIDTokenRefreshNotification, object: nil)
return true
}
//Receive Remote Notification on Background
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void)
{
FIRMessaging.messaging().appDidReceiveMessage(userInfo)
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData)
{
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox)
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Prod)
}
func tokenRefreshNotification(notification: NSNotification)
{
if let refreshedToken = FIRInstanceID.instanceID().token()
{
print("InstanceID token: \(refreshedToken)")
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
func connectToFcm()
{
FIRMessaging.messaging().connectWithCompletion { (error) in
if (error != nil)
{
print("Unable to connect with FCM. \(error)")
}
else
{
print("Connected to FCM.")
}
}
}
func applicationDidBecomeActive(application: UIApplication)
{
connectToFcm()
}
You might be using Data or aps key in PUSH JSON which is used to send notifications to devices. It should work properly but in rare cases, it not works, even it'll give you success in fcm/send api but notification will not reach particular devices. This problem usually occurs in iOS devices.
A solution which worked for me is add notification key instead of Data.
{
"to" : "device token",
"notification":{
"body": "test",
"title": "test"
}
}
If you are sending from Backend OR you don't have access of Firebase console. Then you can test and send notification via POSTMAN also. But you must have SERVER KEY, which can be got from Firebase console under Cloud Messaging settings.
API: https://fcm.googleapis.com/fcm/send
Method: POST
Headers:
"Content-Type"=application/json
"Authorization"="key=YOUR SERVER KEY" //You must add key= above the server key.
{
"to" : "your device token",
"notification":{
"body": "test",
"title": "test"
}
}
ANOTHER DETAILED AND FULL PAYLOAD IF YOU NEED TO SEE WHAT WE CAN SEND IN FIREBASE NOTIFICATION:
{
"to":"device token",
"notification":{
"data":{
"avatar":"",
"body":"",
"key_notification":"0",
"type_notification":"1",
"deviceToken":"device token",
"badge":1,
"message":"your text"
},
"text":"your text",
"sound":"sound.caf",
"badge":21
},
"priority":"high"
}
For some reason my didReceiveRemoteNotification is never called. I have done the following:
checklist of APNS:
Create AppId allowed with Push Notification
Create SSL certificate with valid certificate and app id
Create Provisioning profile with same certificate and make sure to add device
With Code:
Register app for push notification
Handle didRegisterForRemoteNotificationsWithDeviceToken method
Set targets> Capability> background modes> Remote Notification
Handle didReceiveRemoteNotification
Yet my function does not seem to get called. My code looks like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if (application.respondsToSelector("isRegisteredForRemoteNotifications"))
{
// iOS 8 Notifications
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: (.Badge | .Sound | .Alert), categories: nil));
application.registerForRemoteNotifications()
}
else
{
// iOS < 8 Notifications
application.registerForRemoteNotificationTypes(.Badge | .Sound | .Alert)
}
return true
}
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var tokenString = ""
for var i = 0; i < deviceToken.length; i++ {
tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
apnsID = tokenString
println("******apnsID is \(apnsID)")
dToken = deviceToken
println("******dToken is \(dToken)")
NSUserDefaults.standardUserDefaults().setObject(deviceToken, forKey: "deviceToken")
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
println("***********didFailToRegisterForRemoteNotificationsWithError")
println(error)
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
println("Getting notification")
var message: NSString = ""
var alert: AnyObject? = userInfo["aps"]
println(userInfo["aps"])
if((alert) != nil){
var alert = UIAlertView()
alert.title = "Title"
alert.message = "Message"
alert.addButtonWithTitle("OK")
alert.show()
}
}
add content_available:true in your request . for iOS payload data.You will get notification in didReceiveRemoteNotification. Now handle it.
As I found out having the same problem myself, in order for didReceiveRemoteNotificationto be called, the incoming notification music carry an "available_content" : true parameter with the notification payload. So in case of you sending the notification in a dictionary form , as was my case in device to device pushes, you just have to add it in the dictionary as you would specify other parameters as you would for sound or badge, also needed if you're using some sort of push service as Postman
Three steps:
Add logic here to handle incoming notification:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Add your logic here
completionHandler(.newData)
}
Add Background mode to capabilities in target, and ensure to check 'Remote notifications'
While sending a push notification, add "content_available" : true
This worked for me in iOS 14/Xcode 12.3.