Project Overview
The Seamless Notification Delivery System was designed to provide a fully automated and highly customizable push notification experience. The aim was to connect backend triggers with mobile app notifications, ensuring instant and efficient communication between users and the platform. Built for a client needing an advanced notification mechanism with real-time capabilities and personalized user experiences.
Workflow Overview
The following diagram illustrates the end-to-end workflow for the notification delivery system.
Workflow Steps
01 Event Triggering and Backend Processing
The workflow begins when an Event or Trigger occurs — either an automated cron job or a hook from an external action. The backend processes this trigger and initiates the necessary messaging through Firebase.
02 Triggering Firebase Messaging
The backend sends a trigger to Firebase Messaging, which broadcasts notifications. Firebase manages real-time data flow to ensure messages are delivered to the correct users instantly.
public async sendNotification({
registrationTokens,
title,
body,
data,
}: {
registrationTokens: string[];
title: string;
body: string;
data: any;
}) {
const message: MulticastMessage = {
data: { title, body, ...data },
tokens: registrationTokens,
};
try {
const response = await this.app.messaging().sendEachForMulticast(message);
logger.info('Successfully sent message:', response);
return response;
} catch (error) {
logger.info('Error sending message:', error);
throw error;
}
}
03 Broadcast via Awesome Notifications Package
Once Firebase has processed the message, it is broadcast through the Awesome Notifications Package. This package facilitates the creation of customized notifications, tailored to specific user preferences or roles.
04 Mobile App Reception and Data Handling
The Mobile App receives the notification and displays it according to user preferences. Each notification is also saved in the local database to provide a history of received messages.
Features and Solutions
01 Automated Trigger System
The system utilizes both manual and automated triggers. Notifications can be initiated through backend events, cron jobs, or manual actions by platform administrators. Notifications are divided based on user roles, allowing targeted, personalized messaging.
@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
await NotificationService().showNotification(message);
await ElasticServcie().logEvent(
MessageRecievedEvent(
timestamp: DateTime.now(),
message: message,
isBackgroundMessage: true,
),
);
}
02 Customized Notification Channels
The system allows the creation of custom channels with different sounds and visual configurations to suit specific user needs, making each notification type easily distinguishable.
final NotificationChannel highPriorityChannel = NotificationChannel(
channelKey: 'high_priority',
channelName: 'High Priority Notifications Channel',
channelDescription: 'Notification channel for high priority notifications.',
defaultColor: const Color(0xFF9D50DD),
ledColor: Colors.white,
playSound: true,
importance: NotificationImportance.High,
channelShowBadge: true,
enableVibration: true,
enableLights: true,
vibrationPattern: highVibrationPattern,
soundSource: "resource://raw/res_notification",
);
03 Integration with Firebase Messaging
We leveraged Firebase Messaging to facilitate real-time notifications. Firebase served as the bridge between the backend server and the mobile applications, broadcasting notifications quickly and reliably.
FirebaseMessaging.onMessage.listen((message) async {
await Firebase.initializeApp();
await NotificationService().showNotification(message);
await ElasticServcie().logEvent(
MessageRecievedEvent(
timestamp: DateTime.now(),
message: message,
),
);
});
04 Real-Time Delivery with Pusher
Pusher was integrated to enhance the speed and reliability of notifications, especially during high traffic. Pusher guarantees every notification — manual or automated — is delivered in real time to all active devices.
05 Mobile App Integration
A Flutter-based Mobile App received customized notifications via the Awesome Notifications Package. Notifications were stored locally to ensure users always had easy access to their recent messages.
Future<void> navigateToMessage() async {
final String? generalAccessToken = await _getGeneralAccessToken();
if (generalAccessToken != null && generalAccessToken.isNotEmpty) {
await AwesomeNotifications().resetGlobalBadge();
if (Get.isRegistered<MessagesController>()) {
await Get.find<MessagesController>().refreshData();
}
if (Get.currentRoute == homePageName) {
Get.find<HomeController>().currentTabIndex(1);
Get.find<HomeController>().tabController.index = 1;
} else {
Get.toNamed(permissionsPageName, arguments: {"homeTab": 1});
}
}
}
Challenges & Solutions
Challenge Creating notification channels that users can easily distinguish by type.
Solution Used the Awesome Notifications package to customize sounds, visual layouts, and channel identifiers — ensuring each notification type stands out clearly.
Challenge Establishing seamless connectivity between Firebase, backend logic, and the mobile app.
Solution Firebase served as an intermediary that handled all data flow smoothly between the backend and the Flutter app, abstracting away complexity.
Challenge Ensuring notifications were automated for different scenarios while maintaining a high level of personalization.
Solution The use of cron jobs, event-based hooks, and customized user roles ensured each notification was timely, relevant, and fully automated.
Impact
The implementation resulted in a highly efficient and automated notification process. The platform saw reduced operational costs through full automation, increased user engagement via real-time updates, and strong positive feedback on the customization and reliability of the notification system.