Unhandled Exception: PlatformException(exact_alarms_not_permitted, Exact alarms are not permitted, null, null)

3 min read 05-10-2024
Unhandled Exception: PlatformException(exact_alarms_not_permitted, Exact alarms are not permitted, null, null)


Understanding and Resolving the "PlatformException(exact_alarms_not_permitted...)" Error in Flutter

Have you encountered the frustrating "PlatformException(exact_alarms_not_permitted, Exact alarms are not permitted, null, null)" error in your Flutter app? This error, often encountered when working with background tasks and alarms, can leave you scratching your head.

The Problem: This error indicates that your app is attempting to set an exact alarm (triggering a task at a specific time), but the platform (either Android or iOS) does not allow it. This limitation is due to security and battery-saving concerns.

Simplifying the Issue: Imagine you're trying to schedule a reminder to wake up at exactly 7:00 AM every day. The platform is saying "Hold on! You can't be that specific. You need to give me a bit more flexibility."

Code Example:

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  @override
  void initState() {
    super.initState();
    initializeNotifications();
  }

  void initializeNotifications() async {
    // Initialize the notifications plugin
    var initializationSettingsAndroid =
        AndroidInitializationSettings('app_icon');
    var initializationSettingsIOS = IOSInitializationSettings(
        requestSoundPermission: false,
        requestBadgePermission: false,
        requestAlertPermission: false,
        onDidReceiveLocalNotification:
            (int id, String title, String body, String payload) async {});
    var initializationSettings = InitializationSettings(
        android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
    await flutterLocalNotificationsPlugin.initialize(initializationSettings);

    // Scheduling the alarm (causing the error)
    await flutterLocalNotificationsPlugin.schedule(
        0, // ID
        'Reminder', // Title
        'Wake up!', // Body
        DateTime.now().add(Duration(seconds: 5)), // Time
        // Here's the culprit!
        // This sets an exact alarm which is not allowed on Android
        const AndroidNotificationDetails('channel id', 'channel name',
            channelDescription: 'channel description'));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Local Notifications'),
      ),
      body: Center(
        child: Text('Press the button to schedule a notification'),
      ),
    );
  }
}

The Solution:

The key is to understand that Android and iOS restrict the use of exact alarms. Instead, you need to use a more flexible approach:

  1. Use Repeating Alarms: Set an alarm to repeat at a specific interval (e.g., every day, every hour). You can then adjust the time within the interval to get the desired result.

  2. Use Delayed Alarms: Schedule an alarm for a certain time in the future, but allow some flexibility. For example, schedule an alarm for 5 minutes from now, then use a timer to check for the actual desired time within that 5-minute window.

Example Implementation:

// Use delayed alarms to schedule a notification at a desired time
await flutterLocalNotificationsPlugin.schedule(
  0,
  'Reminder',
  'Wake up!',
  DateTime.now().add(Duration(seconds: 30)), // Delay for 30 seconds
  const AndroidNotificationDetails('channel id', 'channel name',
      channelDescription: 'channel description'),
);

// Use timer to check for the exact desired time within the delay
Timer(Duration(seconds: 30), () {
  if (DateTime.now() == desiredDateTime) {
    // Trigger the notification at the exact time
    flutterLocalNotificationsPlugin.show(
      0,
      'Reminder',
      'Wake up!',
      const AndroidNotificationDetails('channel id', 'channel name',
          channelDescription: 'channel description'),
    );
  }
});

Additional Considerations:

  • Background Tasks: If you need to perform background tasks, explore the workmanager plugin for Android and iOS to schedule reliable background jobs.

  • Battery Consumption: Avoid scheduling excessive alarms or background tasks to minimize battery drain.

  • Platform Specifics: The exact requirements and best practices may vary between Android and iOS. Consult the official documentation for both platforms.

By understanding the limitations of exact alarms and adapting your scheduling strategies, you can ensure a smoother development experience and create reliable background tasks for your Flutter apps.