why I can't remove the badge after receiving notification? - ios

I am trying to implement push notification using Firebase Cloud Messaging, I send the message through firebase console. when composing a message in Firebase console, I set the badge number to be 1 like the picture below
after that, my app icon in the home screen will always have badge with number "1", even tough I have tried to uninstall and reinstall it, the badge with number "1" is still there.
but it only happens in my iPhone,if I Install it on the other phone, the badge will not show up
I use this code in App delegate to trigger push notification
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
var fcmTokenUser : String?
var firsTimeUsingApp = true
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
print(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last! as String)
// To get FCM token that will be sent to APNS via Google FCM
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
let token = Messaging.messaging().fcmToken
fcmTokenUser = token
checkFirstTimeUsingAppOrNot()
moveToNextPage()
// to make status bar in the light mode (in info.plist it also has to be set 'View controller-based status bar appearance' to NO)
UIApplication.shared.statusBarStyle = .lightContent
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String){
// This callback is fired at each app startup (when the user install the app for the very first time) and whenever a new token is generated due to The app is restored on a new device, The user uninstalls/reinstall the app, The user clears app data.
// after fcm generated for the very first time,then fcm can also be retrieved in the 'didFinishLaunchingWithOptions' method above (let token = Messaging.messaging().fcmToken)
fcmTokenUser = fcmToken
moveToNextPage()
}
private func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken as Data
}
}
how to resolve this issue?

iOS will remember your applications badge count always, even if your uninstall your app and install it again. For removing your badge you have to do any one of following things,
Send another push notification to your app with badge = 0.
Remove badge count by your own whenever user open your app by using below code, UIApplication.shared.applicationIconBadgeNumber = 0 . Add this line of code in Appdelegate's didBecomeActive(:) method.
Thanks.

Related

How to Show a Certain View Controller and Send the Data After We Tap the Notification?

I have tried to read similar thread in here How to make your push notification Open a certain view controller?
but the information is not complete.
I am trying to implement push notification (firebase cloud messaging). after receiving the notification alert, i want if the user tap that notification, it will send the user to a certain view controller and open the data that have been sent from the server.
how to access the data/information from the server that has been sent through push notification?
send that data/information to a certain view controller?
Here is my code in app delegate
import UIKit
import Firebase
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
var fcmTokenUser : String?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
print(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last! as String)
// To get FCM token that will be sent to APNS via Google FCM
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
let token = Messaging.messaging().fcmToken
fcmTokenUser = token
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String){
// This callback is fired at each app startup (when the user install the app for the very first time) and whenever a new token is generated due to The app is restored on a new device, The user uninstalls/reinstall the app, The user clears app data.
// after fcm generated for the very first time,then fcm can also be retrieved in the 'didFinishLaunchingWithOptions' method above (let token = Messaging.messaging().fcmToken)
fcmTokenUser = fcmToken
}
private func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken as Data
}
}
Add this code to your AppDelegate to detect the user tap (response) and after double tap it will show you a certain viewController as you specified.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
//THIS PRINT WILL SHOW YOU THE USER TAP ON NOTIFICATION
print("userNotificationCenter --- \(response) --- ")
let sb = UIStoryboard(name: "Main", bundle: nil)
let otherVC = sb.instantiateViewController(withIdentifier: "yourViewControllerIdentifier") as! yourViewControllerClassName
window?.rootViewController = otherVC;
}
To access the data/information from the server that has been sent through push notification -
The notification data is delivered to your app in application:didReceiveRemoteNotification:. If you want to process it in applicationDidBecomeActive: you should store it in application:didReceiveRemoteNotification: and read it again in applicationDidBecomeActive.
the delegate method to
Handle notification messages after display notification is tapped by the user.
func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
//get required values from data
completionHandler();
//push to view controller
}
Note: Save this dictionary data in model after parse or save the dictionary object on project level to use in any where in the project.
Than before push to any view controller declare dictionary or modal that controller in which way you want to see the date there.

iOS Push Notifications doesn't work with Firebase

I use Firebase to send Notification with my iOS app, I have followed all step in documentation :
Apple Developer Account Configuration
Generating a CSR file
Uploading CSF file
Preparing the APNs Certificate
Configuring Firebase for Push Notifications
Building the Firebase Notification in my app
When I try to send a Notification there isn't no problem found in Firebase, for one particular user or for all iOS device. But none of my device (real device obviously) receive notification.
I use the good Bundle, I enable notification in my application and there is the code in my AppDelegate :
import UIKit
import UserNotifications
import Firebase
import FirebaseInstanceID
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UINavigationBar.appearance().barTintColor = Design.blue_es
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white]
UINavigationBar.appearance().tintColor = UIColor.white
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
// For iOS 10 data message (sent via FCM
Messaging.messaging().remoteMessageDelegate = self
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
return true
}
func application(received remoteMessage: MessagingRemoteMessage) {
print(remoteMessage.appData)
}
// Called when APNs failed to register the device for push notifications
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
// Print the error to console (you should alert the user that registration failed)
print("APNs registration failed: \(error)")
}
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
}
}
IN Swift 3
Configuring Your Apple Developer Account
Generating a CSR file
Uploading Your CSR File
Preparing the APNs Certificate
Configuring Firebase for Push Notifications
Building the Firebase Notification App
Installing the Firebase SDK Using CocoaPods
Adding GoogleService-Info.plist
Enabling Push Notifications
Initializing Push Notifications
AppDelegate of your Project
import UIKit
import SVProgressHUD
import UserNotifications
import Firebase
import FirebaseInstanceID
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
static var appDelegate:AppDelegate!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
// For iOS 10 data message (sent via FCM
Messaging.messaging().remoteMessageDelegate = self
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
FirebaseApp.configure()
return true
}
func application(received remoteMessage: MessagingRemoteMessage) {
print(remoteMessage.appData)
}
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken as Data
}
}
I think first configure for firebase
FirebaseApp.configure()
after that you should call registerForRemoteNotifications()

How to get FCM Token when user has denied access to allow notifications

This is my first time working on with firebase due to a requirement by the backend so let me know if you don't understand the question or if it doesn't make any sense. What I want to achieve is that I need a Registration_ID which is the FCM Token when user register. So this is how I'm implementing it in AppDelegate.swift > didFinishLaunchingWithOptions
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
After that in AppDelegate.swift I've added these three functions:
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken as Data
}
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
}
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken as Data
}
No the issue is that when it ask for permission of notification and user deny it then how I'll get FCM that I'll send to the backend when user register or login.
An FCM token is generated regardless of the user's response to the authorization request - if the response takes long enough, the FCM token will be generated before the response is given.
Notifications will not work until the user gives permission but generating the FCM token is not dependent on getting permission.
Please note: I have not found this documented anywhere, but through my own testing. I have tested on iOS 10.3.1 and 11.0.
The first time the token is generated the Messaging delegate's didRefreshRegistrationToken is called, I suspect the problem is that you have not set the delegate with
Messaging.messaging().delegate = self
If user not granting permission, you will not able to send push notification. 3rd party you use cant change this permission (amazon, firebase). For Firebase cloud Messaging Push notification permission is a must.

Firebase Notification To Device with FCM Token Says Sent but not received

I am attempting to send a simple push notification from the firebase notification console to a specific device using an FCM token. The firebase notification console shows the notification as sent but the device does not receive it. I have tried sending the notification and then waiting to see if the console logs from didReceiveRemoteNotification, but the notification takes too long (hours) to be shown as sent in the firebase console (even when I set the priority to high).
App Delegate
import UIKit
import Firebase
import FirebaseStorage
import FirebaseDatabase
import FirebaseMessaging
import CoreData
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Use Firebase library to configure APIs
FirebaseApp.configure()
/////
// For Firebase Cloud Messaging (FCM)
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
// End of [for Firebase Cloud Messaging (FCM)]
/////
return true
}
///////////////////////
// FCM Setup
// Monitor token generation for FCM: Be notified whenever the FCM token is updated
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
}
// Monitor token generation for FCM:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
} // Handle messages received through the FCM APNs interface
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
print("didReceiveRemoteNotification")
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
// gcm_message_id
if let messageID = userInfo["gcmMessageIDKey"] {
print("Message ID: \(messageID)")
}
^My guess is that the issue may have to do with the "gcm_message_id"/"gcmMessageId"/"gcm.message_id" as it is different in each of the three approaches I tried below
// Print full message.
print(userInfo)
}
// Handle messages received through the FCM APNs interface
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
print("didReceiveRemoteNotification (withCompletionHandeler)")
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo["gcmMessageIDKey"] {
print("Message ID: \(messageID)")
}
^My guess is that the issue may have to do with the "gcm_message_id"/"gcmMessageId"/"gcm.message_id" as it is different in each of the three approaches I tried below
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
// End of [FCM Setup]
///////////////////////
}
View Controller
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Retrieve the current registration token for Firebase Cloud Messaging (FCM)
let token = Messaging.messaging().fcmToken
print("FCM token: \(token ?? "")")
}
}
Entitlements & Enabling Push Notifications
I have added the push entitlements and enabled background modes for push notifications and added the GoogleService-Info.plist to my project.
Method for sending Notification
I am creating notification from the Firebase Notifications console (as shown below) so there should be no issue with the structure of the notification itself.
I have tried the following approaches to remedy the issue, but all have produced the same result:
Google Firebase Documentation
Remote Notifications w/ firebase tutorial
Google Firebase Quickstart
Does anyone know why the notification is being marked as sent in the firebase notification console but not showing up on the device?
A couple of troubleshooting steps I use when working with push notifications are:
Get push working independent of the firebase services first. I use this tool.
Make sure that you dont have any bundle identifier namespace collisions. So for example having any combination of appstore build, testflight build, and / or develop build of an app on the device. Delete all but one instance of the app. The bundle identifier is how your device knows which app to route the push notification to.
When all else fails - I try to isolate the issue by building a new sample project and hook it up to a new firebase project and see if I can narrow my focus down to just being able to get push working without any other business logic in my app. This helps me prove to my self that I haven't gone insane, and proves to me that it's not some mysterious network condition leading to my woes.
I hope this helps you as you work get it all figured out.
Try to add the following code to didRegisterForRemoteNotificationsWithDeviceToken func:
Messaging.messaging().apnsToken = deviceToken
So it will look like this:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
It is work for me.
Does anyone know why the notification is being marked as sent in the firebase notification console but not showing up on the device?
Because "sent" does not mean "received".
Notifications cannot be guaranteed to be received on the device. With basic APNS infrastructure you even cannot get the information if a notifications was received or processed on the device.
If you don't receive a successfully sent message on the device there can be many reasons. Furthermore, even if you receive a Firebase token, that does not mean that your device can receive the notification in any case.
To isolate the problem I would suggest to build up the minimal setup and use APNS without Firebase. You could use Terminal or NWPusher (https://github.com/noodlewerk/NWPusher) for sending notifications from your local macOS system and the iOS native remote push notifications framework for receiving notifications.
Keep care to convert the APNS device token to the correct format required for submitting a notification:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.hexEncodedString()
print("Token: \(token)")
}
Data extension:
extension Data {
func hexEncodedString() -> String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
I see that you have done everything in your project's Capabilities.
Some points:
Conform your class to messaging delegate like so:
Messaging.messaging().delegate = self
Make sure you've setup your certificates properly and uploaded everything on Firebase Push Notification Configurations (not exact term).
I've done several applications that uses Firebase Push Notification Service and making a sample app from scratch might help you figure out what you've been doing wrong.
And... here's a nicer code block for registering your application for push notification.
// Setup Push Notifications
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
if error == nil{
DispatchQueue.main.async(execute: {
application.registerForRemoteNotifications()
})
}
}
}
else {
let notificationTypes: UIUserNotificationType = [.sound, .alert, .badge]
let notificationSettings = UIUserNotificationSettings(types: notificationTypes, categories: nil)
application.registerForRemoteNotifications()
application.registerUserNotificationSettings(notificationSettings)
}

Push notification retrieved in iOS but not in Firebase

I am facing this strange issue in my application. I am trying to integrate push notification in my application using firebase. I have included Firebase SDK in the project using the downloaded SDK(not using pod). I have included the following frameworks from the downloaded zip file in the application:
In AppDelegate
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
}
// This is called and the access token is received.
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
var token = ""
for i in 0..<deviceToken.count {
token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
}
print(token)
Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
}
// This is not getting called
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
Messaging.messaging().subscribe(toTopic: "ios_topic")
}
The access token I get in didRegisterForRemoteNotificationsWithDeviceToken is valid and I successfully sent push to the device using that. But the didRefreshRegistrationToken of FireBase is not getting called. I have added -ObjC in linkerflags and FirebaseAppDelegateProxyEnabled as NO in info.plist. I have added the GoogleService-Info.plist file in the project root, and the project is configured correctly in FireBase console.
What is the possible issue here and how to solve it?
That was the silliest of mistakes while following the tutorials. Just needed to set the delegate of Messaging.messaging() as AppDelegate. Add the following code right under FirebaseApp.configure() and the issue is solved.
FirebaseApp.configure()
Messaging.messaging().delegate = self

Resources