Skip to main content
Integrate push notifications into your Flutter app using Firebase Cloud Messaging (FCM) to deliver real-time updates across both Android and iOS platforms with a unified codebase.
Flutter’s cross-platform nature allows you to implement push notifications once and deploy to both platforms, but platform-specific configuration is still required.

Prerequisites

Firebase Project

Active Firebase project with FCM enabled

Platform Setup

Android google-services.json and iOS GoogleService-Info.plist

social.plus SDK

social.plus Flutter SDK properly integrated

Certificates

iOS APNs certificate and Android FCM configuration

Step 1: Install Dependencies

Add the Firebase Messaging plugin to your pubspec.yaml:
dependencies:
  flutter:
    sdk: flutter
  
  # social.plus SDK
  amity_sdk: ^6.x.x
  
  # Firebase dependencies
  firebase_core: ^2.24.2
  firebase_messaging: ^14.7.10
  
  # Optional: For local notifications
  flutter_local_notifications: ^16.3.2
  
  # Optional: For permission handling
  permission_handler: ^11.1.0
Always use the latest stable versions. Check pub.dev for current version numbers.

Step 2: Configure Firebase with FlutterFire CLI

Before proceeding with push notification setup, you need to configure Firebase for your Flutter app using the FlutterFire CLI.
Follow the official Firebase documentation to install and configure FlutterFire CLI for your platform:The FlutterFire CLI will automatically handle Firebase project setup, app registration, and configuration file generation for both platforms.

Initialize Firebase in Your App

After running flutterfire configure, initialize Firebase in your app’s main() function:
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart'; // Generated by FlutterFire CLI

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Initialize Firebase
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  
  runApp(MyApp());
}
You must initialize Firebase before using any Firebase services, including FCM. The firebase_options.dart file is automatically generated by the FlutterFire CLI.

Step 3: Platform Configuration

If you’ve run flutterfire configure, the configuration files are already in place. You still need to update the build files and permissions as shown below.

Android Configuration

  1. Add google-services.json to android/app/ (automatically done by FlutterFire CLI)
  2. Update build.gradle files:
// android/build.gradle
buildscript {
  dependencies {
    classpath 'com.google.gms:google-services:4.3.15'
  }
}

// android/app/build.gradle
apply plugin: 'com.google.gms.google-services'

android {
  compileSdkVersion 34
  
  defaultConfig {
    minSdkVersion 21
    targetSdkVersion 34
  }
}
  1. Add permissions to android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    
    <!-- Push notification permissions -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    
    <application
        android:label="Your App"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        
        <!-- Your activities -->
        
    </application>
</manifest>

iOS Configuration

  1. Add GoogleService-Info.plist to ios/Runner/ (automatically done by FlutterFire CLI)
  2. Enable Push Notifications capability in Xcode
  3. Generate APNs certificate following the iOS setup guide
  4. Update Runner-Info.plist for background modes:
<!-- ios/Runner/Info.plist -->
<dict>
    <!-- Existing keys -->
    
    <key>UIBackgroundModes</key>
    <array>
        <string>background-fetch</string>
        <string>remote-notification</string>
    </array>
    
    <key>FirebaseAppDelegateProxyEnabled</key>
    <false/>
</dict>
  1. Update AppDelegate.swift:
// ios/Runner/AppDelegate.swift
import UIKit
import Flutter
import Firebase
import UserNotifications

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()
    
    if #available(iOS 10.0, *) {
      UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
    }
    
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  override func userNotificationCenter(_ center: UNUserNotificationCenter,
                                       willPresent notification: UNNotification,
                                       withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    let userInfo = notification.request.content.userInfo
    let title = notification.request.content.title
    let body = notification.request.content.body
    
    completionHandler([.banner, .badge, .sound])
  }
  
  // Handle notification tap when app is in background or terminated
  override func userNotificationCenter(_ center: UNUserNotificationCenter,
                                       didReceive response: UNNotificationResponse,
                                       withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo
    let title = response.notification.request.content.title
    let body = response.notification.request.content.body
    
    completionHandler()
  }
}
Note: The notification handlers above allow you to:
  • Display notifications when app is in foreground (willPresent)
  • Handle user taps on notifications (didReceive)
  • Access notification payload through userInfo dictionary
  • Customize notification presentation options

Step 4: Register Device for Push Notifications

After configuring the platform settings, you need to register the device token with social.plus SDK.

Implementation

Create a function to handle device token registration:
import 'dart:io';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:amity_sdk/amity_sdk.dart';

Future<void> registerPushNotification({
  String? fcmToken,
  Function(bool success, String? error)? callback,
}) async {
  try {
    final messaging = FirebaseMessaging.instance;
    
    // Request notification permissions (iOS)
    if (Platform.isIOS) {
      NotificationSettings settings = await messaging.requestPermission(
        alert: true,
        badge: true,
        sound: true,
      );
      
      if (settings.authorizationStatus != AuthorizationStatus.authorized) {
        if (callback != null) {
          callback(false, "Notification permission denied");
        }
        return;
      }
    }

    // Get device token
    String? token;
    if (Platform.isIOS) {
      // For iOS, try to get APNs token first
      token = await messaging.getAPNSToken();
      // Fall back to FCM token if APNs token is not available
      if (token == null) {
        token = await messaging.getToken();
      }
    } else {
      // For Android, get FCM token
      token = await messaging.getToken();
    }

    // Use provided FCM token or fallback to retrieved token
    final deviceToken = fcmToken ?? token;

    if (deviceToken == null) {
      if (callback != null) {
        callback(
          false,
          "Failed to get device token. Please ensure push notifications are enabled in device settings and APNs is configured in Firebase Console.",
        );
      }
      return;
    }

    // Register device token with Amity SDK
    await AmityCoreClient.registerDeviceNotification(deviceToken)
        .then((value) {
      if (callback != null) {
        callback(true, null);
      }
    }).onError((error, stackTrace) {
      if (callback != null) {
        callback(false, "Failed to register push notification: $error");
      }
    });
  } catch (e) {
    if (callback != null) {
      callback(false, e.toString());
    }
  }
}

Usage Example

Call the registration function after the user is logged in to social.plus:
// After user login to Amity
await AmityCoreClient.login(userId: 'user123')
    .then((value) async {
  print('✅ Logged in successfully');
  
  // Register for push notifications after successful login
  await registerPushNotification(
    callback: (success, error) {
      if (success) {
        print('✅ Push notifications registered successfully');
      } else {
        print('❌ Failed to register push notifications: $error');
      }
    },
  );
}).onError((error, stackTrace) {
  print('❌ Login failed: $error');
});
Important Notes:
  • iOS: The function attempts to get the APNs token first, then falls back to the FCM token if unavailable
  • Android: Directly retrieves the FCM token
  • Permissions: iOS requires explicit permission request, which is handled in the function
  • Timing: Register after user authentication with social.plus SDK

Step 5: Upload Certificates to social.plus Console

Before registering devices, you must upload your certificates to the social.plus Console. Push notifications will not work without proper certificate configuration.

Android - FCM Service Account

  1. Generate FCM service account JSON:
    • Go to Firebase Console → Project Settings → Service Accounts
    • Click “Generate new private key”
    • Download the JSON file
  2. Upload to social.plus Console:
    • Navigate to Settings → Push Notifications
    • Upload the FCM service account JSON file

iOS - APNs Certificate

  1. Generate .p12 certificate following the iOS setup guide
  2. Upload to social.plus Console:
    • Navigate to Settings → Push Notifications
    • Upload the .p12 file with password
For detailed instructions on creating and obtaining your APNs certificate, refer to the iOS Push Notification Setup Guide.

Firebase Cloud Messaging (FCM) for iOS

iOS also supports Firebase Cloud Messaging (FCM) for push notifications. To set this up:
  1. Upload APNS Auth Key to Firebase:
    • Go to your Firebase Console
    • Navigate to Project Settings → Cloud Messaging → Apple app configuration
    • Upload your Apple Push Notification service (APNs) Authentication Key (.p8 file)
    • Provide your Key ID and Team ID
  2. Upload APNS Certificate to social.plus Console:
    • Get your iOS APNs Certificate (.p8 file)
    • Go to social.plus Console
    • Navigate to Settings → Push Notifications
    • Upload your APNs Certificate (.p8 file) with the appropriate configuration

Best Practices

Platform-Specific Handling: While Flutter allows shared code, some platform-specific handling is necessary.
// Handle platform differences
Future<void> handlePlatformSpecificSetup() async {
  if (Platform.isIOS) {
    // iOS-specific handling
    await _handleIOSSpecificSetup();
  } else if (Platform.isAndroid) {
    // Android-specific handling
    await _handleAndroidSpecificSetup();
  }
}
Token State Management: Keep token state consistent across app lifecycle.
class NotificationState extends ChangeNotifier {
  String? _fcmToken;
  bool _isRegistered = false;
  
  String? get fcmToken => _fcmToken;
  bool get isRegistered => _isRegistered;
  
  Future<void> updateToken(String token) async {
    _fcmToken = token;
    await _registerWithSDK(token);
    _isRegistered = true;
    notifyListeners();
  }
}
Robust Error Management: Handle various failure scenarios gracefully.
class PushNotificationErrorHandler {
  static void handleError(dynamic error) {
    if (error is FirebaseException) {
      _handleFirebaseError(error);
    } else if (error is PlatformException) {
      _handlePlatformError(error);
    } else {
      _handleGenericError(error);
    }
  }
  
  static void _handleFirebaseError(FirebaseException error) {
    // Handle Firebase-specific errors
    print('Firebase error: ${error.message}');
  }
}

Troubleshooting

Token Not Generated:
  • Verify Firebase configuration files are correctly placed
  • Check internet connectivity
  • Ensure permissions are granted
iOS Notifications Not Working:
  • Verify APNs certificate is uploaded to social.plus Console
  • Test with TestFlight or App Store build (not debug)
  • Check iOS project capabilities
Android Notifications Not Working:
  • Verify FCM service account JSON is uploaded
  • Check google-services.json placement
  • Ensure minSdkVersion >= 21
iOS Debug Builds:
  • Push notifications don’t work with debug builds
  • Use TestFlight for testing
Android 13+ Permission:
  • Runtime notification permission required
  • Handle permission request properly
// Check Android version and request permission
if (Platform.isAndroid) {
  final androidInfo = await DeviceInfoPlugin().androidInfo;
  if (androidInfo.version.sdkInt >= 33) {
    await Permission.notification.request();
  }
}
Testing Strategy: Always test push notifications on physical devices with production builds, as simulators and debug builds have limitations with push notification delivery.