Skip to content

Critical Bug: iOS builds deployed via FlutterFlow are missing Push Notification entitlements when using custom authentication (Supabase). #6373

@indiedev84

Description

@indiedev84

Can we access your project?

  • I give permission for members of the FlutterFlow team to access and test my project for the sole purpose of investigating this issue.

Current Behavior

When deploying an iOS app to TestFlight using the built-in FlutterFlow deployment feature, the generated build is missing the necessary aps-environment entitlement for Push Notifications.

This occurs in projects that use Supabase for authentication and Firebase only for Cloud Messaging. Because Firebase Authentication is not enabled in the FlutterFlow project settings, the build system incorrectly assumes that Push Notifications are not needed and omits the entitlement.

As a result, the app successfully requests notification permission from the user, but the call to FirebaseMessaging.instance.getToken() fails with the error [firebase_messaging/apns-token-not-set]. We have confirmed this by debugging the TestFlight build with Apple's Console app.

Expected Behavior

The FlutterFlow build system should correctly include the aps-environment entitlement in the final iOS build whenever the project uses the firebase_messaging package, regardless of the authentication provider being used (Firebase, Supabase, or other).

The app should be able to receive an APNs token from iOS and successfully generate an FCM token.

Steps to Reproduce

  1. Create a FlutterFlow project that uses Supabase Authentication.
  2. Configure Firebase and add the firebase_messaging package for Push Notifications.
  3. Create a Custom Action to initialize Firebase and another Custom Action to request permission and get the FCM token upon user login.
  4. Deploy the app to the App Store (TestFlight) using the built-in "Deploy to App Store" button.
  5. Install the build from TestFlight on a physical iOS device.
  6. Connect the device to a Mac and monitor logs using the Console app.
  7. Observe that after granting permission, the app logs a [firebase_messaging/apns-token-not-set] error and fails to generate a token.

Reproducible from Blank

  • The steps to reproduce above start from a blank project.

Bug Report Code (Required)

IT8KhvHqx4hOxLhK1aXide9VgSQWGDs7RYI7lexqEBMjF5TuBOxye86lalhoTdOmYmxUJmG0jn4y7NHtiYbpCvkCCwutbL5twZdTFzz/VnKVWq2DGbWOOkFDN8BUIFOP08OZ3wpSCNZsS3gc7Tu6AfaSXhPbGZTSPWwdOv6aCILAn16rGQzvMBFHzTYPGXWkCfA6ZAq+loqUtpJh0eDnyw==

Visual documentation

Image

Custom Actions

setupPushNotifications

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:url_launcher/url_launcher.dart';
import 'dart:async';
import '/custom_code/actions/index.dart';
Future<void> _updateFcmTokenInSupabase(String token) async {
  try {
    await updateUserFcmToken(token);
    print('[FCM_SETUP] Token successfully sent to Supabase.');
  } catch (e) {
    print('[FCM_SETUP] Error calling "updateUserFcmToken" action: $e');
  }
}
void _handleMessageNavigation(RemoteMessage message) async {
  final String? deepLinkUrl = message.data['link'];
  if (deepLinkUrl != null && deepLinkUrl.isNotEmpty) {
    print('[FCM_SETUP] Notification contains deep link: $deepLinkUrl');
    final uri = Uri.parse(deepLinkUrl);
    if (await canLaunchUrl(uri)) {
      await launchUrl(uri);
    } else {
      print('[FCM_SETUP] Could not launch deep link: $deepLinkUrl');
    }
  }
}
Future<void> setupPushNotifications() async {
  print('[FCM_SETUP] Main function started.');
  try {
    if (Firebase.apps.isEmpty) {
      print('[FCM_SETUP] Firebase not initialized. Aborting.');
      return;
    }
    print('[FCM_SETUP] Requesting notification permissions...');
    NotificationSettings settings =
        await FirebaseMessaging.instance.requestPermission();
    if (settings.authorizationStatus != AuthorizationStatus.authorized &&
        settings.authorizationStatus != AuthorizationStatus.provisional) {
      print(
          "[FCM_SETUP] Permission not granted. Status: ${settings.authorizationStatus}");
      return;
    }
    print("[FCM_SETUP] Permission granted.");
    String? fcmToken;
    print('[FCM_SETUP] Attempting to get FCM token...');
    if (kIsWeb) {
      const String vapidKey =
          "***";
      fcmToken = await FirebaseMessaging.instance.getToken(vapidKey: vapidKey);
    } else {
      
      fcmToken = await FirebaseMessaging.instance.getToken();
    }
    if (fcmToken != null) {
      print("[FCM_SETUP] SUCCESS! Token received. Updating in Supabase...");
      await _updateFcmTokenInSupabase(fcmToken);
    } else {
      print('[FCM_SETUP] FAILED to get FCM token. The token was null.');
    }
    print('[FCM_SETUP] Setting up message listeners...');
    FirebaseMessaging.instance.onTokenRefresh.listen(_updateFcmTokenInSupabase);
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print(
          '[FCM_SETUP] Message received in foreground: ${message.notification?.title}');
    });
    FirebaseMessaging.onMessageOpenedApp.listen(_handleMessageNavigation);
    FirebaseMessaging.instance.getInitialMessage().then((message) {
      if (message != null) {
        _handleMessageNavigation(message);
      }
    });
  } catch (e) {
    print("[FCM_SETUP] FATAL ERROR during notification setup: $e");
  }
  print('[FCM_SETUP] Setup process finished.');
}

initializeFirebase

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart'
show kIsWeb, defaultTargetPlatform, TargetPlatform;
import 'package:flutter/widgets.dart';
FirebaseOptions _getFirebaseOptions() {
  if (kIsWeb) {
    return FirebaseOptions(
      apiKey: "***",
      appId: "",
      messagingSenderId: "***",
      projectId: "***",
      authDomain: "***",
      storageBucket: "***",
    );
  }
  switch (defaultTargetPlatform) {
    case TargetPlatform.android:
      return FirebaseOptions(
        apiKey: "***",
        appId: "***",
        messagingSenderId: "***",
        projectId: "***",
        storageBucket: "***",
      );
    case TargetPlatform.iOS:
      return FirebaseOptions(
        apiKey: "***",
        appId: "***",
        messagingSenderId: "***",
        projectId: "***",
        storageBucket: "***",
        iosBundleId: "***",
      );
    default:
      throw UnsupportedError(
          'FirebaseOptions are not supported for this platform.');
  }
}
Future<void> initializeFirebase() async {
  WidgetsFlutterBinding.ensureInitialized();
  if (Firebase.apps.isEmpty) {
    await Firebase.initializeApp(options: _getFirebaseOptions());
    print('[FCM_INIT] Custom Firebase Initialization COMPLETE.');
  } else {
    print('[FCM_INIT] Firebase was already initialized.');
  }
}

Environment

- **FlutterFlow version:** v6.1.45
- **Platform:** iOS
- **Browser name and version:** Chrome 107 139.0.7258.128
- **Operating system and version:** Mac OS Sequoia 15.6

Additional Information

This is a critical blocker for our app's release, as push notifications are a core feature. Using Firebase for push notifications while using a different backend/auth provider like Supabase is a very common architecture. The current build system incorrectly links the Push Notification capability to the Firebase Auth setting, preventing this standard architecture from working.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions