flutter_local_notification_plus 0.1.0
flutter_local_notification_plus: ^0.1.0 copied to clipboard
Enhanced local notifications with rich media, actions, and scheduling for Flutter
import 'package:flutter/material.dart';
import 'package:flutter_local_notification_plus/flutter_local_notification_plus.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Local Notification Plus Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Local Notification Plus Example'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isInitialized = false;
int _badgeCount = 0;
List<Map<String, dynamic>> _pendingNotifications = [];
@override
void initState() {
super.initState();
_initializeNotifications();
}
Future<void> _initializeNotifications() async {
try {
final result = await FlutterLocalNotificationPlus.initialize();
if (mounted) {
setState(() {
_isInitialized = true;
});
if (result) {
await _refreshBadge();
await _refreshPendingNotifications();
} else {
// If initialization returned false, try requesting permissions
final granted = await FlutterLocalNotificationPlus.requestPermissions();
if (!mounted) return;
if (granted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Permissions granted!')),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Notification permissions not granted. Please enable in settings.'),
duration: Duration(seconds: 5),
),
);
}
}
}
} catch (e) {
if (mounted) {
setState(() {
_isInitialized = true; // Set to true even on error so UI is usable
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to initialize: $e')),
);
}
}
}
Future<void> _refreshBadge() async {
final count = await FlutterLocalNotificationPlus.getBadgeCount();
setState(() {
_badgeCount = count;
});
}
Future<void> _refreshPendingNotifications() async {
try {
final pending = await FlutterLocalNotificationPlus.getPendingNotifications();
setState(() {
_pendingNotifications = pending;
});
} catch (e) {
if (mounted) {
_showMessage('Failed to get pending notifications: $e');
}
}
}
void _showMessage(String message) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
}
// Basic Notification
Future<void> _showBasicNotification() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await FlutterLocalNotificationPlus.showNotification(
id: 1,
title: 'Basic Notification',
body: 'This is a simple notification',
);
_showMessage('Basic notification sent!');
} catch (e) {
_showMessage('Failed: $e');
}
}
// Rich Media Notification
Future<void> _showRichMediaNotification() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await FlutterLocalNotificationPlus.showNotification(
id: 2,
title: 'Rich Media Notification',
body: 'This notification includes rich media features',
options: {
'icon': 'https://via.placeholder.com/150', // Web/Android
'badge': 5,
'image': 'https://via.placeholder.com/400x200', // iOS/Android/Web
'tag': 'rich_media',
},
);
_showMessage('Rich media notification sent!');
await _refreshBadge();
} catch (e) {
_showMessage('Failed: $e');
}
}
// Notification with Actions
Future<void> _showActionNotification() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await FlutterLocalNotificationPlus.showNotification(
id: 3,
title: 'Action Required',
body: 'Please respond to this notification',
options: {
'actions': [
{'id': 'accept', 'title': 'Accept'},
{'id': 'decline', 'title': 'Decline'},
{'id': 'maybe', 'title': 'Maybe Later'},
],
'sound': 'default',
'vibration': true,
},
);
_showMessage('Action notification sent! Tap the notification to see actions.');
} catch (e) {
_showMessage('Failed: $e');
}
}
// Styled Notification
Future<void> _showStyledNotification() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await FlutterLocalNotificationPlus.showNotification(
id: 4,
title: 'Styled Notification',
body: 'This notification has custom styling with sound and vibration',
options: {
'sound': 'default',
'vibration': true,
'badge': 10,
'requireInteraction': true, // Web only
},
);
_showMessage('Styled notification sent!');
await _refreshBadge();
} catch (e) {
_showMessage('Failed: $e');
}
}
// Schedule Notification
Future<void> _scheduleNotification() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
final scheduledTime = DateTime.now().add(const Duration(seconds: 5));
await FlutterLocalNotificationPlus.scheduleNotification(
id: 5,
title: 'Scheduled Notification',
body: 'This notification was scheduled for 5 seconds from now',
scheduledDate: scheduledTime,
);
_showMessage('Notification scheduled for 5 seconds!');
await _refreshPendingNotifications();
} catch (e) {
_showMessage('Failed: $e');
}
}
// Recurring Notification
Future<void> _scheduleRecurringNotification() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
final scheduledTime = DateTime.now().add(const Duration(seconds: 3));
await FlutterLocalNotificationPlus.scheduleNotification(
id: 6,
title: 'Recurring Notification',
body: 'This notification repeats every minute',
scheduledDate: scheduledTime,
options: {
'repeatInterval': 'minute', // minute, hour, day, week, month
},
);
_showMessage('Recurring notification scheduled (every minute)!');
await _refreshPendingNotifications();
} catch (e) {
_showMessage('Failed: $e');
}
}
// Interval-based Notification
Future<void> _scheduleIntervalNotification() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
final scheduledTime = DateTime.now().add(const Duration(seconds: 2));
await FlutterLocalNotificationPlus.scheduleNotification(
id: 7,
title: 'Interval Notification',
body: 'This notification repeats every 10 seconds',
scheduledDate: scheduledTime,
options: {
'interval': 10.0, // seconds
'repeats': true,
},
);
_showMessage('Interval notification scheduled (every 10 seconds)!');
await _refreshPendingNotifications();
} catch (e) {
_showMessage('Failed: $e');
}
}
// Cancel Specific Notification
Future<void> _cancelNotification() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await FlutterLocalNotificationPlus.cancelNotification(5);
_showMessage('Notification #5 cancelled!');
await _refreshPendingNotifications();
} catch (e) {
_showMessage('Failed: $e');
}
}
// Cancel All Notifications
Future<void> _cancelAllNotifications() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await FlutterLocalNotificationPlus.cancelAllNotifications();
_showMessage('All notifications cancelled!');
await _refreshPendingNotifications();
await _refreshBadge();
} catch (e) {
_showMessage('Failed: $e');
}
}
// Get Pending Notifications
Future<void> _getPendingNotifications() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await _refreshPendingNotifications();
_showMessage('Found ${_pendingNotifications.length} pending notifications');
} catch (e) {
_showMessage('Failed: $e');
}
}
// Test Notification Grouping
Future<void> _testNotificationGrouping() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
// Send 3 individual notifications with the same groupKey
// They will be grouped together
await FlutterLocalNotificationPlus.showNotification(
id: 10,
title: 'Message from Alice',
body: 'Hey, how are you?',
options: {
'groupKey': 'messages', // Same group key groups them together
},
);
await Future.delayed(const Duration(milliseconds: 500));
await FlutterLocalNotificationPlus.showNotification(
id: 11,
title: 'Message from Bob',
body: 'Can we meet tomorrow?',
options: {
'groupKey': 'messages',
},
);
await Future.delayed(const Duration(milliseconds: 500));
await FlutterLocalNotificationPlus.showNotification(
id: 12,
title: 'Message from Charlie',
body: 'Thanks for your help!',
options: {
'groupKey': 'messages',
},
);
await Future.delayed(const Duration(milliseconds: 500));
// Send a summary notification (Android) or use threadId (iOS)
await FlutterLocalNotificationPlus.showNotification(
id: 13,
title: 'Messages',
body: 'You have 3 new messages',
options: {
'groupKey': 'messages',
'isGroupSummary': true, // This is the group summary
'summaryText': '3 new messages', // Summary text (Android)
'threadId': 'messages', // For iOS grouping
'summary': '3 new messages', // For iOS summary
},
);
_showMessage('Sent 3 grouped notifications + summary! Check your notification panel.');
} catch (e) {
_showMessage('Failed: $e');
}
}
// Check Permissions
Future<void> _checkPermissions() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
final enabled = await FlutterLocalNotificationPlus.areNotificationsEnabled();
_showMessage('Notifications enabled: $enabled');
} catch (e) {
_showMessage('Failed: $e');
}
}
// Request Permissions
Future<void> _requestPermissions() async {
try {
final granted = await FlutterLocalNotificationPlus.requestPermissions(
alert: true,
badge: true,
sound: true,
);
_showMessage('Permissions granted: $granted');
if (granted) {
setState(() {
_isInitialized = true;
});
}
} catch (e) {
_showMessage('Failed: $e');
}
}
// Badge Management
Future<void> _setBadge(int count) async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await FlutterLocalNotificationPlus.setBadgeCount(count);
_showMessage('Badge set to $count');
await _refreshBadge();
} catch (e) {
_showMessage('Failed: $e');
}
}
Future<void> _clearBadge() async {
if (!_isInitialized) {
_showMessage('Notifications not initialized');
return;
}
try {
await FlutterLocalNotificationPlus.clearBadge();
_showMessage('Badge cleared');
await _refreshBadge();
} catch (e) {
_showMessage('Failed: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
_refreshPendingNotifications();
_refreshBadge();
},
tooltip: 'Refresh',
),
],
),
body: _isInitialized
? _buildMainContent()
: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 20),
Text('Initializing notifications...'),
],
),
),
);
}
Widget _buildMainContent() {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Status Card
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Status',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Text('Initialized: ✅'),
Text('Badge Count: $_badgeCount'),
Text('Pending Notifications: ${_pendingNotifications.length}'),
],
),
),
),
const SizedBox(height: 16),
// Permissions (Most Important - Required First)
_buildSection(
title: 'Permissions',
children: [
_buildButton('Request Permissions', _requestPermissions),
_buildButton('Check Permissions', _checkPermissions),
],
),
// Basic Features (Core Functionality)
_buildSection(
title: 'Basic Features',
children: [
_buildButton('Show Basic Notification', _showBasicNotification),
],
),
// Rich Media (Important Feature)
_buildSection(
title: 'Rich Media',
children: [
_buildButton('Show Rich Media Notification', _showRichMediaNotification),
],
),
// Actions (Important Feature)
_buildSection(
title: 'Custom Actions',
children: [
_buildButton('Show Notification with Actions', _showActionNotification),
],
),
// Scheduling (Core Scheduling)
_buildSection(
title: 'Scheduling',
children: [
_buildButton('Schedule Notification (5s)', _scheduleNotification),
_buildButton('Schedule Recurring (every minute)', _scheduleRecurringNotification),
_buildButton('Schedule Interval (every 10s)', _scheduleIntervalNotification),
],
),
// Styling (Nice to Have)
_buildSection(
title: 'Styling Options',
children: [
_buildButton('Show Styled Notification', _showStyledNotification),
],
),
// Advanced Features
_buildSection(
title: 'Advanced Features',
children: [
_buildButton('Test Notification Grouping', _testNotificationGrouping),
],
),
// Management (Utility)
_buildSection(
title: 'Notification Management',
children: [
_buildButton('Get Pending Notifications', _getPendingNotifications),
_buildButton('Cancel Notification #5', _cancelNotification),
_buildButton('Cancel All Notifications', _cancelAllNotifications),
],
),
// Badge Management (Less Common)
_buildSection(
title: 'Badge Management',
children: [
_buildButton('Set Badge to 5', () => _setBadge(5)),
_buildButton('Set Badge to 10', () => _setBadge(10)),
_buildButton('Clear Badge', _clearBadge),
],
),
// Pending Notifications List
if (_pendingNotifications.isNotEmpty) ...[
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Pending Notifications',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
..._pendingNotifications.map((notification) {
final id = notification['id']?.toString() ?? 'Unknown';
final title = notification['title']?.toString() ?? 'No title';
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Text(
'ID: $id - $title',
style: Theme.of(context).textTheme.bodyMedium,
),
);
}),
],
),
),
),
],
],
),
);
}
Widget _buildSection({
required String title,
required List<Widget> children,
}) {
return Card(
margin: const EdgeInsets.only(bottom: 16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
title,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 12),
...children,
],
),
),
);
}
Widget _buildButton(String text, VoidCallback onPressed) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: ElevatedButton(
onPressed: onPressed,
child: Text(text),
),
);
}
}