I'm developing an iOS 11 app using Swift 4 and using Firebase Cloud Messaging to send notifications to my users.
The process to set up the notifications was:
1) Join the Apple Developer program. Register an App ID for my app and generate a Key with the APNs Service, like you can see on the picture:
2) Add iOS App to my existing Firebase Project, and uploading the Apple Key generated on step one.
3) Prepare iOS app to receive notifications: Added GoogleServices-Info, installed required Firebase pods (Firebase Core and Messaging).
4) Enabled required capabilities. background Modes and Push Notifications.
5) Finally, I edited my appDelegate.swift allowing to receive notifications:
import UIKit
import CoreData
import KeychainAccess
import IQKeyboardManagerSwift
import Fabric
import Crashlytics
import Firebase
import FirebaseMessaging
import FirebaseInstanceID
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//FIREBASE CONFIGURATION START
FirebaseApp.configure()
UNUserNotificationCenter.current().requestAuthorization( options: [.alert, .badge, .sound]) { (success, error) in
if error == nil {
print("Successfull authorization!")
}
}
application.registerForRemoteNotifications()
NotificationCenter.default.addObserver(self, selector: #selector(refreshToken(notification:)), name: NSNotification.Name.InstanceIDTokenRefresh, object: nil)
UNUserNotificationCenter.current().delegate = self
//FIREBASE CONFIGURATION END
if let token = InstanceID.instanceID().token() {
print("token: '\(token)'")
}
return true
}
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 = false
}
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.
FBHandler()
}
@objc func refreshToken(notification: NSNotification) {
let refreshToken = InstanceID.instanceID().token()!
print("*** \(refreshToken) ***")
FBHandler()
}
func FBHandler() {
Messaging.messaging().shouldEstablishDirectChannel = true
}
// MARK: - Handle Silent FCM notifications
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
showLocalNotification()
print("Entire message \(userInfo)")
let state : UIApplicationState = application.applicationState
switch state {
case UIApplicationState.active:
print("If needed notify user about the message")
default:
print("Run code to download content")
}
completionHandler(UIBackgroundFetchResult.newData)
}
func showLocalNotification() {
let notification = UNMutableNotificationContent()
notification.title = "Nou contingut disponible: Benicolet"
notification.body = "Restriccions cremes agrícoles"
let notificationTrigger =
UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
let request = UNNotificationRequest(identifier: "\(Int(arc4random_uniform(999999)))", content: notification, trigger: notificationTrigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
// Make local notification to appear even when app is open
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
print(response.notification.request.content.userInfo)
completionHandler()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void {
completionHandler([.alert, .badge, .sound])
}
}
My goal is to receive silent notifications, execute some logic, and then, show a Local Notification. This will happens each time I send a notification to my app, on the method didReceiveRemoteNotification
.
At the moment I only need to be able to receive the silent notification and show up a local notification, using the method showLocalNotification
.
The problem is that this method is only triggered when I send a notification while my iPhone is attached to Xcode (debugging). In this state, code works fine, but if I unplug the cable, notifications are not triggered anymore until I rerun the app using Xcode
I send my notifications using my own server, setting the Firebase topic
, 'priority': 'High'
and 'content_available':true
Simmilar unresolved questions:
didReceiveRemoteNotification:fetchCompletionHandler not called when not attached to xcode iOS 8.0.2