Flutter FCM iOS Issue - APNS device token not set before retrieving FCM Token
Asked Answered
G

4

9

I am using firebase_messaging v9.0.1 in my Flutter application. On configuring this library based on the https://pub.dev/packages/firebase_messaging/example, I am able to receive the notification for android in both foreground and background states. But the same for iOS is not working. I am getting the below error,

APNS device token not set before retrieving FCM Token for Sender ID ''. 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.

My iOS device is connected to internet and there were no network related issues while running this.

Do I want to call any other function apart from FirebaseMessaging.instance.getToken() for iOS? Please help.

Thanks.

Gaudreau answered 1/4, 2021 at 5:15 Comment(2)
I have the same issue.Calc
Were you able to solve the issue @Karthikeyan P?Zygotene
T
13

I had the same problem, I went step by step again with firebase documentation and realize that the push notification capability was missing on debug and release modes.

Steps to solve the issue:

  1. Go to xcode
  2. Select runner
  3. Signing & Capabilities
  4. Check debug and release capabilities you need to have background modes and push notification

push notification capability

https://firebase.flutter.dev/docs/messaging/apple-integration

Termagant answered 11/5, 2021 at 17:16 Comment(1)
I've set it all, but still get that error, any update solution?Frodeen
K
2

Try running on a real device

Try this:

AppDelegate.swift

import UIKit
import Flutter
import Firebase
import FirebaseMessaging
import UserNotifications
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    var firebaseToken : String = "";
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    Messaging.messaging().delegate = self;
    FirebaseApp.configure()
    GeneratedPluginRegistrant.register(with: self)
    Messaging.messaging().isAutoInitEnabled = true;
    self.registerForFirebaseNotification(application: application);
    return true;
   // GeneratedPluginRegistrant.register(with: self)
    
  }
   override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken : Data){
    print("X__APNS: \(String(describing: deviceToken))")
       Messaging.messaging().apnsToken = deviceToken;
    //Messaging.messaging().setAPNSToken(deviceToken, type:MessagingAPNSTokenType.prod )
    }
    
    override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("X_ERR",error);
    }
    
     func registerForFirebaseNotification(application : UIApplication){
    //    Messaging.messaging().delegate     = self;
        if #available(iOS 10.0, *) {
            //UNUserNotificationCenter.current().delegate = self ;
            let authOpt : UNAuthorizationOptions = [.alert, .badge, .sound];
            UNUserNotificationCenter.current().requestAuthorization(options: authOpt, completionHandler: {_, _ in})
            UNUserNotificationCenter.current().delegate = self ;
        }else{
            let settings : UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)                
            application.registerUserNotificationSettings(settings);
        }
        application.registerForRemoteNotifications();
    }
}

extension AppDelegate : MessagingDelegate{
    func messaging(_messagin : Messaging, didRecieveRegistrationToken fcmToken : String){
        self.firebaseToken = fcmToken;
        print("X__FCM: \(String(describing: fcmToken))")
    }
    func messaging(_messagin : Messaging, didRecieve remoteMessage : Any){
        //self.firebaseToken = fcmToken;
        print("REMOTE__MSG: \(remoteMessage)")
    }
    func application(_ application : UIApplication,didRecieveRemoteNotification uinfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void){
        print("WITH__APN: \(uinfo)")
    }
}

podfile

target 'Runner' do
  use_frameworks!
  use_modular_headers!

#  pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '7.11.0'

  pod 'Firebase/Auth'
  pod 'Firebase/Analytics'
  pod 'FBSDKLoginKit'
  pod 'Firebase/Messaging'

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

pubspec.yaml

  cloud_firestore: ^2.0.0
  firebase_auth: ^1.1.2
  firebase_core: ^1.1.0
  firebase_messaging: ^9.1.3
  flutter_local_notifications: ^5.0.0+3

Answered here also

Kawai answered 31/5, 2021 at 3:58 Comment(0)
T
1

The way I solve this issue, instead of running the application thru debug mode, I archive the app and download it thru ad hoc and somehow this solves the issue

Triad answered 5/6, 2021 at 13:18 Comment(1)
Practiclly the same for me. Stop playing from XCode and ran from phone itself and it worked.Devin
V
0

I received this error too but in my case I had set up an APN certificate instead of an APN key in Firebase. I had to update my APN certificate in Firebase which had expired. This resolved the error and I could obtain a token with .getToken() in my app.

Update: In Firebase > Project Settings > Cloud Messaging I uploaded an APNs Authentication Key for my flutter iOS app. I did not upload any APNs Certificates. Follow guide here on how to create and upload APN Authentication key: https://firebase.flutter.dev/docs/messaging/apple-integration/

Then in my flutter project I use this to get FCM token

import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';


Future<String?> getFirebaseToken() async {
  String? fcmToken;
  if (Platform.isIOS) {
    // On iOS we need to see an APN token is available first
    String? apnsToken = await FirebaseMessaging.instance.getAPNSToken();
    if (apnsToken != null) {
      fcmToken = await FirebaseMessaging.instance.getToken();
    }
    else {
      // add a delay and retry getting APN token
      await Future<void>.delayed(const Duration(seconds: 3,));
      apnsToken = await FirebaseMessaging.instance.getAPNSToken();
      if (apnsToken != null) {
        fcmToken = await FirebaseMessaging.instance.getToken();
      }
    }
  }
  else {
    // android platform
    fcmToken = await FirebaseMessaging.instance.getToken();
  }
  return fcmToken;
}

In my main.dart I initialise firebase like this

  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  FirebaseMessaging.instance.onTokenRefresh.listen((String token) {
    String? fcmToken = await getFirebaseToken();
    // save token to storage or server-side depending where you want 
    // to send push notification
  })
Vassily answered 22/5, 2021 at 5:36 Comment(2)
can you please brief a bit more about itComfy
@Comfy I've added an update with explanation.Vassily

© 2022 - 2024 — McMap. All rights reserved.