Mastering Flutter Notifications Part .1

hab
6 min readDec 19, 2023

--

Hey Flutter enthusiasts! 🚀 Ever found yourself lost in the notification jungle, wondering how to make your Flutter app’s alerts pop with style? Look no further! Dive into our latest blog, “Mastering Flutter Notifications,” where we break down the art and science of keeping your users in the loop.

Expect a friendly guide, loaded with practical examples and real-world scenarios. Whether you’re a beginner craving clarity or a seasoned developer aiming to finesse your notification game, this blog is your one-stop shop.

Get ready to sprinkle some Flutter magic on your app’s alerts and keep your users smiling. 🌟✉️ Ready, set, Flutter! 💙 #Flutter #MobileDev #NotificationsMagic ✨

Note: This is the kickoff of my series diving into notifications. 🎉 Stay tuned for the upcoming iOS enchantment! 💙✉️ #NotificationSeries 🌟✨

Installation and Setup

Open your project’s pubspec.yaml file and add the following line under the dependencies section:

flutter_local_notifications: ^16.2.0

Always ensure you have the latest package version go to pub.dev. Run flutter pub get after making changes.

Implementations

Note: this implementation for android only

That’s all we need to apply local notifications. Now, let’s take a look at some code.

we will make the NotificationMangaerclass a singleton like this:

class NotificationManager {
static final NotificationManagerinstance = NotificationManager._();

final FlutterLocalNotificationsPlugin notification =
FlutterLocalNotificationsPlugin();

factory NotificationManager() {
return instance;
}

NotificationManager._() {
initializeNotifications();
}

But why make it a singleton? While static functions are an option, singletons are preferred when you need a single instance of a class with an instance-specific state or behavior. Singleton instances maintain their state throughout the app’s lifespan, providing consistent notification management.

Future<void> initializeNotifications() async {
// Step 1: Define Android Initialization Settings
const AndroidInitializationSettings androidInitializationSettings =
AndroidInitializationSettings('app_icon');

// Step 2: Combine Android Initialization Settings into Initialization Settings
const InitializationSettings initializationSettings =
InitializationSettings(
android: androidInitializationSettings,
);

// Step 3: Initialize Notifications with the Initialization Settings
await notification.initialize(
initializationSettings,
);
}d

Step 1: Define Android Initialization Settings:

This line creates an instance of AndroidInitiaizaionSettingswith the specified app_icon. This setting is used to configure the default icon for the notification on Android. You can find the content of the AndroidInitiaizaionSettingsclass here.

The next step is important. We need to add an icon to your app. Otherwise, you may encounter an error stating that the package cannot detect the app_icon, and nothing will happen. This is crucial. If you already have an icon but face an issue where the icon appears as a solid rectangle, follow these steps:

to resolve this we need help from the Android Asset Studio you will find there are many options but we need the Notification Icon Generatorjust drop the image and it will handle it after u have the notification icon you will have a drawable folder to copy and paste it into your Android folder resources.

Step 2: Combine Android Initialization Settings into Initialization Settings:

Here, the AndroidInitiaizaionSettings instance is combined with an overall InitializationSettingsinstance. This is necessary because the initialize method of FlutterLocalNotificationPluginrequires an InitializationSettingsobject that includes platform-specific settings. You can find the content of the InitializationSettingsclass here.

Step 3: Initialize Notifications with the Initialization Settings:

Finally, the initialize method is called on the FlutterLocalNotificationPlugin instance (notification). This method initializes the notification settings based on the provided InitializationSettings. The await keyword ensures that the initialization process is completed before proceeding.

Future<void> showNotification({
int id = 0,
String title = 'Notification Title',
String body = 'This is contain notification body',
}) async {
// Step 1: Define Android Notification Details
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'your_channel_id',
'your_channel_name',
importance: Importance.max,
priority: Priority.high,
ticker: 'Message for user'
sound: RawResourceAndroidNotificationSound('your_sound_file')
);

// Step 2: Combine Android Notification Details into Notification Details
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
);

// Step 3: Show the Notification
await notification.show(
id,
title,
body,
platformChannelSpecifics,
);
}

Step 1: Define Android Notification Details

This step creates an instance of AndroidNotificationDetails`, which contains Android-specific settings for the notification. It includes information such as channel ID, channel name, importance level, and priority.

channel ID:

When you need to issue a notification multiple times for the same event, you should avoid making a completely new notification. Instead, you should consider updating a previous notification. For that you need NotificationID. Notification can be updated.

Notification Channels:

allow us to separate notifications into different groups/categories. Every channel would have a common functionality. It allows the user to customize their notification settings.

importance:

  1. Importance.min:
  • The notification is considered minimally important. It might not make a sound or disrupt the user in any noticeable way.

2. Importance.low:

  • Notifications with low importance are considered less disruptive. They may not make a sound or appear in the status bar.

3. Importance.default:

  • This is the default importance level. Notifications with default importance will generally make a sound and appear in the status bar.

4. Importance.high:

  • High importance indicates that the notification is more important and may be shown as a heads-up notification, potentially interrupting the user’s current activity.

5. Importance.max:

  • This is the highest level of importance. Notifications with maximum importance are considered very important, and they are more likely to be shown as heads-up notifications, ensuring that they grab the user’s attention.

Ticker:

This is used to set the text that appears in the status bar when the notification is first shown. The “ticker” text is a concise message that gives a preview or summary of the notification content.

Sound:

First of all, create a raw folder inside the res folder of the Android project. Additionally, update the AndroidManifest.xml file to include the necessary permissions for sound.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your_package_name">

<!-- ... other manifest elements ... -->

<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application>

<!-- ... other application elements ... -->

<!-- Receiver for boot completed broadcast -->
<receiver android:enabled="true" android:exported="false" android:permission="android.permission.BIND_JOB_SERVICE" android:label="flutter_local_notifications_boot_receiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="com.ht.flutter_local_notifications_boot_receiver" />
</intent-filter>
</receiver>

</application>
</manifest>

Ensure you replace "your_package_name" with the actual package name of your Android app.

Adding these permissions allows your app to vibrate the device (if specified) and receive notifications after the device has been rebooted.

Note: that the sound file should be in the WAV format.

Step 2: Combine Android Notification Details into Notification Details

Here, the Android-specific notification details are combined into an overall NotificationDetails object. This object is used to encapsulate platform-specific details for the notification.

Step 3: Show the Notification

The showmethod is called on the FlutterLocalNotificationsPlugin instance (notification). This method takes parameters such as id, title, body, and platformChannelSpecifics. It displays the notification with the specified content and settings. The await keyword ensures that the notification is shown before moving on to the next code.

our class is ready to use but, before we use it we need to use the InitializeNotifications method on the main function to initialize our settings

void main() async { // don't forget the async & await
WidgetsFlutterBinding.ensureInitialized(); // and also we need to do this
await NotificationManager.instance.initializeNotifications(); // here
runApp(const MyApp());
}

now we can use it anywhere we want ex:

ElevatedButton(
// u can pass the title and the body and also a custom ID
onPressed: () => NotificationManager.instance.showNotification(),
child: const Text("Normal Notification"),
)

and this is the final shape of our class, for now,

import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class NotificationManager {
static final NotificationManager instance = NotificationManager._();

final FlutterLocalNotificationsPlugin notification =
FlutterLocalNotificationsPlugin();

factory NotificationManager() {
return instance;
}

NotificationManager._() {
initializeNotifications();
}

Future<void> initializeNotifications() async {
const AndroidInitializationSettings androidInitializationSettings =
AndroidInitializationSettings('app_icon');
const InitializationSettings initializationSettings =
InitializationSettings(
android: androidInitializationSettings,
);

await notification.initialize(
initializationSettings,
);
}

Future<void> showNotification({
int id = 0,
String title = 'Notification Title',
String body = 'This is contain notification body',
}) async {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'your_channel_id',
'your_channel_name',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker',
sound: RawResourceAndroidNotificationSound('your_sound_file')
);

const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
);

await notification.show(
id,
title,
body,
platformChannelSpecifics,
);
}
}

--

--