Patrick
Patrick

Reputation: 119

Flutter Firebase getAPNSToken() returns null

I am trying to implement push notifications in my flutter app.

On iOS, if I call FirebaseMessaging.instance.getToken(), I receive the error firebase_messaging/apns-token-not-set, so I am calling

FirebaseMessaging.instance.getAPNSToken()

but it returns null on real devices.

Works in simulator, but not on real devices

All StackOverflow threads and all GitHub issues I read say: Push notifications don't work in the iOS simulator, use a real device. But for me it's the other way round:

In the iOS iPhone 15 simulator I do receive an APNS token, but on my real device connected via Lightning cable to my Mac and on the same device using the app via Testflight, I do not receive an APNS token.

Code

I use the following code to receive the FCM token. The code is a bit messy right now because of all the debugging I am doing. I added a delay as second step in case the first getAPNSToken() returns null, because that worked for some people, but not in my case.

Future<void> initNotifications() async {
    await FirebaseMessaging.instance.setAutoInitEnabled(true);

    final permissionRequest = await FirebaseMessaging.instance.requestPermission(
      alert: true,
      announcement: false,
      badge: true,
      carPlay: false,
      criticalAlert: false,
      provisional: false,
      sound: true,
    );

    if (permissionRequest.authorizationStatus == AuthorizationStatus.authorized) {
      String? fcmToken;

      if (Platform.isIOS) {
        String? apnsToken = await FirebaseMessaging.instance.getAPNSToken();

        if (apnsToken != null) {
          debugPrint("APNS Token: $apnsToken");
          fcmToken = await FirebaseMessaging.instance.getToken();
          debugPrint("FCM Token: $fcmToken");
        } else {
          debugPrint("APNS Token not available, waiting ...");

          await Future<void>.delayed(
            const Duration(
              seconds: 3,
            ),
          );

          apnsToken = await FirebaseMessaging.instance.getAPNSToken();

          if (apnsToken != null) {
            debugPrint("APNS Token: $apnsToken");
            fcmToken = await FirebaseMessaging.instance.getToken();
            debugPrint("FCM Token: $fcmToken");
          } else {
            debugPrint("APNS Token not available, trying to get FCM token anyway ...");
            
            try {
              fcmToken = await FirebaseMessaging.instance.getToken();
            } catch (err) {
              debugPrint("FCM Token not available ($err)");
            }
          }
        }

      } else {
        fcmToken = await FirebaseMessaging.instance.getToken();
        debugPrint("FCM Token: $fcmToken");
      }
    } else {
      debugPrint("Notifications not authorized");
    }
}

The method above is called in main.dart:

  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  await FireBaseNotifications().initNotifications();

Xcode

In Xcode I enabled:

- Push Notifications
- Background Modes:
    - Background fetch
    - Remote notifications

Firebase console

In the project settings I added two APNs certificates (development and production).

pubspec.yaml

I am using these firebase packages:

  firebase_core: ^2.20.0
  firebase_messaging: ^14.7.2

I have no idea why I get the APNS token in simulator but not on my real device. I don't understand what I am missing.

Upvotes: 4

Views: 6227

Answers (4)

Ataberk
Ataberk

Reputation: 605

I know it is an edge case. But it might be helpful for some. In my case, I realized I added Push Notifications capability only under Release. So I wasn't getting any APNS token in debug mode.

This is how it was looking (select all and see if there is Release postfix):

xcode push notifications only added to release

Now you should add the capability when All is selected.

Make sure it looks like this:

xcode push notifications added to all

Upvotes: 0

Mntimande
Mntimande

Reputation: 21

I had the very same error , however in my case I solved it by doing the following

Add the following to your AppDelegate.swift file if not added yet

override func application(_ application: UIApplication, 
  didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data){


Messaging.messaging().apnsToken = deviceToken
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken:deviceToken)

So your AppDelegate.swift file should look like :

import UIKit
import Flutter
import FirebaseCore
import FirebaseMessaging

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication ,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  override func application(_ application: UIApplication, 
  didRegisterForRemoteNotificationsWithDeviceToken deviceToken:Data){

    
    Messaging.messaging().apnsToken = deviceToken
    super.application(application, didRegisterForRemoteNotificationsWithDeviceToken:deviceToken)
  }


}

I also had to create new certificate and generate a new Signing profile , then opened it via xcode to update signing profile

Upvotes: 0

xleon
xleon

Reputation: 6365

Make sure ios/Runner/Runner.entitlements contains aps-environment

enter image description here

Upvotes: 0

K-Soliman
K-Soliman

Reputation: 1100

Make sure that you enabled push notifications on Xcode

enter image description here

Upvotes: 4

Related Questions