I am facing some issues with push notifications. We are using Firebase for Push Notificaions. The thing is I am able to receive PushNotifications properly on one iPhone but can’t get them on another iPhone. And I am getting Notifications properly on Android.
What I am doing is Signing-In from a same account and trying push notifications. What is happening is am getting on all android phones, on my iPhone 5S most of all but very few on my iPhone 6.
Here is the code which is used in AppDelegate for setting up the connection.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
InstanceID.instanceID().setAPNSToken(deviceToken, type: InstanceIDAPNSTokenType.sandbox)
}
#objc func tokenRefreshNotification(notification: Notification){
print("entered tokenRefreshNotification")
let refreshedToken = InstanceID.instanceID().token()
if refreshedToken != nil{
UserDefaults.standard.setValue(refreshedToken, forKey: "token")
}
//UserDefaults.standard.setValue(refreshedToken, forKey: "token")
print("Instance ID token: \(String(describing: refreshedToken))")
connectToFCM()
}
func connectToFCM(){
Messaging.messaging().connect { (error) in
if error != nil{
self.print("Unable to connect to FCM \(String(describing: error))")
return
}
self.print("connected to FCM")
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print("application did receive remote notification")
print(userInfo)
let notification = UILocalNotification()
notification.fireDate = Date()
let notificationType = (userInfo["type"] as! String).lowercased()
switch notificationType {
case "alert" :
print("Show notifications and save in the notifications list.")
notification.alertBody = userInfo["message"] as? String
//code for saving to user defaults
if var notifications = userDefaults.value(forKey: keys.notificationsList) as? [String] {
if let notificationString = notification.alertBody{
notifications.append(notificationString)
userDefaults.setValue(notifications, forKey: keys.notificationsList)
}
} else{
//in case of empty notificationList
if let notificationString = notification.alertBody{
let notifications = [notificationString]
userDefaults.setValue(notifications, forKey: keys.notificationsList)
}
}
//notifications.append(notification.alertBody)
UIApplication.shared.scheduleLocalNotification(notification)
case "advertisement" :
print("Just show the notification and do nothing else.")
notification.alertBody = userInfo["message"] as? String
UIApplication.shared.scheduleLocalNotification(notification)
case "cleardb":
print("Clear everything from Database, but not logout user.")
notification.alertBody = "All data from database had been wiped"
UIApplication.shared.scheduleLocalNotification(notification)
case "update_device":
print("device_data has been updated so download devices info again")
case "logout":
print("logout the user")
Functions.functions.wipeUserDefaults()
notification.alertBody = "Logged out of Ryoking"
UIApplication.shared.scheduleLocalNotification(notification)
default:
print("lol")
}
}
func application(received remoteMessage: MessagingRemoteMessage) {
print("application received remote message")
print(remoteMessage.appData)
}
I have followed this steps from firebase console literally and it works for me like a charm, try it out:
https://firebase.google.com/docs/cloud-messaging/ios/first-message?authuser=0
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!
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!
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.
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
Ok so my push notification work like a charm when the app is running in the foreground. But when ever I enter into the background, the app never receives the push notification. Its like the notification falls on deaf ears.
So this is what happening. When the app is first started, I can received notification. When I close and reopen the app I can receive notification. But when the app is closed in the background I cannot receive notification. I print off when the app goes into the background and when the app becomes active so I know that its not closing I think. Because its printing that its going into the background, so it should be running.
So this is what I have for the app deligate class:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//OTHER THINGS
//Open the Push note page
if launchOptions != nil
{
print(launchOptions)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier(myPage)
self.window?.rootViewController = vc
}
//handel push note if app is closed
//Sends it to the regular handler for push notifcaiton
//didrecivepushnotificaiton
if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary
{
print("Got A Push Note when I was closed")
self.application(application, didReceiveRemoteNotification: remoteNotification as [NSObject : AnyObject])
}
}
func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
deviceToken: NSData ) {
print("DEVICE TOKEN = \(deviceToken)")
//convert the device token into a string
let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
var token = ""
for i in 0..<deviceToken.length {
token += String(format: "%02.2hhx", arguments: [tokenChars[i]])
}
print("token: " + token)
//store the user device token for apns push notification
loginInformation.setObject(token, forKey: "token")
self.loginInformation.synchronize()
}
// [START ack_message_reception]
func application( application: UIApplication,
didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print("Recived Push Notificaion")
var myMess :String = ""
var url : String = ""
var myTitle : String = ""
if var alertDict = userInfo["aps"] as? Dictionary<String, String> {
print("Alert Dict")
print(alertDict)
url = alertDict["url"]!
myMess = alertDict["alert"]!
myTitle = alertDict["mytitle"]!
//store the url for the push control view
loginInformation.setObject(url, forKey: "URL")
loginInformation.setObject(myMess, forKey: "Message")
loginInformation.setObject(myTitle, forKey: "Title")
self.loginInformation.synchronize()
}else{print("No go")}
application.applicationIconBadgeNumber = 0
//post notification.
NSNotificationCenter.defaultCenter().postNotificationName("PushReceived", object: nil, userInfo: userInfo)
if myTitle == ""
{
myTitle = “New Title“
}
if myMess == ""
{
myMess = “All Hail Gus“
}
let alert = UIAlertController(title: myTitle, message: myMess, preferredStyle: UIAlertControllerStyle.Alert)
//Close Button
alert.addAction(UIAlertAction(title: "次回", style: UIAlertActionStyle.Default, handler: nil))
self.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
}
func registrationHandler(registrationToken: String!, error: NSError!) {
}
// [START receive_apns_token_error]
func application( application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
error: NSError ) {
print(error)
}
I think I have all the right setting on this too. But I am not too sure now. The push notifications did work but I made a lot of changes and haven't tested them in a while.
And this is an example of the payload
{"aps":{"alert":"Gus Message.","badge":"1", "url":"https://www.gus.com","mytitle":"Gus Title"}}
To fully implement APNS servie, u have to handle three cases:
inactive
foreground
background
the inactive mode should be handled in didFinishLaunchingWithOptions method
//receive apns when app in inactive mode, remaining message hint display task could be sum up by the code in applicationwillenterforeground
if let options = launchOptions {
if options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil {
let userInfo: NSDictionary = options[UIApplicationLaunchOptionsRemoteNotificationKey] as! NSDictionary
let apsInfo: NSDictionary = userInfo["aps"] as! NSDictionary
//parse notification body message ...
NSNotificationCenter.defaultCenter().postNotificationName(APP_NOTIF_RECEIVE_REMOTE_NOTIF, object: userInfo)
APService.handleRemoteNotification(userInfo as! [NSObject : AnyObject])
//Update badge number
let badgeIndex = apsInfo["badge"] as! Int
UIApplication.sharedApplication().applicationIconBadgeNumber = badgeIndex
}
}
} else if options[UIApplicationLaunchOptionsURLKey] != nil {
if let url = launchOptions?[UIApplicationLaunchOptionsURLKey] as? NSURL {
print(url)
}
}
}
the remaining two cases should be handle in didReceiveRemoteNotification method
//receive apns when app in background mode
let apsInfo: NSDictionary = userInfo["aps"] as! NSDictionary
if UIApplication.sharedApplication().applicationState != UIApplicationState.Active{
//TODO: temporary method, need further update
//judge notification type
if let _ = userInfo["inviterName"] as? String {
//notification for group invite
}else{
//Update badge number
if let badgeInt = apsInfo["badge"] as? Int {
UIApplication.sharedApplication().applicationIconBadgeNumber = badgeInt > 0 ? badgeInt: 1
}else{
UIApplication.sharedApplication().applicationIconBadgeNumber = 1
}
//turn on trigger to enable message hint btn on recorder vc when it appear
NSUserDefaults.standardUserDefaults().setBool(true, forKey: REMOTE_NOTIF_REMAINING)
}
}
//receive apns when app in forground mode
else{
//TODO: temporary method, need further update
//judge notification type
if let _ = userInfo["inviterName"] as? String {
//notification for group invite
NSNotificationCenter.defaultCenter().postNotificationName(APP_NOTIF_RECEIVE_GROUP_NOTIF, object:nil)
}else{
//notificate recorder vc to display message hint directly
NSNotificationCenter.defaultCenter().postNotificationName(APP_NOTIF_RECEIVE_REMOTE_NOTIF, object: userInfo)
}
}
APService.handleRemoteNotification(userInfo)
completionHandler(UIBackgroundFetchResult.NewData)