OneSignal and latest xcode: app does not ask for push notifications - swift

I followed this guide to integrate the push notifications into my app:
https://documentation.onesignal.com/docs/ios-sdk-setup
I followed the guide step-by-step but my app does not request for sending notifications, once installed even in the options I can't see notification service.
I implemented everything on an existing app, my doubts are about the AppDelegate.swift file, this is the full code:
import UIKit
import CoreData
import OneSignal
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
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.
}
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.
}
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: "Web_Lebo")
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)")
}
}
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: true]
// Replace 'YOUR_APP_ID' with your OneSignal App ID.
OneSignal.initWithLaunchOptions(launchOptions,
appId: "[my-onesignal-id]",
handleNotificationAction: nil,
settings: onesignalInitSettings)
OneSignal.inFocusDisplayType = OSNotificationDisplayType.notification;
// Recommend moving the below line to prompt for push after informing the user about
// how your app will use them.
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
// Sync hashed email if you have a login system or collect it.
// Will be used to reach the user at the most optimal time of day.
// OneSignal.syncHashedEmail(userEmail)
return true
}

I noticed now that I did not paste the function in the right place, it's ok with this code:
import UIKit
import CoreData
import OneSignal
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: true]
// Replace 'YOUR_APP_ID' with your OneSignal App ID.
OneSignal.initWithLaunchOptions(launchOptions,
appId: "9ec7d060-b6b5-4cc5-a4d3-291748e2465b",
handleNotificationAction: nil,
settings: onesignalInitSettings)
OneSignal.inFocusDisplayType = OSNotificationDisplayType.notification;
// Recommend moving the below line to prompt for push after informing the user about
// how your app will use them.
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
// Sync hashed email if you have a login system or collect it.
// Will be used to reach the user at the most optimal time of day.
// OneSignal.syncHashedEmail(userEmail)
return true
}
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.
}
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.
}
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: "Web_Lebo")
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)")
}
}
}
}

Related

how to test in ios device about bgtaskscheduler function not using debug function

i have no problem when using debug function in my ios device not simulator.
(ex, e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:#"TASK_IDENTIFIER"] )
but when do not using debug function, follow my code, it will be play the music after 60 seconds going to background. however nothing to happen in the device.
how do i test the device not using debug function?
import UIKit
import BackgroundTasks
import os.log
import AVFoundation
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "AppDelegate")
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
let bgTaskIdentifier = "com.hakjun.bgTest.playMusic"
var alarmTime : Int = 0
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
BGTaskScheduler.shared.register(forTaskWithIdentifier: bgTaskIdentifier, using: nil) { task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
print("test bg")
}
return true
}
func scheduleAppRefresh(time : Double) {
let request = BGAppRefreshTaskRequest(identifier: bgTaskIdentifier)
request.earliestBeginDate = Date(timeIntervalSinceNow: time)
do {
try BGTaskScheduler.shared.submit(request)
print("schedule app refresh")
} catch {
print("Could not schedule app refresh task \(error.localizedDescription)")
}
}
func handleAppRefresh(task : BGAppRefreshTask){
scheduleAppRefresh(time: 60)
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
let appRefreshOperation = BlockOperation {
Singleton.sharedInstance.play()
}
// queue.addOperation(appRefreshOperation)
task.expirationHandler = {
print("expire background")
queue.cancelAllOperations()
}
let lastOperation = queue.operations.last
lastOperation?.completionBlock = {
task.setTaskCompleted(success: !(lastOperation?.isCancelled ?? false))
}
print("background handle")
queue.addOperation(appRefreshOperation)
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
func applicationDidEnterBackground(_ application: UIApplication) {
print("test bg os log2")
logger.log("App did enter background")
scheduleAppRefresh(time: 60)
}
}
class Singleton {
static let sharedInstance = Singleton()
private var player: AVAudioPlayer?
func play() {
let audioSession = AVAudioSession.sharedInstance()
guard let url = Bundle.main.url(forResource: "alarm2", withExtension: "mp3") else { return }
do {
try audioSession.setCategory(.playback, mode: .default, options: [])
} catch let error as NSError {
print("audioSession 설정 오류 : \(error.localizedDescription)")
}
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
guard let player = player else { return }
player.play()
} catch let error {
print(error.localizedDescription)
}
}
func stop() {
player?.stop()
}
}
FYI, BGAppResfreshTask is for “updating your app with small bits of information”, i.e., for performing a small network request to refresh your app so that, when the user next launches the app, you have more current information ready and waiting for them. But this app refresh is performed at a time chosen at the discretion of the OS, based upon many factors, but not earlier than earliestBeginDate.
Thus is not appropriate for an alarm clock because (a) you are not doing a network request to refresh your app; and (b) it is not guaranteed to run at the designated “earliest” date, only some time thereafter.
You might consider scheduling a user notification, instead.
You asked:
how do i test the device not using debug function?
You add logging statements. But rather than using print or NSLog, one would add Logger statements as discussed in WWDC 2020 Explore logging in Swift. (Or, if supporting iOS versions prior to iOS 14, use os_log; this was described in WWDC 2016 video Unified Logging and Activity Tracing, but that video is no longer available.) These Logger/os_log logging statements issued from an iOS app can be monitored from the macOS Console app.
So, once you have added your logging messages in your code in the relevant spots, using Logger (or os_log), you can then
install app on your device,
connect device to your computer,
launch the app directly from your device and
you can watch the log statements issued by your app in your macOS Console.
See points 3 and 4 in Swift: print() vs println() vs NSLog().
But note, you do not want to run the app from Xcode. You can install it by running it from Xcode, but then stop execution and re-launch the app directly on the device, not using Xcode. Unfortunately, being attached to the Xcode debugger keeps the app artificially running in the background when it would really be otherwise suspended when running independently on the device. So, when testing background execution on a physical device, do not debug it from Xcode directly, but rather add logging statements, launch the app directly from the device, and watch the logging statements in the macOS console.
Alternatively, sometimes background processes happen hours later, so I also will occasionally write log statements to a text file in the Application Support directory, and revisit that file later (by downloading the container back to my Mac later). In the case of background fetch and background tasks (which can happen hours or days later), this can be useful. In the case of an alarm app, though, the macOS Console approach outlined above is easiest.

Thread1: signal SIGABRT

I am getting Thread 1: signal SIGABRT error on appDelegate, I think it is because of facebook login button which I have been trying to connect to my xcode project through facebook sdk. I dont know if the way i am connecting facebook login button through outlet is correct or not. because at first it was giving me an error of optional unwrapping, when I avoided it by adding ? in the code below
fbloginbtnview?.delegate = self
fbloginbtnview?.permissions = ["email"]
now I get signal SIGABRT error.
I have been watching all the tutorials and reading all the questions on stackoverflow, but can not find anything helpful to connect facebook login button, because al the helps available are either for older versions of swift and xcode or I dont get axactly what i want.
my swift version is 5, and xcode 9.3
can anyone please give me a right peice of code to connect a facebook login button?
This is appdelegate
import UIKit
import Firebase
import CoreData
import FirebaseAuth
import FacebookCore
import FBSDKCoreKit
import FBSDKLoginKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//below for fb sdk
//....
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
//....
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
guard let urlScheme = url.scheme else { return false }
if urlScheme.hasPrefix("fb") {
return ApplicationDelegate.shared.application(app, open: url, options: options)
}
return true
}
// above for fb sdk nothing
//
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.
}
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.
}
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: "LetsGoTogether")
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)")
}
}
}
}
This below is my View controller code
import UIKit
import Firebase
import FBSDKLoginKit
import FacebookCore
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, LoginButtonDelegate {
#IBOutlet var fbloginbtnview: FBLoginButton!
override func viewDidLoad() {
super.viewDidLoad()
// fb
fbloginbtnview?.delegate = self
fbloginbtnview?.permissions = ["email"]
}
func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: Error?) {
if let error = error {
print("error took place\(error.localizedDescription)")
return
}
print("Success")
}
func loginButtonDidLogOut(_ loginButton: FBLoginButton) {
print("user signed out")
}
}
You have declared fbloginbtnview as an implicit optional, which is normal but means it is assumed to be valid. References to it will fail if you haven't connected the outlet to an actual button (or to a button of the right type) in interface builder.

Iot Raspberry Pi Xcode - FIREBASE

I am connecting firebase to xcode. I keep getting a THREAD 1 : SIGBART ERROR. I'm new to xcode so I don't know what to do. Please help. It gives me the error at the part where it says **class AppDelegate: UIResponder, UIApplicationDelegate {*
//
// AppDelegate.swift
// H2KNOW
//
// Created by Sohil Bhatia on 9/4/18.
// Copyright © 2018 Sohil Bhatia. All rights reserved.
//
import UIKit
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
// Override point for customization after application launch.
return true
}
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.
}
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.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
Please help me fix this. I really want to fix this. Thanks.

Error while connecting my project with the firebase to send push notifications

I am trying to connect my app to firebase to send notification but there i have an error:
"_OBJC_CLASS_$_FIRApp", referenced from:
clang: error: linker command failed with exit code 1 (use -v to see invocation)
in the General Capabilities there is no any error.
in code the same there is no any error but when I build and Run there is this error.
While creating certificates also there is wasn't any errors.
Here is how the errror is look like . Please help!
Here is the piece of code that I wrote:
//
// AppDelegate.swift
// COAP
//
// Created by Azamat Bolegenov on 23.05.17.
// Copyright © 2017 Azamat Bolegenov. All rights reserved.
//
import UIKit
import CoreData
import FirebaseCore
import FirebaseMessaging
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
let notificationTypes: UIUserNotificationType = [UIUserNotificationType.alert, UIUserNotificationType.badge, UIUserNotificationType.sound]
let notificationSettings = UIUserNotificationSettings(types: notificationTypes, categories: nil)
application.registerForRemoteNotifications()
application.registerUserNotificationSettings(notificationSettings)
return true
}
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.
}
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 application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
print("MessageID:: \(userInfo["gcm_message_id"]!)")
print(userInfo)
}
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.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
Go to Build Settings > Other Linker Flags > on a new line $(inherited).
Do a Cmd+Ctrl+K for a clean, and then build

Receiving Firebase Notifications in Foreground but not Background

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.