Firebase Cloud Messaging (FCM) is a powerful tool for sending notifications to mobile devices, web browsers, and apps. However, Google has been phasing out legacy protocols in favor of the new HTTP v1 API. Migrating from the legacy XMPP/HTTP protocols to HTTP v1 is crucial to ensure continued support, enhanced security, and access to modern features. This article outlines the steps and considerations for migrating Firebase notifications from legacy protocols to the HTTP v1 API in Flutter applications.

Why Migrate to HTTP v1?

Before diving into the migration process, it’s essential to understand the benefits of using the HTTP v1 API over the legacy protocols:

  1. Improved Security: HTTP v1 uses OAuth 2.0 for authentication, which is far more secure than the legacy server keys.
  2. Advanced Features: HTTP v1 supports new features, such as message analytics, direct targeting of topics, and message scheduling.
  3. Future-proofing: Google is deprecating legacy protocols, making HTTP v1 the standard for FCM, and has already shut down legacy APIs. 
FCM XMPP And HTTP Legacy APIs Disapproval Notice Screenshot

Step-by-Step Migration Process:

This section provides a comprehensive guide for migrating from the legacy HTTP API to the HTTP v1 API in a Flutter application. It demonstrates the step-by-step process, including updating the dependencies.

Step 1: Set Up Firebase in Your Flutter Project

Before migrating, ensure that your Flutter project is correctly set up with Firebase. If you haven’t integrated Firebase yet, follow these steps:

Install Firebase dependencies: In your pubspec.yaml file, add the necessary Firebase packages:

dependencies:
  firebase_core: latest_version
  firebase_messaging: latest_version
  googleapis_auth: latest_version

Then run:

flutter pub get
  1. Configure Firebase: Add the google-services.json (for Android) or GoogleService-Info.plist (for iOS) files to your Flutter project. These can be downloaded from the Firebase Console under your project’s settings.

      Initialize Firebase: In your main.dart file, initialize Firebase in the main() method:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

Step 2: Obtain OAuth 2.0 Credentials

HTTP v1 API uses OAuth 2.0 for authentication, requiring you to generate OAuth credentials.

  1. Create a Service Account:
    • Go to the Google Cloud Console.
    • Navigate to “IAM & Admin” → “Service Accounts”.
    • Create a new service account with the necessary permissions for Firebase Cloud Messaging.
Service Accounts in Google Cloud
  1. Generate a Private Key:
    • Once the service account is created, click on it and generate a new private key in JSON format. Store this file securely, as it will be used to generate OAuth tokens.
Firebase Admin SDK
  1. Store Credentials Securely:
    • For security reasons, avoid hardcoding your service account JSON file into your app. Instead, use a backend server to handle authentication and manage tokens securely.

Step 3: Update Backend to Use HTTP v1 API

If you have a backend server managing notifications, you’ll need to update it to work with the HTTP v1 API.

Generate an Access Token: Use the service account JSON file to generate an OAuth 2.0 token. Here’s an example of generating the token using a Flutter-compatible HTTP client like Dio or HTTP.

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:googleapis_auth/auth_io.dart';

Future<String> getAccessToken() async {
  final accountCredentials = ServiceAccountCredentials.fromJson(
    json.decode(your_service_account_json),
  );
  var scopes = ['https://www.googleapis.com/auth/firebase.messaging'];

  var client = http.Client();
  var authClient =
      await clientViaServiceAccount(accountCredentials, scopes, baseClient: client);

  var accessToken = (authClient.credentials).accessToken.data;

  return accessToken;

}

Send Notifications via HTTP v1: After generating the access token, you can send notifications using the HTTP v1 API. Here’s an example request:

Old endpoint:

https://fcm.googleapis.com/fcm/send

New endpoint: 

https://fcm.googleapis.com/v1/projects/project-id/messages:send

New Message Payload:

{
  "message": {
    "token": "target-device-token",
    "notification": {
      "title": "Notification Title",
      "body": "Notification Body"
    },
    "data": {
      "key1": "value1",
      "key2": "value2"
    }
  }
}

Send HTTP request using dart code:

Future<void> sendNotification(String token, String title, String body) async {
  final url = 'https://fcm.googleapis.com/v1/projects/project-id/messages:send';

  final headers = {
    'Authorization': 'Bearer ${await getAccessToken()}',
    'Content-Type': 'application/json',
  };

  final bodyData = {
    "message": {
      "token": token,
      "notification": {
        "title": title,
        "body": body,
      },
      "data": {
        "key1": "value1",
        "key2": "value2",
      }
    }
  };

  final response = await http.post(Uri.parse(url), headers: headers, body: jsonEncode(bodyData));

  if (response.statusCode == 200) {
    print('Notification sent successfully');
  } else {
    print('Failed to send notification: ${response.body}');
  }
}
  1. In this code:
    • token is the FCM token of the target device.
    • title and body represent the notification content.
    • data represents custom payload data that can be passed along with the notification.

Step 4: Update Firebase Messaging Logic in Flutter

Once the backend is ready to handle HTTP v1 requests, you need to ensure that the Flutter app properly handles incoming notifications.

Listen for FCM Token: You’ll need to listen for token updates and handle token refreshes. This ensures your server has the latest device token to send notifications.
dart

FirebaseMessaging messaging = FirebaseMessaging.instance;

messaging.getToken().then((String? token) {
  print("FCM Token: $token");
  // Send token to your backend for registration
});

FirebaseMessaging.onTokenRefresh.listen((newToken) {
  print("Token refreshed: $newToken");
  // Update the new token on your backend
});

Handle Background and Foreground Messages: Configure your app to handle messages when it’s in the foreground or background:
dart

FirebaseMessaging.onMessage.listen((RemoteMessage message) {
  print('Message received while app is in foreground: ${message.notification}');
  // Display or handle the notification
});

FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
  print('Message opened by user: ${message.notification}');
  // Handle the message, possibly by navigating to a specific screen
});
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

Step 5: Testing the Migration

After completing the migration steps, test the new notification system thoroughly:

  1. Send Test Notifications: Use the Firebase Console or your backend to send test notifications to individual devices, topics, or groups.
  2. Monitor Logs: Check your backend logs to ensure that the notifications are being sent using HTTP v1. Ensure that there are no authentication errors or invalid tokens.
  3. Check Device Behavior: Ensure that notifications arrive correctly on different devices (iOS, Android), both when the app is in the foreground, background, and terminated.

We have integrated Firebase Push Notifications (FCM) in multiple applications, including U-Report Global, eCook, and Out of School Children BD etc. U-Report Global, in particular, relies heavily on FCM for its functionality. Following Google’s announcement regarding the deprecation of the FCM Legacy API, effective June 2024, we have proactively initiated research and development (R&D) to address this transition. 

After completing our R&D, we followed the outlined steps provided in the article, ‘Migrating Firebase notifications from legacy protocols to HTTP v1‘. By adhering to these guidelines, we successfully migrated our systems to the new HTTP v1 protocol, ensuring seamless push notification functionality across all our applications.

Conclusion

Migrating from FCM legacy to HTTP v1 might seem difficult at first, but it offers significant improvements in functionality, security, and performance. By following this guide, you can smoothly transition your app to the new API, ensuring it remains up-to-date and fully supported by Firebase.

This page was last edited on 1 October 2024, at 4:48 pm