flutter_awesome_notification 0.0.2
flutter_awesome_notification: ^0.0.2 copied to clipboard
A comprehensive notification plugin for Flutter with FCM, local notifications, and intelligent filtering.
Flutter Awesome Notification đ #
A comprehensive, production-ready notification plugin for Flutter apps with Firebase Cloud Messaging (FCM) and local notifications. Handles foreground, background and terminated notifications and navigation on notification tap.
⨠Features #
- â Foreground Notification Handling: Intelligent foreground notification management
- â Intelligent Filtering: Action step, chat room, and custom notification filtering
- â Navigation Integration: Custom callbacks for navigation handling
- â Topic Subscriptions: Easy FCM topic management
- â Local Notifications: Immediate and scheduled local notifications
- â Highly Configurable: Builder pattern with sensible defaults
- â Minimal Code: Easy setup with very little boilerplate
- â FCM Token Management: Automatic token handling and refresh
- â Custom Logging: Integrate with your preferred logging solution
- â Type-Safe: Full TypeScript-style type safety
đ Quick Start #
Installation #
Add to your pubspec.yaml:
dependencies:
flutter_awesome_notification: ^0.0.2
Basic Setup #
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_awesome_notification/flutter_awesome_notification.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize the notification plugin BEFORE Firebase
await FlutterAwesomeNotification.initialize(
config: FlutterFlutterAwesomeNotificationConfig(
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
mainChannelId: 'my_app_notifications',
mainChannelName: 'My App Notifications',
onNotificationTap: (data) {
print('Notification tapped: $data');
},
onNavigate: (pageName, id, data) {
print('Navigate to: $pageName with id: $id');
},
),
);
// Initialize Firebase
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(MyApp());
}
That's it! You now have full notification support with just a few lines of code.
đ Configuration #
Complete Configuration Example #
await FlutterAwesomeNotification.initialize(
config: FlutterFlutterAwesomeNotificationConfig(
// REQUIRED
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
// Channel Configuration
mainChannelId: 'my_app_channel',
mainChannelName: 'My App Notifications',
mainChannelDescription: 'General notifications',
notificationIcon: '@mipmap/ic_launcher',
// Callbacks
onNotificationTap: (data) {
// Handle notification tap
print('Tapped: $data');
},
onNavigate: (pageName, id, data) {
// Custom navigation
// Example: GoRouter.of(context).push('/$pageName/$id');
},
getCurrentUserId: () {
// Return current user ID for filtering
return userCubit.getUserModel()?.id;
},
customFilter: (messageData) async {
// Custom filtering logic
// Return true to show, false to hide
return true;
},
// Logging Options
// Option 1: External logger (recommended - unified logging)
// Compatible with flutter_awesome_logger and other logging solutions
externalLogger: logger, // Your logger instance with d(), i(), w(), e() methods
// Option 2: Logger callback (legacy support)
// logger: (message, {error}) {
// myLogger.log(message, error: error);
// },
// Filtering Options
enableActionStepFiltering: true,
enableChatRoomFiltering: true,
isActiveChatRoom: (chatRoomId) {
// Check if user is currently in this chat room
return appCubit.isActiveChatRoom(chatRoomId);
},
chatPageRoute: 'chat-page',
// Notification Types
notificationTypeToPage: {
'action_step': 'challenge-details',
'chat_message': 'chat-room',
'event_reminder': 'event-details',
},
// Advanced
enableLogging: true,
requestPermissionOnInit: true,
showAlertInForeground: true,
showBadgeInForeground: true,
playSoundInForeground: true,
defaultNotificationTitle: 'New Update',
defaultNotificationBody: 'You have a new update',
environment: 'production',
),
);
Minimal Configuration #
For a basic setup, only Firebase options are required:
await FlutterAwesomeNotification.initialize(
config: FlutterFlutterAwesomeNotificationConfig(
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
),
);
đ¯ Usage #
Access the Service #
final notificationService = FlutterAwesomeNotification.instance;
Topic Subscriptions #
// Subscribe to a topic
await notificationService.subscribeToTopic('announcements');
// Unsubscribe from a topic
await notificationService.unsubscribeFromTopic('announcements');
Get FCM Token #
final token = await notificationService.getDeviceToken();
print('FCM Token: $token');
Show Local Notification #
await notificationService.showLocalNotification(
id: 123,
title: 'Hello!',
body: 'This is a local notification',
data: {'key': 'value'},
);
Schedule Notification #
await notificationService.scheduleNotification(
id: 124,
title: 'Reminder',
body: 'Don\'t forget to check this!',
scheduledDate: DateTime.now().add(Duration(hours: 2)),
data: {'reminder_type': 'task'},
);
Cancel Notifications #
// Cancel specific notification
await notificationService.cancelNotification(123);
// Cancel all notifications
await notificationService.cancelAllNotifications();
Check Notification Permissions #
final enabled = await notificationService.areNotificationsEnabled();
if (!enabled) {
await notificationService.requestPermissions();
}
Unified Logging with External Logger #
The plugin supports external logger instances for unified logging across your app:
// 1. Create or use your existing logger instance
class MyLogger {
void d(String message) => print('đ DEBUG: $message');
void i(String message) => print('âšī¸ INFO: $message');
void w(String message) => print('â ī¸ WARNING: $message');
void e(String message, {dynamic error, StackTrace? stackTrace}) {
print('â ERROR: $message');
if (error != null) print('Error: $error');
}
}
final logger = MyLogger();
// 2. Pass it to the plugin during initialization
await FlutterAwesomeNotification.initialize(
config: FlutterAwesomeNotificationConfig(
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
enableLogging: true,
externalLogger: logger, // đ¯ Your logger instance
),
);
Benefits:
- â Unified logging across all plugins (deeplink, notification, etc.)
- â
Compatible with
flutter_awesome_loggerand other logging solutions - â Consistent log format and filtering
- â No need for custom callbacks
Supported Log Levels:
d()- Debug messages (initialization, state changes)i()- Info messages (successful operations)w()- Warning messages (non-critical issues)e()- Error messages (failures, exceptions)
đ How It Works #
App State Behavior #
Foreground (App Open & Visible)
- FCM Message Received â
FirebaseMessaging.onMessagestream - Custom Filtering Applied â Action steps, chat rooms, user filtering
- Local Notification Shown â Via
flutter_local_notificationsplugin - Tap Navigation â
onNavigatecallback withpageNameandid
Background (App Minimized)
- FCM Message Received â System notification (if
notificationfield present) - No Custom Filtering â Plugin doesn't run in background
- User Taps Notification â
FirebaseMessaging.onMessageOpenedApptriggers - Navigation on App Open â Same
onNavigatecallback as foreground
Terminated (App Closed)
- FCM Message Received â System notification (if
notificationfield present) - No Custom Filtering â App not running
- User Taps Notification â Cold app launch with initial message
- Navigation on Launch â
FirebaseMessaging.getInitialMessage()âonNavigate
Key Differences by App State #
| Feature | Foreground | Background | Terminated |
|---|---|---|---|
| Custom Filtering | â Full | â None | â None |
| Notification Display | â Plugin | â System | â System |
| Navigation | â Immediate | â On tap | â On launch |
| Plugin Processing | â Active | â Dormant | â Dormant |
FCM Payload Requirements #
For Background/Terminated delivery:
{
"notification": {
"title": "New Message",
"body": "You have a new message"
},
"data": {
"pageName": "chat-room",
"id": "room123",
"type": "message"
}
}
â ī¸ Data-only payloads won't show in background/terminated:
// â Won't show in background/terminated
{
"data": {
"pageName": "chat-room",
"id": "room123"
}
}
Filtering System #
The plugin provides multiple layers of filtering:
- Action Step Filtering: Prevents users from seeing their own action notifications
- Chat Room Filtering: Hides notifications when user is in the chat room
- Custom Filtering: Your own logic via callback
- Type Filtering: Filter by notification type
đ§ Migration from Existing Service #
If you're using the notification_service/ from challenge_app, here's how to migrate:
Before (Old Code) #
// In main.dart
NotificationService.registerBackgroundMessageHandler();
await Firebase.initializeApp();
// In your app
await getIt<NotificationService>().initialize();
After (Plugin) #
// In main.dart
await FlutterAwesomeNotification.initialize(
config: FlutterAwesomeNotificationConfig(
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
onNotificationTap: (data) => AutoNavigation.handleNotificationTap(data),
getCurrentUserId: () => getIt<UserCubit>().getUserModel()?.id,
isActiveChatRoom: (id) => getIt<MyAppCubit>().isActiveChatRoom(id),
chatPageRoute: RouteNames.chatPage,
logger: (msg, {error}) => logger.d(msg, error: error),
),
);
await Firebase.initializeApp();
// That's it! No need for separate initialization
Example: my_bottom_nav_bar.dart #
Future<void> _initializeServices() async {
logger.i('MyBottomNavBar: Initializing services');
try {
final notificationService = FlutterAwesomeNotification.instance;
// Optional: Subscribe to topics
// await notificationService.subscribeToTopic('challenges');
logger.i('MyBottomNavBar: Services initialized');
} catch (e) {
logger.e('MyBottomNavBar: Error initializing services', error: e);
}
}
đą Server-Side Configuration #
FCM Message Format #
For proper filtering, send data-only messages:
{
"data": {
"type": "action_step_completion",
"excludeUserId": "user123",
"challengeId": "challenge456",
"pageName": "challenge-details",
"id": "challenge456",
"title": "Challenge Update",
"body": "Someone completed a step!"
},
"token": "fcm_device_token"
}
đ Troubleshooting #
Notifications Not Showing #
Foreground Issues:
- Check if permissions are granted:
final enabled = await notificationService.areNotificationsEnabled(); - Ensure plugin is initialized before Firebase initialization
- Check if custom filters are blocking notifications
Background/Terminated Issues:
- Critical: FCM payload must include
notificationfield:{ "notification": {"title": "Title", "body": "Body"}, // REQUIRED "data": {"pageName": "route"} } - Data-only payloads won't show in background/terminated states
- Custom filtering doesn't work in background/terminated
Navigation Not Working #
- Verify
onNavigatecallback is set - Ensure
pageNameis in notification data - Check navigation implementation in callback
đ Comparison #
| Feature | flutter_awesome_notification | Manual Setup |
|---|---|---|
| Setup Complexity | âī¸ Simple | âī¸âī¸âī¸âī¸ Complex |
| Lines of Code | ~10 lines | ~500+ lines |
| Filtering System | â Built-in | â Manual |
| Topic Management | â Built-in | â Manual |
| Documentation | â Complete | â Variable |
| Maintenance | â Plugin updates | â Manual updates |
đ License #
MIT License - see LICENSE file for details
đ¤ Contributing #
Contributions are welcome! Please open an issue or submit a PR.
đ Support #
For issues, questions, or feature requests, please open an issue on GitHub.