A push notification is a short message that appears as a pop-up on your desktop browser, mobile home screen, or in your device notification center from a mobile app. For receiving and showcasing push notifications in flutter using local_notifications. There are 3 conditions when we receive notifications
- When the app is closed.
- When the app is opened and the user is using it.
- When the app is not opened not it is completely closed. It is running in the background.
Here we will handle all the notifications.
Step By Step Implementation
Step 1: Create a Flutter project
flutter create .
Step 2: Add local notification package
// Add in dependencies in pubspec.yaml file flutter_local_notifications:
Step 3: Create 1 class for adding all local notifications functions and add an Instance of local notification in it
class LocalNotificationService {
// Instance of Flutternotification plugin
static final FlutterLocalNotificationsPlugin _notificationsPlugin =
FlutterLocalNotificationsPlugin();
} |
Step 4: Add initialize function in this class
static void initialize() {
// Initialization setting for android
const InitializationSettings initializationSettingsAndroid =
InitializationSettings(
android: AndroidInitializationSettings( "@drawable/ic_launcher" ));
_notificationsPlugin.initialize(
initializationSettingsAndroid,
// to handle event when we receive notification
onDidReceiveNotificationResponse: (details) {
if (details.input != null) {}
},
);
}
|
Step 5: Call this function in the Widget you are putting in the runApp function like this
Future main() async { runApp( const MyApp());
} class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
} class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
// Initialise localnotification
LocalNotificationService.initialize();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo' ,
theme: ThemeData(
primarySwatch: Colors.green,
),
home: const MyHomePage(title: 'Flutter Demo Home Page' ),
);
}
} |
Step 6: For handling all these conditions we have to add firebase messaging and for this add firebase to your flutter project
To add firebase to your project read this article How to Add Firebase to Flutter App.
firebase_messaging: |
Step 7: To handle background notifications add this to the main function
Future main() async { FirebaseMessaging.onBackgroundMessage(backgroundHandler);
// To handle background message
runApp( const MyApp());
} // background handler Future backgroundHandler(RemoteMessage msg) async {} |
Step 8: Now to handle the other 2 conditions add this in the init function below initialization of local notification
@override void initState() {
super.initState();
LocalNotificationService.initialize();
// To initialise the sg
FirebaseMessaging.instance.getInitialMessage().then((message) {
});
// To initialise when app is not terminated
FirebaseMessaging.onMessage.listen((message) {
if (message.notification != null) {
LocalNotificationService.display(message);
}
});
// To handle when app is open in
// user divide and heshe is using it
FirebaseMessaging.onMessageOpenedApp.listen((message) {
print( "on message opened app" );
});
}
|
Step 9: To display notifications you have to add this function in the local notification
static Future< void > display(RemoteMessage message) async {
// To display the notification in device
try {
print(message.notification!.android!.sound);
final id = DateTime.now().millisecondsSinceEpoch ~/ 1000;
NotificationDetails notificationDetails = NotificationDetails(
android: AndroidNotificationDetails(
message.notification!.android!.sound ?? "Channel Id" ,
message.notification!.android!.sound ?? "Main Channel" ,
groupKey: "gfg" ,
color: Colors.green,
importance: Importance.max,
sound: RawResourceAndroidNotificationSound(
message.notification!.android!.sound ?? "gfg" ),
// different sound for
// different notification
playSound: true ,
priority: Priority.high),
);
await _notificationsPlugin.show(id, message.notification?.title,
message.notification?.body, notificationDetails,
payload: message.data[ 'route' ]);
} catch (e) {
debugPrint(e.toString());
}
|
Also, add these settings to the android folder
1. Create a file named colors.xml in android/app/src/main/res/values and add these codes to this file
<? xml version = "1.0" encoding = "utf-8" ?>
< color name = "green" >#00FF00</ color >
</ resources >
|
2. Add this code in android/app/src/main/AndroidManifest.xml
< meta-data android:name = "com.google.firebase.messaging.default_notification_icon"
android:resource = "@drawable/ic_launcher" >
< meta-data android:name = "com.google.firebase.messaging.default_notification_color"
android:resource = "@color/green" >
|
Note:
If you want to receive notifications you need 1 token which is unique for every phone and may expire in some time. You need to store this token in your server if you want to send notifications to individual people To get the token you can use this function of firebase messaging
// in some device or platform specially in web // it may happen gettoken is not supported then // you can put these condition to so that // you can not get any error in production var notifyToken = FirebaseMessaging.instance.isSupported() ? await FirebaseMessaging.instance
.getToken()
: "notifyToken" ;
|
Now you can receive notifications on your android phone. For receiving notifications on the web you have to do the following settings. Create this file in the web folder and named as firebase-messaging-sw.js
/*Update with yours config*/
const firebaseConfig = {
apiKey: "YOur Key-EW_U6NZU-A" ,
authDomain: "flutter-notification-test-gfg.firebaseapp.com" ,
projectId: "flutter-notification-tes-fec9d" ,
storageBucket: "flutter-dsd-tes-fec9d.gfg.com" ,
messagingSenderId: "263307381024" ,
appId: "1:263307381024:web:dsds" ,
measurementId: "G-dsada"
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
/*messaging.onMessage((payload) => {
console.log('Message received. ', payload);*/
messaging.onBackgroundMessage( function (payload) {
console.log( 'Received background message ' , payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
};
self.registration.showNotification(notificationTitle,
notificationOptions);
});
|
3. Do the following changes in index.html
<!DOCTYPE html> < html >
< head >
< meta charset = "UTF-8" >
< title >flutter_notification_test</ title >
</ head >
< body >
< script >
<!--Update with yours config-->
const firebaseConfig = {
apiKey: "your key-EW_U6NZU-A",
authDomain: "flutter-notification-temp-fec9d.gfg.com",
projectId: "flutter-notification-tes-fec9d",
storageBucket: "flutter-dasdadas-tes-fec9d.appspot.com",
messagingSenderId: "dasdsa",
appId: "1:263307381024:web:dsadads",
measurementId: "G-dsadsa"
};
firebase.initializeApp(firebaseConfig);
</ script >
< script src = "main.dart.js" type = "application/javascript" ></ script >
< script >
if ("serviceWorker" in navigator) {
window.addEventListener("load", function () {
navigator.serviceWorker.register("/firebase-messaging-sw.js");
});
}
</ script >
</ body >
</ html >
|
4. Add this function in location_notification_service.dart file in the lib folder
void messageListener(BuildContext context) {
// Either you can pass buildcontext or you
// can take a context from navigator key
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print( 'Got a message in the foreground!' );
print( 'Message data: ${message.data}' );
if (message.notification != null) {
print(
'Message also contained a notification: so it will pop up ${message.notification.body}' );
showDialog(
context: context,
// context: navigatorKey!.currentContext!,
builder: ((BuildContext context) {
return DynamicDialog(
title: message.notification.title,
body: message.notification.body);
}));
}
});
}
|
For dynamic dialog either add this code below localnotificationservice class file or create a new file
import 'package:flutter/material.dart' ;
class DynamicDialog extends StatefulWidget {
final title;
final body;
const DynamicDialog({ this .title, this .body});
@override
_DynamicDialogState createState() => _DynamicDialogState();
} class _DynamicDialogState extends State<DynamicDialog> {
@override
Widget build(BuildContext context) {
// You can change the UI as per
// your requirement or choice
return AlertDialog(
title: Text(widget.title),
actions: <Widget>[
OutlinedButton.icon(
label: const Text( 'Close' ),
onPressed: () {
Navigator.pop(context);
},
icon: const Icon(Icons.close))
],
content: Text(widget.body),
);
}
} |
Call these functions below the initialization of the local_notification service like this
@override void initState() {
super.initState();
LocalNotificationService.initialize();
LocalNotificationService.messageListener(context);
FirebaseMessaging.onBackgroundMessage(backgroundHandler);
FirebaseMessaging.instance.getInitialMessage().then((message) {
print( "Initial Message ${message.toString()}" );
});
FirebaseMessaging.onMessageOpenedApp.listen((event) {
print( "Message on App opened ${event.toString()}" );
});
FirebaseMessaging.onMessage.listen((event) {
print( "Message when it is termination mode ${event.toString()}" );
if (event.notification != null) {
LocalNotificationService.display(event);
}
});
}
|