flutter_awesome_notification 2.0.1
flutter_awesome_notification: ^2.0.1 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 notifications with intelligent filtering and seamless navigation across all app states.
β¨ Features #
- β Foreground Notification Handling: Display notifications when app is active
- β Custom Filtering: Flexible callback-based filtering for app-specific logic
- β Navigation Integration: Seamless navigation across all app states (foreground/background/terminated)
- β 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 type safety with comprehensive configuration
π¦ Repository #
- Repository: GitHub
- Pub.dev: Package
- Issues: GitHub Issues
- Changelog: CHANGELOG.md
π Quick Start #
Installation #
Add to your pubspec.yaml:
dependencies:
flutter_awesome_notification: ^2.0.1
firebase_core: ^3.8.0
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();
// Step 1: Initialize Firebase FIRST
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// Step 2: Initialize the notification plugin with Firebase instance
await FlutterAwesomeNotification.initialize(
config: FlutterAwesomeNotificationConfig(
firebaseApp: Firebase.app(), // Pass initialized Firebase instance
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');
},
),
);
runApp(MyApp());
}
That's it! You now have full notification support with just a few lines of code.
β οΈ Important: Always initialize Firebase BEFORE the notification plugin. The plugin validates Firebase initialization and provides helpful error messages if Firebase is not ready.
π Configuration #
Complete Configuration Example #
// Initialize Firebase first
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
// Then initialize notification plugin
await FlutterAwesomeNotification.initialize(
config: FlutterAwesomeNotificationConfig(
// REQUIRED - Pass initialized Firebase instance
firebaseApp: Firebase.app(),
// 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');
},
customFilter: (messageData) async {
// Your app-specific filtering logic
// Example: Filter notifications based on type and user
final type = messageData['type'];
final excludeUserId = messageData['excludeUserId'];
final currentUserId = getCurrentUserId();
// Don't show user's own action notifications
if (type == 'action_step_completion' && excludeUserId == currentUserId) {
return false; // Don't show
}
// Show all other notifications
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);
// },
// 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: FlutterAwesomeNotificationConfig(
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"
}
}
Custom Filtering #
The plugin provides a flexible filtering system via the customFilter callback:
customFilter: (messageData) async {
// Implement your app-specific filtering logic here
// Return true to show notification, false to hide it
// Example: Filter by notification type
final type = messageData['type'];
if (type == 'spam') return false;
// Example: Filter by user
final userId = messageData['userId'];
if (userId == currentUserId) return false;
// Example: Filter by app state
final chatRoomId = messageData['chatRoomId'];
if (isUserInChatRoom(chatRoomId)) return false;
return true; // Show by default
}
π Migration Guide #
From Manual FCM Setup #
If you're currently handling FCM manually, migration is straightforward:
// Before (Manual Setup)
FirebaseMessaging.onMessage.listen((message) {
// Custom filtering logic
// Manual notification display
// Navigation handling
});
FirebaseMessaging.onMessageOpenedApp.listen((message) {
// Navigation from background tap
});
FirebaseMessaging.getInitialMessage().then((message) {
// Navigation from terminated state
});
// After (Plugin)
await FlutterAwesomeNotification.initialize(
config: FlutterAwesomeNotificationConfig(
firebaseOptions: DefaultFirebaseOptions.currentPlatform,
onNavigate: (pageName, id, data) {
// Your navigation logic here
// Works for all app states automatically
},
),
);
// That's it! Plugin handles everything else
π± 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 #
We welcome contributions! Please feel free to submit issues, feature requests, or pull requests.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
π Support & Issues #
- π Documentation: GitHub README
- π Bug Reports: GitHub Issues
- π‘ Feature Requests: GitHub Issues
- π§ General Questions: Use GitHub Discussions