I am using FCM for push notification. FCM is connected, device is registered successfully and I am able to print device token but the device is not receiving notification.
In general -> capabilities tab -> enabled push notification and remote notification in back ground mode.
Here registering device for remote notification.
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let trimEnds:String! = {
deviceToken.description.trimmingCharacters(
in: CharacterSet(charactersIn: "<>"))
}()
let cleanToken:String! = {
trimEnds.replacingOccurrences(of: " ", with: "")
}()
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
print(token)
UserDefaults.standard.set(token, forKey: "deviceToken")
UserDefaults.standard.synchronize()
#if DEBUG
//For Firebase
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.sandbox)
#else
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.prod)
#endif
print("Device Token:", token)
}
Here I called didReceiveRemoteNotification method to receive notification on the registered device:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
print("-=-=-=-=-\nDid receive notification\n-=-=-=-",userInfo)
print("-=-=-=-=-\n")
NotificationCenter.default.post(name: Notification.Name(rawValue: "notification_recieved"), object: nil)
if userInfo.index(forKey: "chat_id") != nil {
print("messag push")
if (AppUtility?.hasValidText(User.userID))! {
//let friendImage = userInfo["path"] as! String
let chatID = userInfo["chat_id"] as! String
let friendId = userInfo["to"] as! String
let unRead = userInfo["unread"] as! String
print(unRead)
UnReadMsgs = unRead
let dictAPS = userInfo["aps"] as! NSDictionary
let dict = dictAPS["alert"] as! NSDictionary
let friendName = dict["title"] as! String
let friendMsg = dict["body"] as! String
if(UIApplication.shared.applicationState == UIApplicationState.active){
print("app is Active")
if let wd = self.window {
var VC = wd.rootViewController
if(VC is UINavigationController){
VC = (VC as! UINavigationController).visibleViewController
if(VC is ChatViewController!){
print("Chat Screen")
let chatVC : ChatViewController = VC as! ChatViewController
if chatVC.chatId == chatID{
print("Same Chat")
self.clearChatWithChatID(chatID)
}else{
CustomNotificationView.showNotificationPopUp(self.window!, name: friendName, msg: friendMsg, image: "", chat: chatID, friendID: friendId)
playSound()
print("Other Chat")
}
}else{
let nc = NotificationCenter.default
nc.post(name: Notification.Name(rawValue: "MessageGet"),
object: nil,
userInfo: ["unRead":unRead,
"date":Date()])
CustomNotificationView.showNotificationPopUp(self.window!, name: friendName, msg: friendMsg, image: "", chat: chatID, friendID: friendId)
playSound()
print("Other Screen")
}
}
}
}else{
print("app is in BG")
var vc:ChatViewController!
vc = ChatViewController(nibName: "ChatViewController", bundle: nil)
vc.chatId = chatID
vc.otherUserId = friendId
vc.otherUserName = friendName
vc.channelRef = self.channelRef.child("\(chatID)")
vc.friendImageLink = "\(resourceUrl)\("")"
let nav = UINavigationController(rootViewController: vc)
nav.isNavigationBarHidden = false
if let wd = self.window {
var VC = wd.rootViewController
if(VC is UINavigationController){
VC = (VC as! UINavigationController).visibleViewController
}
VC!.present(nav, animated: false, completion: {
})
}
}
}
}else{
let val = userInfo["aps"] as! [String:AnyObject];
let alert = NSString(string: val["alert"] as! String)
if(UIApplication.shared.applicationState == UIApplicationState.inactive || UIApplication.shared.applicationState == UIApplicationState.background)
{
showUserInfo(application, didReceiveRemoteNotification: userInfo)
}
else
{
print("top most vc \(String(describing: UIApplication.shared.keyWindow!.rootViewController!.topMostViewController().presentingViewController)) and presentedvc \(String(describing: UIApplication.shared.keyWindow!.rootViewController!.topMostViewController().presentedViewController))")
if UIApplication.shared.keyWindow!.rootViewController!.topMostViewController() is NYAlertViewController{
let newAlert = AppUtility?.getDisplayAlertController(title: "FitFlow", messageText: alert as String)
let nvVc = UIApplication.shared.keyWindow!.rootViewController!.topMostViewController().presentedViewController
nvVc?.present(newAlert!, animated: true, completion: nil)
return
}
AppUtility?.displayAlert(title:"FitFlow", messageText: alert as String,UIApplication.shared.keyWindow!.rootViewController!.topMostViewController())
}
}
}
I have tested by keeping breakpoints, it does not called didReceiveRemoteNotification method at all. How to receive push notification using above method?
I was also stuck with this earlier.
This requires FCM token, and not the APNS token.
To do so,
Your AppDelegate class needs to have these -
import Firebase
import UserNotifications
import FirebaseMessaging
class AppDelegate: UIResponder,
UIApplicationDelegate,
UNUserNotificationCenterDelegate,
FIRMessagingDelegate {
}
Then subscribe the messaging delegate in didFinishLaunchingWithOptions
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
GIDSignIn.sharedInstance().clientID =
"Your client id"
DispatchQueue.main.async {
FIRApp.configure()
}
FIRMessaging.messaging().remoteMessageDelegate = self
if #available(iOS 10, *) {
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]){ (granted, error) in }
application.registerForRemoteNotifications()
}
// iOS 9 support
else if #available(iOS 9, *) {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
// iOS 8 support
else if #available(iOS 8, *) {
UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
}
// iOS 7 support
else {
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
return true
}
// You dont need didRegisterForRemoteNotificationsWithDeviceToken method anymore
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { }
the token you received from the delegate didRegisterForRemoteNotificationsWithDeviceToken is not useful,
You need to use the FIRInstanceID.instanceID().token()
Add below code in your applicationDidBecomeActive, this will check for FCM token refreshes, and handle that elegantly.
func applicationDidBecomeActive(_ application: UIApplication) {
NotificationCenter.default.addObserver(self, selector:
#selector(tokenRefreshNotification), name:
NSNotification.Name.firInstanceIDTokenRefresh, object: nil)
}
#objc func tokenRefreshNotification(notification: NSNotification) {
if let refreshedToken = FIRInstanceID.instanceID().token() {
print("InstanceID token: \(refreshedToken)")
UserDefaults.standard.set(refreshedToken, forKey: "deviceToken")
self.sendFCMTokenToServer(token: refreshedToken)
}
/*
Connect to FCM since connection may
have failed when attempted before having a token.
*/
else {
connectToFcm()
}
}
func updatePushNotificationWebservice() {
/*
if you want to save that token on your server
Do that here.
else use the token any other way you want.
*/
}
func connectToFcm() {
FIRMessaging.messaging().connect { (error) in
if (error != nil) {
print("Unable to connect with FCM. \(String(describing: error))")
}
else {
print("Connected to FCM.")
/*
**this is the token that you have to use**
print(FIRInstanceID.instanceID().token()!)
if there was no connection established earlier,
you can try sending the token again to server.
*/
let token = FIRInstanceID.instanceID().token()!
self.sendFCMTokenToServer(token: token)
}
}
}
For debugging use the token obtained from FIRInstanceID.instanceID().token()!, and use the push notification firebase console with same token in the >project>Cloud messaging tab.
https://console.firebase.google.com/u/0/
Setting priority to high from backend solves my problem.
Please check from firebase console->cloud messaging(down left item) to send push notification.
Related
So I have a single Xcode project for two iOS app targets that share a common codebase.
The first app was already working and live on the App Store. The second app is just a modified paid version of our earlier app.
Both the apps use Firebase and OneSignal (for push notifications ) and I have downloaded two GoogleServiceInfo.plist files and linked them to their respective targets.
This is my AppDelegate.swift file where I configured Firebase.
import Firebase
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var wakeTime : Date = Date() // when did our application wake up most recently?
// To access AppDelegate values
class var shared: AppDelegate {
return (UIApplication.shared.delegate as? AppDelegate) ?? AppDelegate()
}
// To get token for login
var pushRefreshedToken : String {
print(Messaging.messaging().fcmToken)
return Messaging.messaging().fcmToken ?? "token_new_reg"
}
let gcmMessageIDKey = "gcm.message_id"
var notification: Any?
var window: UIWindow?
//this variable is declared so that the app can run on ios 12 or lower running devices, without this it will show black screen.
func applicationWillEnterForeground(_ application: UIApplication) {
// time stamp the entering of foreground so we can tell how we got here
wakeTime = Date()
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// OneSignal
let notificationOpenedBlock: OSNotificationOpenedBlock = { result in
// This block gets called when the user reacts to a notification received
let notification: OSNotification = result.notification
print("Message: ", notification.body ?? "empty body")
print("badge number: ", notification.badge)
print("notification sound: ", notification.sound ?? "No sound")
if let additionalData = notification.additionalData {
print("additionalData: ", additionalData)
// Handle additional data
switch UIApplication.shared.applicationState {
case .background, .inactive:
// background, opened from notif
if let tag = additionalData["t"] as? String {
if tag == NotificationRedirectionTags.appstore {
CentralLoadingViewController.redirectionTag = tag
} else {
MiddleViewController.notifTag = tag
}
}
case .active:
// foreground
if let topVC = UIApplication.getTopViewController() {
if let tag = additionalData["t"] as? String {
if tag == NotificationRedirectionTags.vehicleHealth {
print("Going to VH")
let storyboard = UIStoryboard(name: StoryBoards.CarHealthStoryboard, bundle: nil)
let nv = storyboard.instantiateViewController(withIdentifier: Identifiers.MainCarHealthViewController) as! MainCarHealthViewController
topVC.navigationController?.pushViewController(nv, animated: true)
}
if tag == NotificationRedirectionTags.appstore {
if let url = URL(string: "https://apps.apple.com/in/app/scouto/id1495648508") {
UIApplication.shared.open(url)
}
}
}
}
default:
break
}
// Handle action buttons
if let actionSelected = notification.actionButtons {
print("actionSelected: ", actionSelected)
}
if let actionID = result.action.actionId {
//handle the action
if actionID == NotificationRedirectionTags.vehicleHealth {
MiddleViewController.notifTag = actionID
} else if actionID == NotificationRedirectionTags.appstore {
CentralLoadingViewController.redirectionTag = actionID
}
}
}
}
OneSignal.setNotificationOpenedHandler(notificationOpenedBlock)
// Remove this method to stop OneSignal Debugging
OneSignal.setLogLevel(.LL_VERBOSE, visualLevel: .LL_NONE)
// OneSignal initialization
OneSignal.initWithLaunchOptions(launchOptions)
#if MAHINDRA_CW_PRODUCTION
OneSignal.setAppId(appIDOne)
#elseif SCOUTO_PRODUCTION
OneSignal.setAppId(appIDTwo)
#endif
// promptForPushNotifications will show the native iOS notification permission prompt.
// We recommend removing the following code and instead using an In-App Message to prompt for notification permission (See step 8)
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
let str = [NotificationRedirectionTags.appstore, "AppStore"]
if str.contains(UserDefaults.standard.value(forKey: NotificationActionTags.inputText) as? String ?? ""){
if let url = URL(string: "https://apps.apple.com/in/app/scouto/id1495648508") {
UIApplication.shared.open(url)
}
}
LocationService.shared.updatingLocation(completion: { location in
if location != nil{
LocationService.shared.stopUpdatingLocation()
} else {
LocationService.shared.showLocationPermissionsAlert(true)
}
})
// FireBase Setup
FirebaseApp.configure()
// notification
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) { (granted, error) in
guard granted else { return }
print("UNNotificationCenter Auth Granted")
let replyAction = UNTextInputNotificationAction(identifier: "ReplyAction", title: "Reply", options: [])
let openAppAction = UNNotificationAction(identifier: "OpenAppAction", title: "Open app", options: [.foreground])
let quickReplyCategory = UNNotificationCategory(identifier: "QuickReply", actions: [replyAction, openAppAction], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([quickReplyCategory])
print("UNNotificationCategory Set")
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
Messaging.messaging().delegate = self
Messaging.messaging().token { token, error in
if let error = error {
print("Error fetching FCM registration token: \(error)")
} else if let token = token {
print("FCM registration token: \(token)")
//self.fcmRegTokenMessage.text = "Remote FCM registration token: \(token)"
}
}
application.registerForRemoteNotifications()
}
//MARK:- Push Notifications
extension AppDelegate {
// DEPRECATED
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// 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)")
}
// Print full message.
print("Remote notification: User info 1")
print(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// 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)")
}
// Print full message.
print("User info 2")
print(userInfo)
//completionHandler(UIBackgroundFetchResult.newData)
}
}
// MARK:- Push Notification Handler - UNUserNotificationCenterDelegate
#available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
// 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)")
}
// Print full message.
print("User info 3")
print(userInfo)
// Change this to your preferred presentation option
completionHandler([[.alert, .badge , .sound]])
}
// Notification handler
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print full message.
print("User info 4")
print( )
// Handle text input notification
if response.actionIdentifier == "ReplyAction" {
print("Entered ReplyAction block")
if let textResponse = response as? UNTextInputNotificationResponse {
// Do whatever you like with user text response...
print("----RECEIVING USER NOTIFICATION INPUT ------")
print(textResponse.userText)
if textResponse.userText == NotificationRedirectionTags.appstore || textResponse.userText == "AppStore" {
if let url = URL(string: "https://apps.apple.com/in/app/scouto/id1495648508") {
UIApplication.shared.open(url)
}
}
UserDefaults.standard.setValue(textResponse.userText, forKey: NotificationActionTags.inputText)
return
}
}
// Handle userInfo data
switch UIApplication.shared.applicationState {
case .background, .inactive:
// background, opened from notif
if let tag = userInfo["t"] as? String {
if tag == NotificationRedirectionTags.appstore {
UserDefaults.standard.setValue(tag, forKey: NotificationActionTags.inputText)
}
MiddleViewController.notifTag = tag
}
case .active:
// foreground
if let topVC = UIApplication.getTopViewController() {
if let tag = userInfo["t"] as? String {
// Go to Vehicle Health
if tag == NotificationRedirectionTags.vehicleHealth {
print("Going to VH")
let storyboard = UIStoryboard(name: StoryBoards.CarHealthStoryboard, bundle: nil)
let nv = storyboard.instantiateViewController(withIdentifier: Identifiers.MainCarHealthViewController) as! MainCarHealthViewController
topVC.navigationController?.pushViewController(nv, animated: true)
}
// Go to Live Track
if tag == "os" {
print("Going to Live Track")
let storyboard = UIStoryboard(name: StoryBoards.DashboardStoryboard, bundle: nil)
let nv = storyboard.instantiateViewController(withIdentifier: Identifiers.LiveTrackingViewController) as! LiveTrackingViewController
topVC.navigationController?.pushViewController(nv, animated: true)
}
}
}
default:
break
}
completionHandler()
}
}
//MARK: MessagingDelegate FCM -> Recieve message from FCM
extension AppDelegate : MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("Firebase registration token: \(fcmToken)")
let lokenFCM : String = fcmToken ?? "token_new_reg"
let dataDict:[String: String] = ["token": lokenFCM]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
// print("Message message data", remoteMessage.appData)
// }
}
I have uploaded the same APNS key to Firebase for both the apps in Project settings.
However, the issue is that I am able to receive notifications only on one app and I am not able to receive notifications in the second app.
I have checked the code multiple times but cannot seem to figure out what is going wrong at all.
Please kindly have a look at the code and provide me with some suggestions on what I may be doing wrong. Your help is highly appreciated & thank you!
Recently I stopped receiving Firebase Cloud Messaging APNs notifications. I decided to update to latest version of Firebase pods and my AppDelegate.swift had a few functions deprecated so it currently looks like this now:
import UIKit
import SwiftyJSON
import IQKeyboardManagerSwift
import Firebase
import FirebaseInstanceID
import FirebaseMessaging
import UserNotifications
import AVFoundation
import Crittercism
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
var isPulltoRefreshInProgress: Bool = Bool(false)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Crittercism.enable(withAppID: Config.sharedInstance.apteligentAppID())
//To find Home Directory
print("Home Directory - \(NSHomeDirectory())")
IQKeyboardManager.shared.enable = true
IQKeyboardManager.shared.enableAutoToolbar = false
IQKeyboardManager.shared.shouldShowToolbarPlaceholder = false
// IQKeyboardManager.shared.shouldResignOnTouchOutside = true
// UIApplication.shared.statusBarStyle = .lightContent
configureForPushNotification()
registrationForNotification(application: application )
self.startOver()
return true
}
func registrationForNotification(application: UIApplication) {
// iOS 10 support
if #available(iOS 10, *) {
DLog("registrationForNotification")
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .alert, .sound]){ (granted, error) in }
application.registerForRemoteNotifications()
}
else {
application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
Tokens.sharedInstance.isNotificationCame = true
NotificationCenter.default.post(name: NSNotification.Name(NotificationCenterIDs.kPushNotificationReceivedNotification), object:self)
if application.applicationState == UIApplication.State.active {
DLog("App is in foreground when notification received")
// app was already in the foreground
} else {
DLog("App was just brought from background to foreground via PUSH")
// app was just brought from background to foreground via PUSH
self.startOver()
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// let application = UIApplication.shared
// if(application.applicationState == .active){
// DLog("user tapped the notification bar when the app is in foreground")
if let window = self.window {
if let viewController = UIStoryboard(name: StoryboardControllerIDs.kStoryboardId, bundle: nil).instantiateViewController(withIdentifier: StoryboardController.kNotificationsViewController) as? NotificationsViewController{
if let rootViewController = window.rootViewController as? UINavigationController{
// DLog("Root: " + String(describing: type(of: rootViewController)))
Tokens.sharedInstance.isNotificationCame = true
rootViewController.pushViewController(viewController, animated: true)
}
}
}
// }
// if(application.applicationState == .inactive)
// {
// DLog("user tapped the notification bar when the app is in background")
// }
/* Change root view controller to a specific viewcontroller */
// let storyboard = UIStoryboard(name: "Main", bundle: nil)
// let vc = storyboard.instantiateViewController(withIdentifier: "ViewControllerStoryboardID") as? ViewController
// self.window?.rootViewController = vc
completionHandler()
}
func configureForPushNotification() {
var fileName : String = "GoogleServiceQA-Info"
let currentConfiguration = Bundle.main.object(forInfoDictionaryKey: "Config")! as! String
if currentConfiguration.lowercased() == "production" {
fileName = "GoogleServiceProd-Info"
}
let filePath = Bundle.main.path(forResource: fileName, ofType: "plist")!
let options = FirebaseOptions(contentsOfFile: filePath)
FirebaseApp.configure(options: options!)
Messaging.messaging().delegate = self
// if let refreshedToken = InstanceID.instanceID().token() {
// print("InstanceID token: \(refreshedToken)")
// DeviceTokenConstants.deviceToken = refreshedToken
// }
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
DLog("Error fetching remote instange ID: \(error)")
} else if let result = result {
DLog("configureForPushNotification - Remote instance ID token: \(result.token)")
DeviceTokenConstants.deviceToken = result.token
}
}
NotificationCenter.default.addObserver(self, selector:
#selector(tokenRefreshNotification), name:
NSNotification.Name.InstanceIDTokenRefresh, object: nil)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//Getting errors in Xcode10 for iOS12
let hexString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
DLog("===DEVICE-TOKEN: \(hexString)")
// In debug mode
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
Messaging.messaging().setAPNSToken(deviceToken, type: .prod)
// In release mode
// InstanceID.instanceID().setAPNSToken(deviceToken, type: InstanceIDAPNSTokenType.prod)
}
// This method will be called when app received push notifications in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
{
completionHandler([.alert, .badge, .sound])
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
DeviceTokenConstants.deviceToken = fcmToken
FireBaseToken.didReceived = true
}
#objc func tokenRefreshNotification(_ notification: Notification) {
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print("Error fetching remote instange ID: \(error)")
} else if let result = result {
print("tokenRefreshNotification - Remote instance ID token: \(result.token)")
DeviceTokenConstants.deviceToken = result.token
let dataDict:[String: String] = ["token": result.token]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
}
}
// Deprecated code
// if let refreshedToken = InstanceID.instanceID().token() {
// print("InstanceID token: \(refreshedToken)")
// DeviceTokenConstants.deviceToken = refreshedToken
// }
// Connect to FCM since connection may have failed when attempted before having a token.
// connectToFcm()
}
Is there something in this code that may prevent the notification from being delivered or is this an external issue outside of the iOS app? I am able to see tokens being printed in my console for the device token and fcm token, so I feel that the setup in the iOS app is not the issue. I ensured that the app notifications were not disabled in my iPhone.
If you are using keyid instead of certification, you can try to change ur debug mode to release mode then you can try to see if you receive push or u can upload to TestFlight and check if you receive the push.
However it’s better to use certification instead keyid that you can use in debug and in release mode.
I don't understand from your code why it doesn't work, have you tried to follow firebase's guide to the letter? It never gave me problems.
I'm trying to send push notifications to the iPhone 6s I am using for testing. I've followed through the Firebase documentation and I can't seem to get a notification arrive to the phone. When I try to send a test notification with the FCM token I get after registering, it is classed as "sent" on the firebase console but not "received".
The minimum software version for the app is iOS 13 so I haven't added the deprecated functions for the notification service.
I've tried:
Disabling and reenabling the push notification and background task capabilities in xcode
Created new certificates and provisioning profiles using the capabilities
Uninstalling the app from the phone and reinstalling it
Setting FirebaseAppDelegateProxyEnabled to NO and YES in the Info.plist file
Writing and running the cloud function that will be used to send the notification which runs as "ok" according to the firebase console
Cleaning the build folder
Using all of the tokens that are returned on registering
Any help would be greatly appreciated,
Thanks in advance :)
App Delegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
db = Firestore.firestore()
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
print("granted: (\(granted)")
}
application.registerForRemoteNotifications()
Messaging.messaging().delegate = self
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print("Error fetching remote instance ID: \(error)")
} else if let result = result {
print("Remote instance ID token: \(result.token)")
}
}
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
GADMobileAds.sharedInstance().start(completionHandler: nil)
self.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
UserDefaults.standard.setValue(false, forKey: "backing_up")
let user = Auth.auth().currentUser
let email = user?.email
let password = UserDefaults.standard.string(forKey: "password")
let setup = UserDefaults.standard.bool(forKey: "accountSetup")
let credential = EmailAuthProvider.credential(withEmail: email ?? "", password: password ?? "")
user?.reauthenticate(with: credential)
if (user?.isEmailVerified ?? false) && setup {
let homeVC = mainStoryboard.instantiateViewController(withIdentifier: "MainViewController")
self.window?.rootViewController = homeVC
self.window?.makeKeyAndVisible()
} else {
do {
try Auth.auth().signOut()
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
let loginVC = mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController")
self.window?.rootViewController = loginVC
self.window?.makeKeyAndVisible()
}
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().setAPNSToken(deviceToken, type: .prod)
Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
UserDefaults.standard.synchronize()
print("token: \(token)")
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("failed to register for remote notifications with with error: \(error)")
}
// If in foreground
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
// Print message ID.
print("Message ID: \(userInfo["gcm.message_id"]!)")
// Print full message.
print("%#", userInfo)
completionHandler([.alert, .sound])
}
// If in background
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("handling notification")
if let notification = response.notification.request.content.userInfo as? [String:AnyObject] {
let message = parseRemoteNotification(notification: notification)
print(message as Any)
}
completionHandler()
}
private func parseRemoteNotification(notification:[String:AnyObject]) -> String? {
if let identifier = notification["identifier"] as? String {
return identifier
}
return nil
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
FINALLY! I tried to fix the issue by just starting from scratch and began creating another app. Halfway through the process, I found that I hadn't uploaded a .p8 file to Firebase for the app I was trying to get notifications to work for (I thought I had but apparently not).
If you have the same problem, check if your app is properly registered with Firebase on the console for cloud messaging!
in my case, I am using FCM for push notification I did all the code in the app delegate but problem is that when I send the notification from fcm it works successfully but when I trigger from the PHP side this not working and "didReceiveRemoteNotification" is not executing.
this is code which I have done.
import Firebase
import FirebaseMessaging
import FirebaseInstanceID
import UserNotifications
import BRYXBanner
#available(iOS 10.0, *)
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate,MessagingDelegate {
var window: UIWindow?
var strDeviceToken:String = ""
var isView = ""
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (isGranted, err) in
guard isGranted else { return }
self.getNotificationSettings()
if err != nil {
//Something bad happend
} else {
print(" if err != nil else......")
UNUserNotificationCenter.current().delegate = self
Messaging.messaging().delegate = self
DispatchQueue.main.async {
UNUserNotificationCenter.current().delegate = self
UIApplication.shared.registerForRemoteNotifications()
}
}
}
UIApplication.shared.registerForRemoteNotifications()
FirebaseApp.configure()
if Global.isInternetAvailable(){
}else{
Global.showAlertMessageWithOkButtonAndTitle(GlobalConstant.APP_NAME, andMessage: "Check Your Internet")
}
IQKeyboardManager.shared.enable = true
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
IQKeyboardManager.shared.enableAutoToolbar = true
// create viewController code...
let storyboard = UIStoryboard(name: "Main", bundle: nil)
/// Introduction Navigation Controller
let TeamViewController = storyboard.instantiateViewController(withIdentifier: "swr1") as! SWRevealViewController
let BossViewController = storyboard.instantiateViewController(withIdentifier: "swr") as! SWRevealViewController
/// Login Navigation Controller
let selectUserTypeViewController = storyboard.instantiateViewController(withIdentifier: "SlideShow") as! SlideShowViewController
self.window?.makeKeyAndVisible()
// Frist Launch of App check the NSUserDefault
let isFirstLaunch = UserDefaults.standard.string(forKey: GlobalConstant.kkIsLogin) == nil
if (isFirstLaunch)
{
UserDefaults.standard.set("00", forKey: GlobalConstant.kkIsLogin)
UserDefaults.standard.synchronize()
}
// Check the isLogin
let isUser = Global.getStringValue(UserDefaults.standard.value(forKey: "user_type") as AnyObject)
print(isUser)
if UserDefaults.standard.value(forKey: GlobalConstant.kkIsLogin) as! String == "1"
{
if isUser == "t"{
self.window?.rootViewController?.present(TeamViewController, animated: true, completion: nil)
}else{
self.window?.rootViewController?.present(BossViewController, animated: true, completion: nil)
}
}
else if UserDefaults.standard.value(forKey: GlobalConstant.kkIsLogin) as! String == "00"
{
UserDefaults.standard.set("0", forKey: GlobalConstant.kkIsLogin)
UserDefaults.standard.synchronize()
self.window?.rootViewController?.present(selectUserTypeViewController, animated: true, completion: nil)
}
else
{
UserDefaults.standard.synchronize()
self.window?.rootViewController?.present(selectUserTypeViewController, animated: true, completion: nil)
}
// Override point for customization after application launch.
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String)
{
print("Firebase registration token::::::?????????????: \(fcmToken)")
UserDefaults.standard.set(fcmToken, forKey: "deviceToken>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async(execute: { UIApplication.shared.registerForRemoteNotifications() })
}
}
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
Messaging.messaging().apnsToken = deviceToken as Data
}
func applicationWillResignActive(_ application: UIApplication) {
}
func applicationDidEnterBackground(_ application: UIApplication) {
Messaging.messaging().shouldEstablishDirectChannel = true//false
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
UIApplication.shared.applicationIconBadgeNumber = 0
}
func applicationWillTerminate(_ application: UIApplication) {
}
// 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 application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void)
{
print("didReceiveRemoteNotificationv User Info = ",userInfo)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadChatTableView"), object: nil)
GlobalConstant.notificationDict = userInfo
let notificationDictionary: NSDictionary = GlobalConstant.notificationDict?["aps"] as! NSDictionary
let type: String = Global.getStringValue(notificationDictionary.value(forKey: "type") as AnyObject)
// application.applicationIconBadgeNumber = application.applicationIconBadgeNumber + 1
completionHandler(UIBackgroundFetchResult.noData)
var aps: [AnyHashable: Any] = userInfo["aps"] as! [AnyHashable : Any]
/// Check the isLogin
if UserDefaults.standard.value(forKey: GlobalConstant.kkIsLogin) as! String == "1"
{
if UIApplication.shared.applicationState == .inactive || UIApplication.shared.applicationState == .background
{ }
}
else
{
let mainStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let loginNav: UINavigationController = UINavigationController(nibName: "LoginNavigationController", bundle: nil)
let loginViewController = mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
loginNav.viewControllers = [loginViewController]
self.window?.rootViewController = loginNav
}
}
// MARK:- UNUserNotificationCenter Delegate // >= iOS 10
//Called when a notification is delivered to a foreground app.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print(" willPresent User Info = ",notification.request.content.userInfo)
completionHandler([.alert, .badge, .sound])
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "reloadChatTableView"), object: nil)
UIApplication.shared.applicationIconBadgeNumber = UIApplication.shared.applicationIconBadgeNumber + 1
var aps: [AnyHashable: Any] = notification.request.content.userInfo["aps"] as! [AnyHashable : Any]
/// Check the isLogin
if UserDefaults.standard.value(forKey: GlobalConstant.kkIsLogin) as! String == "1"
{
} //====
else
{
let mainStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let loginNav: UINavigationController = UINavigationController(nibName: "LoginNavigationController", bundle: nil)
let loginViewController = mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
loginNav.viewControllers = [loginViewController]
self.window?.rootViewController = loginNav
}
}
//Called to let your app know which action was selected by the user for a given notification.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("didReceive User Info = ",response.notification.request.content.userInfo)
completionHandler()
var aps: [AnyHashable: Any] = response.notification.request.content.userInfo["aps"] as! [AnyHashable : Any]
// UIApplication.shared.applicationIconBadgeNumber = UIApplication.shared.applicationIconBadgeNumber + 1
/// Check the isLogin
if UserDefaults.standard.value(forKey: GlobalConstant.kkIsLogin) as! String == "1"
{
if UIApplication.shared.applicationState == .inactive || UIApplication.shared.applicationState == .background
{
}
else
{
let banner = Banner(title:GlobalConstant.APP_NAME , subtitle: aps["alert"] as? String, image: #imageLiteral(resourceName: "image-3"), backgroundColor: Global.hexStringToUIColor("#F3AF41"))
banner.springiness = .heavy
banner.position = .top
banner.didTapBlock =
{
}
banner.show(duration: 3.0)
}
}
else
{
let mainStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let loginNav: UINavigationController = UINavigationController(nibName: "LoginViewController", bundle: nil)
let loginViewController = mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
loginNav.viewControllers = [loginViewController]
self.window?.rootViewController = loginNav
}
}
}
I have implemented Push Notification using FCM.
When my app is in the foreground and a notification arrive then didReceiveRemoteNotification method is called but when the app is not active it doesn't call this method
I am checking this by setting a bool value to true when app is in background but doesn't change the bool it means it doesn't execute this line..
Here is my method.
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
self.application(application, didReceiveRemoteNotification: userInfo) { (UIBackgroundFetchResult) in
if UIApplication.sharedApplication().applicationState != .Active{
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "AriveNotification")
NSUserDefaults.standardUserDefaults().synchronize()
}else{
NSUserDefaults.standardUserDefaults().setBool(false, forKey: "AriveNotification")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
if UIApplication.sharedApplication().applicationState != .Active{
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "AriveNotification")
NSUserDefaults.standardUserDefaults().synchronize()
}else{
NSUserDefaults.standardUserDefaults().setBool(false, forKey: "AriveNotification")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
completionHandler(.NewData)
}
For Registering GCM Push Notification i use these method when user sign in successfully.
func userDidLoggedIn() -> Void {
tabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! VaboTabBarController
self.window?.rootViewController = self.tabBarController
self.window?.makeKeyAndVisible()
self.registerDeviceForPushNotification(UIApplication.sharedApplication())
}
func connectToFcm() {
FIRMessaging.messaging().connectWithCompletion({error in
if (error != nil) {
print("Unable to connect with FCM. \(error)")
} else {
print("Connected to FCM.")
}
})
}
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox)
}
func registerDeviceForPushNotification(application:UIApplication) -> Void {
let settings: UIUserNotificationSettings = UIUserNotificationSettings.init(forTypes: [.Alert,.Badge,.Sound], categories: nil)
self.pushNotificationToken = FIRInstanceID.instanceID().token()!
let userID = self.userData["id"] as! NSNumber
print("InstanceID token: \(self.pushNotificationToken)")
self.registerDeviceOnServerWith(self.pushNotificationToken, userID: userID)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
func tokenRefreshNotification(notification: NSNotification) {
if let refreshedToken = FIRInstanceID.instanceID().token() {
let userID = self.userData["id"] as! NSNumber
self.registerDeviceOnServerWith(refreshedToken, userID: userID)
print("InstanceID token: \(refreshedToken)")
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
PS. I have set Remote-Notification check from capabilities as well as in info.plist. Plus i also have tried by adding "content-available":1 from the notification payload.
You have to write the correct spelling and character placement in Notification Payload.
As per your statement you might have placed incorrect character in content available place.
Please send your payload in this format..
{
"aps":{
"alert":{
"title":"Notification Title Text",
"Body" :"Notification Body",
"content_available":1
}
}
}
You have written content-available it should be content_availble. Now this will wake your app to run your logic in the background as well