A unified notification layer for Flutter that simplifies setup and usage of local notifications across Android, iOS, and macOS. Built with β€οΈ by MayR Labs.
- π± One-line setup β no native boilerplate required
- π Unified API for Android, iOS, and macOS
- π Simple scheduling and instant notifications
- π Automatic permission handling
- π― Zero configuration needed - just init and go!
- π§© Lightweight and minimal dependencies
Add to your pubspec.yaml:
dependencies:
mayr_local_notifications: ^1.0.0Then run:
flutter pub getFor Android apps, you need to add a few entries to your AndroidManifest.xml. Add this to android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Add these permissions before <application> -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<application ...>
<!-- Add this receiver inside <application> for scheduled notifications -->
<receiver
android:name="com.mayrlabs.mayr_local_notifications.NotificationReceiver"
android:exported="false" />
<!-- Your activities and other components -->
</application>
</manifest>Permissions are handled automatically!
When you call send() or schedule(), the plugin will automatically request permission if needed. You don't need to manually call requestPermission() unless you want to request permission upfront.
Import and initialize the plugin before running your app:
import 'package:flutter/material.dart';
import 'package:mayr_local_notifications/mayr_local_notifications.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize with default settings
await MayrLocalNotifications.init();
runApp(const MyApp());
}Show a notification right away. Permission is requested automatically if needed:
await MayrLocalNotifications.send(
title: 'Hello! π',
body: 'Welcome to MayR Local Notifications!',
);Schedule a notification for later. Permission is requested automatically if needed:
await MayrLocalNotifications.schedule(
title: 'Reminder π',
body: 'Don't forget your meeting at 3 PM.',
at: DateTime.now().add(const Duration(hours: 2)),
);Remove all pending scheduled notifications:
await MayrLocalNotifications.cancelAll();Initialize the notification system. Call this once in your main() function.
Parameters:
channelId(String, optional): Custom channel ID for Android. Default:'mayr_default_channel'channelName(String, optional): Custom channel name for Android. Default:'MayR Notifications'channelDescription(String, optional): Custom channel description for Android. Default:'Default notification channel'requestPermissions(bool, optional): Whether to automatically request notification permissions. Default:trueenableDebugLogs(bool, optional): Enable debug logging. Default:false
Example:
await MayrLocalNotifications.init(
channelId: 'my_custom_channel',
channelName: 'My App Notifications',
enableDebugLogs: true,
);Send an immediate notification.
Automatic Permission Handling: This method automatically requests notification permission if not already granted.
Parameters:
title(String, required): The notification titlebody(String, required): The notification body textpayload(Map<String, dynamic>, optional): Custom data to attach to the notification
Throws: Exception if permission is denied by the user.
Example:
await MayrLocalNotifications.send(
title: 'New Message',
body: 'You have received a new message!',
payload: {'userId': '123', 'type': 'message'},
);Schedule a notification for a specific time.
Automatic Permission Handling: This method automatically requests notification permission if not already granted.
Parameters:
title(String, required): The notification titlebody(String, required): The notification body textat(DateTime, required): When to show the notificationpayload(Map<String, dynamic>, optional): Custom data to attach to the notification
Throws: Exception if permission is denied by the user.
Example:
await MayrLocalNotifications.schedule(
title: 'Morning Reminder',
body: 'Time to start your day!',
at: DateTime(2025, 10, 20, 8, 0), // October 20, 2025 at 8:00 AM
);Cancel all pending scheduled notifications.
Example:
await MayrLocalNotifications.cancelAll();Request notification permissions from the user.
Note: You typically don't need to call this method directly, as send() and schedule() automatically request permission if needed. Use this method if you want to request permission upfront (e.g., during onboarding).
Returns true if permission is granted, false otherwise.
Platform Behavior:
- Android 13+ (API 33+): Shows the system permission dialog
- Android < 13: Returns
true(permissions granted at install time) - iOS/macOS: Requests notification authorization or returns current status
Example:
// Optional: Request permission upfront during onboarding
final granted = await MayrLocalNotifications.requestPermission();
if (granted) {
print('Permission granted!');
} else {
print('Permission denied');
// Show user a message to enable notifications in settings
}
// Or just send directly - permission is requested automatically!
await MayrLocalNotifications.send(
title: 'Test',
body: 'Notifications work!',
);Required Setup:
Add the following to your app's android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Add these permissions inside the <manifest> tag, before <application> -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<application ...>
<!-- Add this receiver inside the <application> tag for scheduled notifications -->
<receiver
android:name="com.mayrlabs.mayr_local_notifications.NotificationReceiver"
android:exported="false" />
<!-- Your other app components (activities, etc.) -->
</application>
</manifest>Permissions Explained:
POST_NOTIFICATIONS: Required for Android 13+ (API 33+) to show notificationsSCHEDULE_EXACT_ALARM&USE_EXACT_ALARM: Required for precise scheduling of notifications
Note: The plugin automatically creates a default notification channel and requests runtime permissions on Android 13+.
Custom Icon (Optional):
To use a custom notification icon, add a drawable resource named ic_notification.png to your Android res/drawable folders. Otherwise, the plugin will use your app's launcher icon.
Permissions:
The plugin automatically requests notification permissions during initialization. Ensure your app's Info.plist includes a usage description (this is optional but recommended):
<key>NSUserNotificationUsageDescription</key>
<string>This app uses notifications to keep you informed.</string>No other setup is required!
Permissions:
Similar to iOS, the plugin automatically requests notification permissions. Ensure your macOS app has the necessary entitlements. The plugin handles everything else automatically.
Check out the /example folder for a complete working demo that showcases:
- Immediate notifications
- Scheduled notifications
- Canceling notifications
- Status feedback
To run the example:
cd example
flutter runNotifications should be powerful but painless. MayR Local Notifications abstracts the complexity β you focus on the experience.
This plugin is designed with these principles:
- Zero Configuration: No manual setup of channels, icons, or permissions
- Cross-Platform: One API works everywhere
- Developer-Friendly: Clear API with helpful documentation
- Minimal Dependencies: Only what's necessary
Perfect for:
- Reminder apps
- Productivity tools
- Health and fitness trackers
- Educational apps with scheduled lessons
- Any app that needs simple local notifications
Common causes and solutions:
-
Missing AndroidManifest.xml setup (Most common!)
- Ensure you added the
<receiver>tag to yourandroid/app/src/main/AndroidManifest.xml - Ensure you added the permission tags (
POST_NOTIFICATIONS,SCHEDULE_EXACT_ALARM,USE_EXACT_ALARM) - See the Platform-Specific Setup section above
- Ensure you added the
-
Permission not granted (Android 13+)
- The app must request
POST_NOTIFICATIONSpermission at runtime - Use the
permission_handlerpackage to request permissions - Check if permission is granted: Go to Settings > Apps > Your App > Notifications
import 'package:permission_handler/permission_handler.dart'; Future<void> checkAndRequestPermission() async { final status = await Permission.notification.status; if (!status.isGranted) { await Permission.notification.request(); } }
- The app must request
-
Do Not Disturb mode
- Check that Do Not Disturb is not enabled on the device
- Check notification settings for your app in device Settings
-
Enable debug logs to see what's happening:
await MayrLocalNotifications.init(enableDebugLogs: true);
Then check Android Studio's Logcat for
[MayrLocalNotifications]messages -
Test with immediate notifications first
- If immediate notifications don't work, scheduled notifications won't work either
- Fix immediate notifications before testing scheduled ones
-
Permission not granted
- Check Settings > Your App > Notifications
- Ensure notifications are enabled for your app
-
App in foreground
- iOS/macOS won't show notification banners when the app is in the foreground
- Test by sending app to background or locking device
-
Enable debug logs to troubleshoot:
await MayrLocalNotifications.init(enableDebugLogs: true);
-
Ensure the BroadcastReceiver is registered (Android only)
- Check that you added the
<receiver>tag in AndroidManifest.xml - The receiver must be inside the
<application>tag
- Check that you added the
-
Check exact alarm permissions (Android 12+)
- Some devices require special permissions for exact alarms
- Add
SCHEDULE_EXACT_ALARMpermission to AndroidManifest.xml
-
Battery optimization
- Some devices may kill background processes
- Check device battery optimization settings for your app
| Version | Features |
|---|---|
| v1.0.0 | β Basic notifications (send, schedule, cancelAll) |
| v1.1.0 | π Tap callbacks and payload handling |
| v1.2.0 | π Notification history |
| v2.0.0 | π₯ Push notifications integration |
Contributions are highly welcome! If you have ideas for new extensions, improvements, or fixes, feel free to fork the repository and submit a pull request.
Please make sure to:
- Follow the existing coding style.
- Write tests for new features.
- Update documentation if necessary.
Let's build something amazing together!
If you encounter a bug, unexpected behaviour, or have feature requests:
- Open an issue on the repository.
- Provide a clear description and steps to reproduce (if it's a bug).
- Suggest improvements if you have any ideas.
Your feedback helps make the package better for everyone!
MayR Labs
Crafting clean, reliable, and human-centric Flutter and Dart solutions. π mayrlabs.com
This package is licensed under the MIT License β which means you are free to use it for commercial and non-commercial projects, with proper attribution.
See the LICENSE file for more details.
MIT Β© 2025 MayR Labs
If you find this package helpful, please consider giving it a βοΈ on GitHub β it motivates and helps the project grow!
You can also support by:
- Sharing the package with your friends, colleagues, and tech communities.
- Using it in your projects and giving feedback.
- Contributing new ideas, features, or improvements.
Every little bit of support counts! ππ