Source

Adding scheduled notifications in your Flutter Application

Tushar M

--

Disclaimer

The package used in this article has gone through a lot of changes and many of the methods used are now deprecated. With the updates, it has become a lot easier to schedule notifications and reading the documentation should suffice

I’m still leaving this article up here for reference if you are using the older versions

Introduction

I have been working on a Flutter application for the past few weeks. One of the features required me to implement scheduled notifications. After poring over several articles here and there, I concluded that the best way to go would be to use the flutter_local_notifications package available on pub.dev. No matter where I read, I didn’t quite find what I was looking for. The examples everywhere revolved around creating a dedicated Reminders app or were picked up straight from the package’s documentation. As a self-taught Flutter developer, I found resources rather inadequate at explaining what I was supposed to add and where it was to be added. I have taken the liberty to put together a little guide to implement this use-case for budding, self-taught app developers like myself without having a tough time.

Part 0: Adding dependencies

The foremost step is to add the required packages to your pubspec.yaml file under dependencies

dependencies:
flutter_local_notifications: ^1.4.2
rxdart: ^0.23.1

Once you have done this, run the following command on your terminal within your project folder to get the dependencies.

$ flutter pub get

Now that you’ve got these initial steps out of the way, it’s time to get down to business.

Part 1: The boilerplate stuff

A) Modifying the AndroidManifest.xml file

Now it’s time to add some permissions for the android version of the app. Head over to /android/app/src/main/ and add these lines if they aren’t already there

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

To ensure that previously scheduled notifications still work upon rebooting the device, add the following lines within the application tag, just after the activity tag closes

<receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>

B) Ensuring the assets are in place

Make sure you have added your app icon within the drawable folder (/android/app/src/main/res/drawable/). For this article, I have named my app icon “icon”. Be sure to make the necessary changes within your app.

C) Modifying the AppDelegate.swift file

A delegate must be registered for this to work on the iOS version. Make the following changes in the AppDelegate.swift file found in /ios/Runner/

Add

if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as ? UNUserNotificationCenterDelegate
}

just before

return super.application(application, didFinishLaunchingWithOptions: launchOptions)

Part 2: Creating a Notifications Helper

I like having my code organised so that it is easier to make changes and follow whenever I need to revisit it. The project I am working on has a ton of dart files within my lib folder. Thus, keeping the notifications-related code consolidated in one dart file made a lot of sense.

A) Importing the libraries

Create a notifications_helper.dart file and import the flutter_local_notifications and rxdart packages.

import 'package:flutter_local_notifications/flutter_local_notifications.dart'as notifs;
import 'package:rxdart/subjects.dart' as rxSub;

Note: I have added the “as notifs” and “as rxSub” so that it is easier to understand the following parts of code.

B) Initialisation

Then create a class which defines the structure of your notification. I used the following

class NotificationClass{
final int id;
final String title;
final String body;
final String payload;
NotificationClass({this.id, this.body, this.payload, this.title});
}

Next, we initialise two variables required for the Notification Stream

final rxSub.BehaviorSubject<NotificationClass> didReceiveLocalNotificationSubject =
rxSub.BehaviorSubject<NotificationClass>();
final rxSub.BehaviorSubject<String> selectNotificationSubject =
rxSub.BehaviorSubject<String>();

Now it’s time to initialise notifications. Add the following method to your helper file

Future<void> initNotifications(
notifs.FlutterLocalNotificationsPlugin
notifsPlugin) async {
var initializationSettingsAndroid =
notifs.AndroidInitializationSettings('icon');
var initializationSettingsIOS = notifs.IOSInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
onDidReceiveLocalNotification:
(int id, String title, String body, String payload) async {
didReceiveLocalNotificationSubject
.add(NotificationClass(id: id, title: title, body: body, payload: payload));
});
var initializationSettings = notifs.InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
await notifsPlugin.initialize(initializationSettings,
onSelectNotification: (String payload) async {
if (payload != null) {
print('notification payload: ' + payload);
}
selectNotificationSubject.add(payload);
});
print("Notifications initialised successfully");
}

This method is to be run in the main method within the main.dart file (i.e. when the app is run). It basically sets permissions et cetera for the Android and iOS versions

C) Creating a permission request method for iOS

As the header suggests, This is a generic permission request method to ensure iOS users receive the notifications scheduled.

void requestIOSPermissions(
notifs.FlutterLocalNotificationsPlugin notifsPlugin) {
notifsPlugin.resolvePlatformSpecificImplementation<notifs.IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}

D) Creating the scheduled notification

We need to create a method that dictates the behaviour and specifics for a scheduled notification in Android as well as iOS. Add the following method in the helper file

Future<void> scheduleNotification(
{notifs.FlutterLocalNotificationsPlugin notifsPlugin,
String id,
String title,
String body,
DateTime scheduledTime}) async {
var androidSpecifics = notifs.AndroidNotificationDetails(
id, // This specifies the ID of the Notification
'Scheduled notification', // This specifies the name of the notification channel
'A scheduled notification', //This specifies the description of the channel
icon: 'icon',
);
var iOSSpecifics = notifs.IOSNotificationDetails();
var platformChannelSpecifics = notifs.NotificationDetails(
androidSpecifics, iOSSpecifics);
await notifsPlugin.schedule(0, title, "Scheduled notification",
scheduledTime, platformChannelSpecifics); // This literally schedules the notification
}

There are many options available within the platform-specific notification details (AndroidNotificationDetails and IOSNotificationDetails). These allow you to customise the look of the notification. I haven’t explored all of them here; for the sake of brevity. Going through the documentation or just inspecting the definition of the methods will let you add a whole bunch of tweaks.

Part 3: Modifying the main.dart file

Now it’s time to get down to the real stuff. First, we must create instances of NotificationAppLaunchDetails and FlutterLocalNotificationsPlugin.

NotificationAppLaunchDetails notifLaunch;
final FlutterLocalNotificationsPlugin notifsPlugin= FlutterLocalNotificationsPlugin();

Now within the main method, add

notifLaunch = await notifsPlugin.getNotificationAppLaunchDetails();
await initNotifications(notifsPlugin);
requestIOSPermissions(notifsPlugin);

These statements initialise everything when the app runs, and in case of iOS, requests the necessary permissions

Part 4: Triggering a scheduled Notification

This is the part where you add the method to the desired dart file where you want the notification to be scheduled. I implemented it within an onPressed method.

A) Import your helper file and main.dart

import '../helpers/notifications_helper.dart';
import '../main.dart';

B) Call the scheduleNotification method

scheduleNotification(
notifsPlugin: notifsPlugin, //Or whatever you've named it in main.dart
id:
DateTime.now().toString(),
body: "A scheduled Notification",
scheduledTime: DateTime.now()); //Or whenever you actually want to trigger it

You could go a step further and define a duration starting from now after which you’d like the notification to be triggered.

Conclusion

I hope you find this useful for whenever you need to implement scheduled notifications within your app.

DISCLAIMER: I do not currently possess the tools to test the iOS implementation of this and hence cannot guarantee how well it works. I shall update the article upon testing it on iOS. That being said, all bases have been covered. There shouldn’t be any problem on the iOS version in theory.

References:

  1. This article that shows you how to make a reminder app of sorts
  2. The official flutter_local_notifications documentation

Thank you for reading. Happy coding :)

--

--

Tushar M

Undergrad engineering student, budding app-developer