Declining request for FCM Token since no APNS Token specified

613 Views Asked by At

I would like to generate notification to specific moment in my swift application but I got this message witch indicate me that apns token is not specified. however I generate the certificate from apple developper and I download it to inject it in firebase settings.

I'm currently running this application on the simulator.

By the way the code is running on my kotlin side perfectly from the simulator.

this is my code from Xcode this class is used to manage notifications :

import Foundation
import UIKit
import Firebase
import FirebaseMessaging
import UserNotifications

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate {
    
    private lazy var currentController: UIViewController? = {
        if let window = UIApplication.shared.windows.first, let rootViewController = window.rootViewController {
            var currentController = rootViewController
            while let presentedController = currentController.presentedViewController {
                currentController = presentedController
            }
            return currentController
        }
        return nil
    }()
    
    private var notificationDetails: FirebaseNotificationAPI?
    
    func registerForPushNotifications() {
        if #available(iOS 10.0, *) {
            // For iOS 10 and later, display notification (sent via APNS)
            UNUserNotificationCenter.current().delegate = self
            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
                if granted {
                    print("Notification authorization granted")
                    // Register for remote notifications after authorization is granted
                    DispatchQueue.main.async {
                        UIApplication.shared.registerForRemoteNotifications()
                    }
                } else {
                    if let error = error {
                        print("Notification authorization error: \(error.localizedDescription)")
                    }
                }
            }
            
            Messaging.messaging().delegate = self
        } else {
            // For older iOS versions, register for user notifications
            let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            UIApplication.shared.registerUserNotificationSettings(settings)
            UIApplication.shared.registerForRemoteNotifications()
        }
    }
    
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        print("FCM Token: \(fcmToken as Any)")
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        
        handleNotificationTap(userInfo: response.notification.request.content.userInfo)
        
        completionHandler()
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        
        handleNotificationTap(userInfo: notification.request.content.userInfo)
        
        completionHandler([.badge, .sound, .alert])
    }
    
    private func handleNotificationTap(userInfo: [AnyHashable: Any]) {
        guard let data = userInfo as? [String: Any], let notificationDetails = FirebaseNotificationAPI.deserialize(from: data) else { return }
        
        self.notificationDetails = notificationDetails
        
        if let currentController = currentController {
            let alertController = UIAlertController(title: notificationDetails.aps?.alert?.title, message: notificationDetails.aps?.alert?.body, preferredStyle: .alert)
            alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            currentController.present(alertController, animated: true, completion: nil)
        }
    }
}

This is my main class :

import SwiftUI
import Firebase
import UserNotifications
import FirebaseMessaging
import FirebaseCore
import FirebaseFirestore
import FirebaseAuth

@main
struct ML2V_IOSApp: App {
    @StateObject var viewModel = AuthViewModel()
    let pushNotificationManager = PushNotificationManager()
    
    init(){
        FirebaseApp.configure()
        FirebaseConfiguration.shared.setLoggerLevel(.max)
        requestNotificationAuthorization()
        pushNotificationManager.registerForPushNotifications()
        
    }
    
    var body: some Scene {
        WindowGroup {
            ContentRooting().environmentObject(viewModel)
        }
    }
}

func requestNotificationAuthorization() {
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
        if granted {
            print("Autorisation pour les notifications accordée")
            
        } else {
            if let error = error {
                print("Erreur d'autorisation des notifications : \(error.localizedDescription)")
            }
        }
    }
}

This is the moment when I want to inject fcm to firebase to use it later :

import Foundation
import Firebase
import FirebaseFirestoreSwift
import FirebaseMessaging

protocol AuthenticationFormProtocol{
    var formIsValid: Bool {
        get
    }
}

@MainActor
class AuthViewModel: ObservableObject{
    @Published var userSession: FirebaseAuth.User?
    @Published var currentUser: User?
    
    init(){
        self.userSession = Auth.auth().currentUser
        Task{
            await getUser()
        }
    }
    
    //Fonction pour la connexion de l'utilisateur
    func connexionUser(whithEmail email: String, password: String) async throws {
        do{
            let result = try await Auth.auth().signIn(withEmail: email, password: password)
            self.userSession = result.user
            await getUser()
        }catch{
            print("DEBUG : Impossible de connecter l'utilisateur")
        }
    }
    
    //Fonction pour l'inscription de l'application
    func inscriptionUser(withEmail email: String, password: String, prenom: String, nom: String, role: String, societe: String, tel: String, date: Date) async throws{
        do{
            let result = try await Auth.auth().createUser(withEmail: email, password: password)
            self.userSession = result.user
            print("DEBUG : uid inscription \(result.user.uid)")
            let user = User(id: result.user.uid, fcm: "", prenom: prenom, nom: nom, email: email, role: role, societe: societe, telephone: tel, date_inscription: Date())
            let userDictionary: [String: Any] = [
                    "prenom": prenom,
                    "nom": nom,
                    "role": role,
                    "societe": societe,
                    "telephone": tel,
                    "date_inscription": date,
                    "fcm": ""
            ]
            try await Firestore.firestore().collection("users").document(result.user.uid).setData(userDictionary)
            await getUser()
        }catch{
            print("DEBUG: Impossible de créer l'utilisateur\(error.localizedDescription)")
        }
    }
    
    //Permet de récupérer toutes les informations de mon utilisateur actuel
    func getUser() async{
        guard let uid = Auth.auth().currentUser?.uid else{return}
        guard let email = Auth.auth().currentUser?.email else{return}
        
        if let useruid = Auth.auth().currentUser?.uid, let token = Messaging.messaging().fcmToken {
            let db = Firestore.firestore()
            let userDocRef = db.collection("users").document(useruid)
            do {
                try await userDocRef.setData(["fcm": token], merge: true)
                print("FCM token updated successfully.")
            } catch {
                print("Error updating FCM token: \(error.localizedDescription)")
            }
        } else {
            print("FCM token is nil.")
        }

            guard let snapshot = try? await Firestore.firestore().collection("users").document(uid).getDocument() else{ return }
            var snapshotData = snapshot.data() ?? [:]
            
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "d MMMM yyyy à HH:ss ZZZZZ"
            
            snapshotData["email"] = email
            snapshotData["id"] = uid
            if let dateString = snapshotData["date_inscription"] as? String {
                let dateFormatter = DateFormatter()
                dateFormatter.dateFormat = "dd MMMM yyyy 'à' HH:mm:ss 'UTC'Z"
                dateFormatter.locale = Locale(identifier: "fr_FR")
                dateFormatter.timeZone = TimeZone(abbreviation: "UTC+0200")
                if let date = dateFormatter.date(from: dateString) {
                    snapshotData["date_inscription"] = date
                }
            }
            //print(snapshotData)
            self.currentUser = try? Firestore.Decoder().decode(User.self, from: snapshotData)
    }
    
    //Deconnexion de l'utilisateur
    func deconnexion(){
        do{
            try Auth.auth().signOut()
            self.userSession = nil
            self.currentUser = nil
        }catch{
            print("DEBUG : Impossible de deconnecter l'utilisateur")
        }
    }
    
    func updateEmail(email: String) async throws{
        guard let user = Auth.auth().currentUser else{return}
        try await user.updateEmail(to: email)
        await getUser()
    }
    
    func updatePassword(password: String) async throws{
        guard let user = Auth.auth().currentUser else{return}
        try await user.updatePassword(to: password)
        await getUser()
    }
    
    func updatePhone(tel: String) async throws{
        guard let uid = Auth.auth().currentUser?.uid else{return}
        let updatedElement: [String: Any] = [
                    "telephone": tel
                ]
        try? await Firestore.firestore().collection("users").document(uid).setData(updatedElement, merge: true)
        await getUser()
    }
    
    func convertTimestampToString(_ timestamp: Timestamp) -> String {
        let date = timestamp.dateValue()
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd MMMM yyyy 'à' HH:mm:ss 'UTC'Z"
        dateFormatter.locale = Locale(identifier: "fr_FR")
        dateFormatter.timeZone = TimeZone(abbreviation: "UTC+2")
        return dateFormatter.string(from: date)
    }
}

My fcm return alway nil. I don't know why. I'm knew on swift development if somebody can help me I will be thankful.

1

There are 1 best solutions below

2
Windows Frame On

answer here thank to all : https://github.com/firebase/quickstart-ios/blob/master/messaging/MessagingExampleSwift/AppDelegate.swift

not possible for iOS simulator for the moment