flutter_local_notification_plus 0.1.0 copy "flutter_local_notification_plus: ^0.1.0" to clipboard
flutter_local_notification_plus: ^0.1.0 copied to clipboard

Enhanced local notifications with rich media, actions, and scheduling for Flutter

example/lib/main.dart

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),
      ),
    );
  }
}
2
likes
160
points
34
downloads

Publisher

verified publisherbechattaoui.dev

Weekly Downloads

Enhanced local notifications with rich media, actions, and scheduling for Flutter

Repository (GitHub)
View/report issues

Topics

#flutter #notifications #local-notifications #cross-platform #wasm

Documentation

API reference

Funding

Consider supporting this project:

github.com

License

MIT (license)

Dependencies

flutter, flutter_web_plugins

More

Packages that depend on flutter_local_notification_plus

Packages that implement flutter_local_notification_plus