tried to solve this myself. spent like an hour or so still no result.
Got me old code of a previous project regarding FCM. however the code was and still working on it's app. though i managed to transfer the code to my new project. but it won't work here.
Now i know APN's are weird and complicated. but it's more of a memorized situation for me.
Things i have done:
- Uploaded my personal .p12 to my firebase project
- Enabled "Push Notifications" in app capabilities
- Imported and used UserNotifications framework on appdelegate.swift
Here's how my AppDelegate look like:
import UIKit
import Firebase
import FirebaseFirestore
import StoreKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
override init() {
super.init()
FirebaseApp.configure()
// not really needed unless you really need it FIRDatabase.database().persistenceEnabled = true
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
Auth.auth().signInAnonymously() { (authResult, error) in
// ...
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
UIApplication.shared.statusBarStyle = .default
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "gateway") as! gatewayViewController
window!.rootViewController = viewController
return true
}
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.
}
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(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(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
Okay so with this code you get the devices Firebase registration token, i copied my code and used it on Cloud Functions to send a test message, here's how my CF looks like:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.helloWorld = functions.https.onRequest((request, response) => {
var registrationToken = 'f8fWx_sANVM:APA91bEd46drxiBvHLZd5YKVClQr91oubzJKOyXE1LNgxOsi3ihUw31yEJL6prHKm-A83B1N1sr2GOff3P9tUsRNhCpG7_VMRlDUDfthIcwkDUgzKPV5NZtlo6pcpxsvD9ZgYlPqibNp';
var payload = {
notification: {
title: "just published new Word",
body: "Hii",
}
};
// registration token.
admin.messaging().sendToDevice(registrationToken, payload)
.then(function(response) {
// See the MessagingDevicesResponse reference documentation for
// the contents of response.
return console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
});
Okay so far after hitting the helloWorld url, my console gets this:
Successfully sent message: { results: [ { messageId: '0:1537714204565821%b3b8835bb3b8835b' } ],
canonicalRegistrationTokenCount: 0,
failureCount: 0,
successCount: 1,
multicastId: 8154206809408282000 }
Function execution took 60002 ms, finished with status: 'timeout'
Last time on my previous project it took 20ms at it's very best. I still can't figure this out. Your help is greatly appreciated
You're using a HTTP(S) triggered Cloud Function, which means your code must send a response. Since your code doesn't do that, the function runs for 60s and then gets terminated by the Cloud Functions environment. This means you pay for more time than you actually need, so you'll want to fix it.
For example:
// registration token.
admin.messaging().sendToDevice(registrationToken, payload)
.then(function(response) {
// See the MessagingDevicesResponse reference documentation for
// the contents of response.
//return console.log("Successfully sent message:", response);
res.status(200).send(response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
This will get rid of the message in the Cloud Functions logs, and ensures you only pay for the time you actually need.
Related
I'm adding Firebase Cloud Messaging in an iOS app (iOS 15.2.1 on a 7th Gen iPad), and I am able to get it to work, but have taken a step that the Firebase docs don't specify, and I don't understand why it's working and why it doesn't work when I don't do this.
First, I'm following these Firebase docs. These docs make no mention of needing to have an application:didRegisterForRemoteNotificationsWithDeviceToken method in the App Delegate. However, if I don't have this method present, I consistently get this error spewed to the console whenever I try to access the token with Messaging.messaging().token:
2022-01-31 22:00:57.448319-0800 authNavFirebaseUISample[4755:1363959] 8.10.0 - [Firebase/Messaging][I-FCM002022] APNS device token not set before retrieving FCM Token for Sender ID 'XXXXXXXXXXXX'. Notifications to this FCM Token will not be delivered over APNS.Be sure to re-retrieve the FCM token once the APNS device token is set.
When I do add in this method, I no longer get that error when accessing the token via Messaging.messaging().token. Furthermore, when this method is present, I can successfully send test notifications via the Notification Composer.
What's particularly strange about all of this is that the actual application:didRegisterForRemoteNotificationsWithDeviceToken is never actually invoked. However, its presence is required and without it, I get that error spew and Notification Composer doesn't work.
I've added relevant code snippets below. Any ideas? Thanks!
App Delegate
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
NotificationHelpers.setupRemoteNotifications(application)
return true
}
// NOTE: Why is this needed?!?!
// If this method isn't present, each time we try to retrieve the FCM (Firebase Cloud
// Messaging) token, we get:
// APNS device token not set before retrieving FCM Token for Sender ID 'XXXXXXXXXXXX'. Notifications to
// this FCM Token will not be delivered over APNS.Be sure to re-retrieve the FCM token once the APNS
// device token is set.
// Adding this method prevents that. However, the method never actually gets executed. (Try putting a
// print statement in there, it won't print.) But if you remove the method, then we get the above error.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
}
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
let sceneConfig = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
sceneConfig.delegateClass = MySceneDelegate.self
return sceneConfig
}
}
NotificationHelpers
class NotificationHelpers {
static func setupRemoteNotifications(_ application: UIApplication) -> Void {
let delegate = NotificationsDelegate()
// For iOS 10 and above display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = delegate
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: { _, _ in }
)
application.registerForRemoteNotifications()
Messaging.messaging().delegate = delegate
}
}
Token accessing code (invoked from button press in app)
Button("retrieve FCM") {
// Get token here, but really can be from anywhere
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)")
}
}
}
After reading about this extensively, I cannot find the solution. I am sending cloud messages from Firebase to my ios app, but the method didReceiveRemoteNotification() is not being called at all, not when the app is in foreground and not in background. I tried sending from the firebase console, and also from postman using topics, and both don't work. I have integrated Firebase in the app, and uploaded certificate to Firebase, and I get no errors in the console. Just the notification isn't coming? I also added the capability of cloud messages.
This is what I do (from the Firebase tutorial) in appDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
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
return true
}
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(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(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
Disable Method swizzling and everything should work fine.
According to the documentation https://firebase.google.com/docs/cloud-messaging/ios/client#token-swizzle-disabled
If you have disabled method swizzling, or you are building a SwiftUI app, you'll need to explicitly map your APNs token to the FCM registration token. Implement the application(_:didRegisterForRemoteNotificationsWithDeviceToken:) method to retrieve the APNs token, and then set Messaging's apnsToken property
It also mentions here https://firebase.google.com/docs/cloud-messaging/ios/receive#handle_messages_with_method_swizzling_disabled
By default, if you assign your app's app delegate class to the UNUserNotificationCenter and Messaging delegate properties, FCM will swizzle your app delegate class to automatically associate your FCM token with the device's APNs token and pass notification-received events to Analytics. If you explicitly disable method swizzling, if you are building a SwiftUI app, or if you use a separate class for either delegate, you will need to perform both of these tasks manually.
Mapping apnToken and deviceToken is to be done at various places thus it's advised to read the documentation completely and apply the necessary changes.
In a Swift 3 app, implementing Firebase 4 for notifications and a WKWebView for displaying an Angular web app I've come to a point where I can receive app notifications from Firebase and get an alert in the Notification Centre.
But when attempting to get app notifications from my server I only end up having them displayed in the console when running the app, but the phone does not display notifications at all.
I'm suspecting an issue with the way the messages from my server are formatted, below is the console output from a successful alert from Firebase:
[AnyHashable("google.c.a.e"): 1, AnyHashable("google.c.a.ts"): 1504280715, AnyHashable("google.c.a.udt"): 0, AnyHashable("gcm.n.e"): 1, AnyHashable("aps"): {
alert = "This one works";
}, AnyHashable("google.c.a.c_id"): 7239776096663233136,
AnyHashable("gcm.message_id"): 0:1504280715823529%dc6002bbdc6002bb]
And here is a sample from my own app server, which does not display as a phone notification:
[AnyHashable("from"): 1001513747966, AnyHashable("body"): Urgent action
is needed to prevent your account from being disabled!,
AnyHashable("title"): Urgent action needed!]
Message ID: 0:1504280715823529%dc6002bbdc6002bb
I'm testing this on ios10 devices, only.
My AppDelegate.swift file looks like this:
import UIKit
import CoreData
import Fabric
import Crashlytics
import Firebase
import FirebaseMessaging
import UserNotifications
import FirebaseInstanceID
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let gcmMessageIDKey = "gcm.message_id"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
// [START set_messaging_delegate]
Messaging.messaging().delegate = self as MessagingDelegate
// [END set_messaging_delegate]
// Register for remote notifications. This shows a permission dialog on first run, to
// show the dialog at a more appropriate time move this registration accordingly.
// [START register_for_notifications]
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)
}
Messaging.messaging().shouldEstablishDirectChannel = true
application.registerForRemoteNotifications()
// [END register_for_notifications]
Fabric.with([Crashlytics.self])
return true
}
// [START receive_message]
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
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
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
Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
// [END receive_message]
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Unable to register for remote notifications: \(error.localizedDescription)")
}
// This function is added here only for debugging purposes, and can be removed if swizzling is enabled.
// If swizzling is disabled then this function must be implemented so that the APNs token can be paired to
// the InstanceID token.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("APNs token retrieved: \(deviceToken)")
// With swizzling disabled you must set the APNs token here.
Messaging.messaging()
.setAPNSToken(deviceToken, type: MessagingAPNSTokenType.unknown)
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
Messaging.messaging().shouldEstablishDirectChannel = true
}
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) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
//connectToFirebaseMessaging()
UIApplication.shared.applicationIconBadgeNumber = 0
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "ViDent")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
// [START ios_10_message_handling]
#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(userInfo)
// Change this to your preferred presentation option
completionHandler([])
}
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)")
}
// Print full message.
print(userInfo)
completionHandler()
}
}
// [END ios_10_message_handling]
extension AppDelegate : MessagingDelegate {
// [START refresh_token]
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
}
// [END refresh_token]
// [START ios_10_data_message]
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
// To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
print("Received data message: \(remoteMessage.appData)")
}
// [END ios_10_data_message]
And it is the print("Received data message: (remoteMessage.appData) at the very end of the AppDelegate.swift file which triggers and prints the message to the console, so I just need to work out how to pass these messages on so an alert is triggered on the device.
I've tried everything to get the alerts to pop up while in the background. I receive the data when app is open or while launching. Because I receive the notifications I'm assuming it's in my AppDelegate code or perhaps something wrong in my .plist??? I've followed a few of the standard tutorials on firebase notifications, all this code is from those tutorials.
import UIKit
import CoreData
import Firebase
import UserNotifications
import FirebaseInstanceID
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
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().delegate = self
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
// Override point for customization after application launch.
NotificationCenter.default.addObserver(self, selector: #selector(self.tokenRefreshNotification(_:)),
name: NSNotification.Name.InstanceIDTokenRefresh, object: nil)
return true
}
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
print("refreshed token")
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
// Messaging.messaging().disconnect()
// print("Disconnected from FCM.")
}
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) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
connectToFcm()
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "firetail")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
#objc private func tokenRefreshNotification(_ notification: Notification) {
if let refreshedToken = InstanceID.instanceID().token() {
print("InstanceID token: \(refreshedToken)")
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
func connectToFcm() {
// Won't connect since there is no token
guard InstanceID.instanceID().token() != nil else {
return
}
// Disconnect previous FCM connection if it exists.
Messaging.messaging().disconnect()
Messaging.messaging().connect { (error) in
if error != nil {
print("Unable to connect with FCM. \(error?.localizedDescription ?? "")")
} else {
print("Connected to FCM.")
}
}
}
public func application(received remoteMessage: MessagingRemoteMessage) {
print(remoteMessage.appData)
}
}
A few things to note:
The simulator cannot receive push notifications.
You must have push notifications and background modes (remote notifications & background fetch) enabled in your project's capabilities.
Try adding these lines of code to your app delegate:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// Will not be called until you open your application from the remote notification (returns to foreground)
// Note: *with swizzling disabled you must let Messaging know about the message
// Messaging.messaging().appDidReceiveMessage(userInfo)`
// Print message ID.
if let messageId = userInfo["gcm.message_id"] {
print("Message Id: \(messageId)")
}
// Print full message.
print(userInfo)
Messaging.messaging().appDidReceiveMessage(userInfo)
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// Will not be called until you open your application from the remote notification (returns to foreground)
// Note: *with swizzling disabled you must let Messaging know about the message
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message id
if let messageId = userInfo["gcm.message_id"] {
print("Message Id: \(messageId)")
}
// Print full message.
print(userInfo)
Messaging.messaging().appDidReceiveMessage(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
I also noticed you map your APNS token to Messaging (in didRegisterForRemoteNotificationsWithDeviceToken) using :
Messaging.messaging().apnsToken = deviceToken
I would try your luck replacing it with the following:
Messaging.messaging().setAPNSToken(deviceToken, type: MessagingAPNSTokenType.sandbox)
Messaging.messaging().setAPNSToken(deviceToken, type: MessagingAPNSTokenType.prod)
Good luck!
Be sure to send your messages through Firebase with the high priority setting instead of the standard/default priority.
I have been trying to create a Tinder clone app. Right now I have to login to my Facebook account, grab my profile and show my display picture.
I have imported the latest FBSDK, confirgured my plist (Plist screenshot) correctly and used the graphRequest function to pull my profile picture but I keep getting the following error.
-canOpenURL: failed for URL: "fbauth2:/" - error: "(null)"
I have cleaned my build, restarted my simulator, restarted my machine and completely commented out my parse code.
I have uncommented all my parse code (which I am deploying through Heroku) so as not to simplify the code.
I have Googled the problem and searched stack overflow and github for over 2 weeks and have yet to find a solution.
I have read comments about how this problem is a red herring due to Facebooks SDK integration with iOS 9.
I want to know what I am doing wrong. I am new to coding and need some help. All I want to achieve right now is to login to my Facebook account (which I can do), authorise my app (which I can also do) and see my profile picture in the UiImageView (which I can NOT do). This way I can keep building the app along with my course.
/**
* Copyright (c) 2015-present, Parse, LLC.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
//current project 02-04-16
import UIKit
import Parse
import Bolts
import FBSDKCoreKit
import FBSDKLoginKit
import ParseFacebookUtilsV4
// If you want to use any of the UI components, uncomment this line
// import ParseUI
// deleted parseFacebookUtils and added ParseFacebookUtilsV4 so that PFFacebookUtils.intializeFacebookWithLaunchOptions would work. Replace parseFacebookUtils if needed to go back to old code (19-04-16).
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//--------------------------------------
// MARK: - UIApplicationDelegate
//--------------------------------------
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Enable storing and querying data from Local Datastore.
// Remove this line if you don't want to use Local Datastore features or want to use cachePolicy.
// Parse.enableLocalDatastore()
//
// let parseConfiguration = ParseClientConfiguration(block: { (ParseMutableClientConfiguration) -> Void in
//
// ParseMutableClientConfiguration.applicationId = "tinder9121hughglass1234"
// ParseMutableClientConfiguration.clientKey = "sam123456hibabina"
// ParseMutableClientConfiguration.server = "https://tinder-sam2.herokuapp.com//parse"
PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)
// Uncomment these lines if you want to enable Parse
// PFUser.enableAutomaticUser()
//
//
// PFUser.logOut()
// let defaultACL = PFACL();
//this is the current project 23-03-16
// PFUser.enableAutomaticUser()
// Parse.setApplicationId("tinder9121hughglass1234", clientKey: "sam123456hibabina")
//this code has been // temporarily 05-04-16 ***
//
// let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
// fbLoginManager.logInWithReadPermissions(["public_profile"], handler: { (result, error) in
//
//
// })
//
// PFUser.enableAutomaticUser()
//
//
// })
// edited again here!
// let PFObject = PFUser.currentUser()
//
// PFUser.enableAutomaticUser()
//
// let acl = PFACL()
// acl.publicReadAccess = true
// acl.publicWriteAccess = true
// PFObject?.ACL = acl
// let defaultACL = PFACL();
// If you would like all objects to be private by default, remove this line.
// defaultACL.publicReadAccess = true
// PFACL.setDefaultACL(defaultACL, withAccessForCurrentUser: true)
if application.applicationState != UIApplicationState.Background {
// Track an app open here if we launch with a push, unless
// "content_available" was used to trigger a background push (introduced in iOS 7).
// In that case, we skip tracking here to avoid double counting the app-open.
let preBackgroundPush = !application.respondsToSelector("backgroundRefreshStatus")
let oldPushHandlerOnly = !self.respondsToSelector("application:didReceiveRemoteNotification:fetchCompletionHandler:")
var noPushPayload = false;
if let options = launchOptions {
noPushPayload = options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil;
}
if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) {
PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)
}
}
//
// Swift 1.2
//
// if application.respondsToSelector("registerUserNotificationSettings:") {
// let userNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound
// let settings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil)
// application.registerUserNotificationSettings(settings)
// application.registerForRemoteNotifications()
// } else {
// let types = UIRemoteNotificationType.Badge | UIRemoteNotificationType.Alert | UIRemoteNotificationType.Sound
// application.registerForRemoteNotificationTypes(types)
// }
//
// Swift 2.0
//
// if #available(iOS 8.0, *) {
// let types: UIUserNotificationType = [.Alert, .Badge, .Sound]
// let settings = UIUserNotificationSettings(forTypes: types, categories: nil)
// application.registerUserNotificationSettings(settings)
// application.registerForRemoteNotifications()
// } else {
// let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound]
// application.registerForRemoteNotificationTypes(types)
// }
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
//--------------------------------------
// MARK: Push Notifications
//--------------------------------------
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let installation = PFInstallation.currentInstallation()
installation.setDeviceTokenFromData(deviceToken)
installation.saveInBackground()
PFPush.subscribeToChannelInBackground("") { (succeeded: Bool, error: NSError?) in
if succeeded {
print("ParseStarterProject successfully subscribed to push notifications on the broadcast channel.\n");
} else {
print("ParseStarterProject failed to subscribe to push notifications on the broadcast channel with error = %#.\n", error)
}
}
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
if error.code == 3010 {
print("Push notifications are not supported in the iOS Simulator.\n")
} else {
print("application:didFailToRegisterForRemoteNotificationsWithError: %#\n", error)
}
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
PFPush.handlePush(userInfo)
if application.applicationState == UIApplicationState.Inactive {
PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo)
}
}
///////////////////////////////////////////////////////////
// Uncomment this method if you want to use Push Notifications with Background App Refresh
///////////////////////////////////////////////////////////
// func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
// if application.applicationState == UIApplicationState.Inactive {
// PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo)
// }
// }
//--------------------------------------
// MARK: Facebook SDK Integration
//--------------------------------------
///////////////////////////////////////////////////////////
// Uncomment this method if you are using Facebook
///////////////////////////////////////////////////////////
// func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool {
// return FBAppCall.handleOpenURL(url, sourceApplication:sourceApplication, session:PFFacebookUtils.session())
// }
func applicationDidBecomeActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
}
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?,
annotation: AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
}
Try add this line into your Info.plist: <string>fbauth2</string>