DEV Community

Cover image for Implementing Push Notifications in Flutter with Firebase
TAIO Sylvain
TAIO Sylvain

Posted on

Implementing Push Notifications in Flutter with Firebase

Step 1: Create a Flutter project
If you haven't installed Flutter yet, follow the instructions on the official Flutter website to do so. After that, create a new Flutter project using the following command:
flutter create push_notification
cd push_notification

Step 2: Set Up dependencies
Add the plugins to your pubspec.yaml file and run flutter pub get to install the dependencies as shown below.

dependencies:
firebase_core: ^3.12.0
flutter_local_notifications: ^19.0.0
firebase_messaging: ^15.2.2
googleapis_auth: ^1.6.0
http: ^1.2.1

Step 3: Create your Firebase project

1. Create a Firebase Project
Go to the Firebase Consoleand log in with your Google account.

Click on Create a project, enter the project name, and follow the setup instructions.

2. Add Your Flutter App to Firebase
In the Firebase console, select your project and click Add app.
Choose the platform: Android or iOS.
For Android, provide the package name (found in android/app/build.gradle).
For iOS, provide the Bundle ID (found in ios/Runner.xcodeproj).

3. Download the Configuration File
For Android, download the google-services.json file and place it inside android/app/.
For iOS, download the GoogleService-Info.plist file and place it inside ios/Runner/.

4. Configure Firebase in the Flutter Project
Update the Android configuration:

Modify android/build.gradle and android/app/build.gradle to include Firebase dependencies.

5. Initialize Firebase in Flutter

import 'package:firebase_core/firebase_core.dart';
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Create a file named notification_service.dart
in your project. Then, copy and paste the following content into the file.

import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';


class AppNotification {
  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
  AndroidNotificationChannel channel = const AndroidNotificationChannel(
    'high_app_notif_channel', // id
    'High Importance Notifications', // title
    description: 'This channel is used for important notifications', // description
    importance: Importance.max,
    showBadge: true
  );

  initializeFcmNotification() async {
    await flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
        AndroidFlutterLocalNotificationsPlugin>()
        ?.createNotificationChannel(channel);

    const AndroidInitializationSettings initializationSettingsAndroid =
    AndroidInitializationSettings('@mipmap/ic_launcher');
    final DarwinInitializationSettings initializationSettingsIOS =
    DarwinInitializationSettings(
        requestSoundPermission: true,
        requestBadgePermission: true,
        requestAlertPermission: true,
        defaultPresentAlert: true,
        defaultPresentSound: true,
        defaultPresentBadge: true,
        );
    final InitializationSettings initializationSettings =
    InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsIOS,
    );
    await flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
      onDidReceiveNotificationResponse: (payload) async{

      },
    );

    await flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
        IOSFlutterLocalNotificationsPlugin>()
        ?.requestPermissions(
      alert: true,
      badge: true,
      sound: true,
    );

    await FirebaseMessaging.instance
        .setForegroundNotificationPresentationOptions(
      alert: true,
      badge: true,
      sound: true,
    );

    FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
      RemoteNotification? notification = message.notification;
      AndroidNotification? android = message.notification?.android;
      if (notification != null && android != null) {
        flutterLocalNotificationsPlugin.show(
          notification.hashCode,
          notification.title,
          notification.body,
          NotificationDetails(
            ///android platform specific
            android: AndroidNotificationDetails(channel.id, channel.name,
                channelDescription: channel.description,
                importance: Importance.max,
                priority: Priority.high,
                channelShowBadge: true,
                enableVibration: true,
                enableLights: true,
                icon: android.smallIcon
            ),
            iOS: const DarwinNotificationDetails(
                presentSound: true, presentBadge: true, presentAlert: true),
          ),
          payload: jsonEncode(message.data),
        );
      }
    },
    );

    FirebaseMessaging.onMessageOpenedApp.listen(
          (RemoteMessage message) {
        //log('Message Opened CallBack $message');
        //log('Message Opened CallBack');
      },
    );
  }


}


Enter fullscreen mode Exit fullscreen mode

Step 5: Go to your Firebase project
Select the project, click on the settings icon, and navigate to Project settings.

Image description

Step 6: Create a file named constant.dart
in your project. Then, copy and paste the following content into the file.

class AppConstant{
  static final fcmUrl = "https://fcm.googleapis.com/v1/projects";
  static final googleApi = "https://www.googleapis.com/auth/cloud-platform";
  static final api = '${AppConstant.fcmUrl}/students-app-4b35f/messages:send';
}


Enter fullscreen mode Exit fullscreen mode

In the following line:
static final api = '${AppConstant.fcmUrl}/students-app-4b35f/messages:send';

students-app-4b35f is the project ID. Copy it and replace it with the correct value from your Firebase project.

Step 7: Navigate through the menu bar and click on Service accounts

Then, click on Firebase Admin SDK with the key icon. Next, click on the Generate a new private key button. Save the file securely in a safe location.

Image description

Open the downloaded file and copy its content. It is in JSON format.

Step 8: Create a file named notification_network.dart
in your project. Then, copy and paste the following content into the file.

import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:googleapis_auth/auth_io.dart';
import 'package:http/http.dart' as http;
import 'package:push_notification/constant.dart';

class SendNotificationAccess{
  static final List<String> scopes = [
    AppConstant.googleApi
  ];
  static Future<String> getAccessToken() async {
    final serviceAccountCredentials = ServiceAccountCredentials.fromJson({
      "type": "service_account",
      "project_id": "students-app-4b35f",
      "private_key_id": "2fa48b2f70407670e0c15998be363fb0ed399f82",
      "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDVHiDLCJDkNJhc\naA6v3Be7cu3bnfZc3E8reHl0c+lxZl2ygN1dWOpdM8ErhlF8aOHdsgYrGJ3txLhU\nPwHf3WpEiHsm2+dXBoEUPDm4kQkZRy0+HYr0jD2MuMeCiC9Sua62of/gp9tQp6m2\nwpKTle4ZPRpYv5AdTqTitl8EJKGj1JP0+mw19K3o7gTMyoY65T/Aw0RGkjBUBDVm\nZSz6nZYYW4H8M93KjO8jCeCWxUYfUe1qKlkJGLaKbxEOQJ6PiD+Vp6Jk4TOkmHht\n8IKmrm7PFt5Dul2D8aT/CorpMmWopjLp2ZhQOArhzByPpMpUyPPlAsleoYXdbSkX\nD29dBJabAgMBAAECggEAB6m8KyDFOPdtLRFuycMDtXFF/ToaVC91x03fLCFI2ROB\ntfvtOcCLOMu2G+8J+gu5Z2PR1fXeI+EJcboMQrTu78TqjLSmhloNBSG/P5QzfA2z\nokKkrvNl+SvhvJ9R+EsF7bo4fab7e1R0BUbMx3LCK3Unf95ve6ZKxn4hP4BjsYTP\n7otywZn3g4H2B47EPJfEL0VJK87hM85Z+f4679m0kcVgYqbcrGUCi6iNy0fLZ0Fu\nQtT4DvoSTqbsVD6zhakpFbtgJdMCslZYAjI02/qptTB/6RrbYJmOr3LLfM6kNJiL\n3/V1rLRb9WGrucfGGh2f25huEm1oBFPCoMRulMSUwQKBgQD8At1X8a6ZTrBKS1wH\nNc3sXb5e8y/DSv5xHU3gObgrTsNDlo6mNpsZrbFXkjaKdANZkB1JNgjknhgHVRQ/\njzkenYbDj8qSDYjV90EBJJSXhFv9QSbU0IiUci+N4vaX3hl+fMbCSYJZ5GtlzAPu\nRAZuJa0GCEkxeR6oCyc4y1bfWwKBgQDYfatODjQI0XwwpRYWzJmojZuGh+eA5Tih\nwZmPxeDBJ8mn7v0Dg3dobJcBg0V+HyFwBxweqLvsImpgjy6tgWccT0IuK0YMZT9J\nwhwUzEv0v4uOpyFcHE4ldkLnxmVo85YoxjolzSEPXjZjgA6YLh8HU22y8uQ0Q716\n9b0n08QJwQKBgHScCrmn3keYDqDCEBpR/jASDIW492/hYq0Khz9q1dpMPrQmlWk5\nuTj/kyDXSh90oRwvQC3hL+pBcRLrfkwOxLpy36nb/jrowllnaI/T0mHt3/bmz8YH\nnDs8Pt7jl4EcRyWtLPc3tnZL6JoY9fSpS2RqUI6LBPs8dUACsSpphJAjAoGAY/FI\nFyXJcdS7330nAGl9+mk9RlMRVdj8VviYWt5ADwu+Na/H0Ept4qBW6hTfDQV0G1K8\n8Y52CuIsd91B8EmP/2q7o7LIiMpo+DULX7Kc0iVnWPjhFrPeg77fzj4x7MyfIr24\ndGEJhR26QB8LHcgU/P3P48/r+BDZtZ0isPM7SkECgYEAgyAR1hG0rfrd9ajbGLpx\nXGJ7fo6vQW2OG96jGXpg12N70JwKtoAYw2ZaRn7ajSXXh8JFlyw5334uOO97+65D\n6dVG2T0KNh5FsrVptNZgZuc/PJXf4mEkYWVRHzE3VFfc0y4RBgVsN8cHpH9nIe3K\nhCfESjU6fePEAo1dFIUfTco=\n-----END PRIVATE KEY-----\n",
      "client_email": "firebase-adminsdk-fbsvc@students-app-4b35f.iam.gserviceaccount.com",
      "client_id": "110426202408684217122",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://oauth2.googleapis.com/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40students-app-4b35f.iam.gserviceaccount.com",
      "universe_domain": "googleapis.com"
    }
    );
    var client = http.Client();
    AuthClient authClient = await clientViaServiceAccount(serviceAccountCredentials, scopes);
    final accessTokenData = authClient.credentials.accessToken.data;
    client.close();
    return accessTokenData;
  }

  static sendNotificationWithHttp({required String token,required String title,required String body}) async {
    String accessToken = await getAccessToken();

    Map<String, dynamic> payload = {
      "message": {
        "token": token,
        "notification": {
          "body": body,
          "title": title
        }
      }
    };
    final response = await http.post(Uri.parse(AppConstant.api),
        headers: {
          'Authorization': 'Bearer $accessToken',
          'Content-Type': 'application/json',
        },
        body: jsonEncode(payload));

    if (response.statusCode == 200) {
      if (kDebugMode) {
        print('Notification send');
      }
    } else {
      if (kDebugMode) {
        print('Notification Not send');
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Replace this part of the code (the JSON) with the content of the JSON file you downloaded.

{
      "type": "service_account",
      "project_id": "students-app-4b35f",
      "private_key_id": "2fa48b2f70407670e0c15998be363fb0ed399f82",
      "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDVHiDLCJDkNJhc\naA6v3Be7cu3bnfZc3E8reHl0c+lxZl2ygN1dWOpdM8ErhlF8aOHdsgYrGJ3txLhU\nPwHf3WpEiHsm2+dXBoEUPDm4kQkZRy0+HYr0jD2MuMeCiC9Sua62of/gp9tQp6m2\nwpKTle4ZPRpYv5AdTqTitl8EJKGj1JP0+mw19K3o7gTMyoY65T/Aw0RGkjBUBDVm\nZSz6nZYYW4H8M93KjO8jCeCWxUYfUe1qKlkJGLaKbxEOQJ6PiD+Vp6Jk4TOkmHht\n8IKmrm7PFt5Dul2D8aT/CorpMmWopjLp2ZhQOArhzByPpMpUyPPlAsleoYXdbSkX\nD29dBJabAgMBAAECggEAB6m8KyDFOPdtLRFuycMDtXFF/ToaVC91x03fLCFI2ROB\ntfvtOcCLOMu2G+8J+gu5Z2PR1fXeI+EJcboMQrTu78TqjLSmhloNBSG/P5QzfA2z\nokKkrvNl+SvhvJ9R+EsF7bo4fab7e1R0BUbMx3LCK3Unf95ve6ZKxn4hP4BjsYTP\n7otywZn3g4H2B47EPJfEL0VJK87hM85Z+f4679m0kcVgYqbcrGUCi6iNy0fLZ0Fu\nQtT4DvoSTqbsVD6zhakpFbtgJdMCslZYAjI02/qptTB/6RrbYJmOr3LLfM6kNJiL\n3/V1rLRb9WGrucfGGh2f25huEm1oBFPCoMRulMSUwQKBgQD8At1X8a6ZTrBKS1wH\nNc3sXb5e8y/DSv5xHU3gObgrTsNDlo6mNpsZrbFXkjaKdANZkB1JNgjknhgHVRQ/\njzkenYbDj8qSDYjV90EBJJSXhFv9QSbU0IiUci+N4vaX3hl+fMbCSYJZ5GtlzAPu\nRAZuJa0GCEkxeR6oCyc4y1bfWwKBgQDYfatODjQI0XwwpRYWzJmojZuGh+eA5Tih\nwZmPxeDBJ8mn7v0Dg3dobJcBg0V+HyFwBxweqLvsImpgjy6tgWccT0IuK0YMZT9J\nwhwUzEv0v4uOpyFcHE4ldkLnxmVo85YoxjolzSEPXjZjgA6YLh8HU22y8uQ0Q716\n9b0n08QJwQKBgHScCrmn3keYDqDCEBpR/jASDIW492/hYq0Khz9q1dpMPrQmlWk5\nuTj/kyDXSh90oRwvQC3hL+pBcRLrfkwOxLpy36nb/jrowllnaI/T0mHt3/bmz8YH\nnDs8Pt7jl4EcRyWtLPc3tnZL6JoY9fSpS2RqUI6LBPs8dUACsSpphJAjAoGAY/FI\nFyXJcdS7330nAGl9+mk9RlMRVdj8VviYWt5ADwu+Na/H0Ept4qBW6hTfDQV0G1K8\n8Y52CuIsd91B8EmP/2q7o7LIiMpo+DULX7Kc0iVnWPjhFrPeg77fzj4x7MyfIr24\ndGEJhR26QB8LHcgU/P3P48/r+BDZtZ0isPM7SkECgYEAgyAR1hG0rfrd9ajbGLpx\nXGJ7fo6vQW2OG96jGXpg12N70JwKtoAYw2ZaRn7ajSXXh8JFlyw5334uOO97+65D\n6dVG2T0KNh5FsrVptNZgZuc/PJXf4mEkYWVRHzE3VFfc0y4RBgVsN8cHpH9nIe3K\nhCfESjU6fePEAo1dFIUfTco=\n-----END PRIVATE KEY-----\n",
      "client_email": "firebase-adminsdk-fbsvc@students-app-4b35f.iam.gserviceaccount.com",
      "client_id": "110426202408684217122",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://oauth2.googleapis.com/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40students-app-4b35f.iam.gserviceaccount.com",
      "universe_domain": "googleapis.com"
    }
Enter fullscreen mode Exit fullscreen mode

Step 9: Create a file named form_screen.dart
in your project. Then, copy and paste the following content into the file.

import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:push_notification/notification_network.dart';


class FormScreen extends StatefulWidget {
  const FormScreen({super.key, required this.title});
  final String title;

  @override
  State<FormScreen> createState() => _FormScreenState();
}

class _FormScreenState extends State<FormScreen> {
  TextEditingController titleCtr = TextEditingController();
  TextEditingController descriptionCtr = TextEditingController();

  void _incrementCounter() async{
    String? fcmToken = await FirebaseMessaging.instance.getToken();

    log("fcmToken fcmToken $fcmToken");

    SendNotificationAccess.sendNotificationWithHttp(
        token: fcmToken!,body: descriptionCtr.text.trim(),title: titleCtr.text.trim());

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.only(left: 15,right: 15),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextFormField(
                controller: titleCtr,
                decoration: InputDecoration(
                  hintText: "Title"
                ),
              ),
              SizedBox(height: 50),
              TextFormField(
                controller: descriptionCtr,
                decoration: InputDecoration(
                    hintText: "Descripton"
                ),
              )
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

If everything is set up correctly, call your view in the main.dart file and run the project.

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:push_notification/form_screen.dart';
import 'package:push_notification/notification_service.dart';

void main() async{
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  final AppNotification appNotification = AppNotification();
  appNotification.initializeFcmNotification();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Push Notifications',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const FormScreen(title: 'Push Notifications'),
    );
  }
}


Enter fullscreen mode Exit fullscreen mode

Top comments (0)