alarm 0.2.0 copy "alarm: ^0.2.0" to clipboard
alarm: ^0.2.0 copied to clipboard

A simple Flutter alarm manager package for both iOS and Android.

Alarm package for iOS and Android #

This Flutter package provides a simple and easy-to-use interface for setting and canceling alarms on iOS and Android devices. It utilizes the android_alarm_manager_plus package for Android and the native iOS AVAudioPlayer class.

Please note that this project is still in beta. Feel free to send us your issues, questions and suggestions to help us in the project development.

Why this package ? #

As a Flutter developer at Evolum, my CTO and I needed to develop an alarm feature for the new version of our app.

An alarm feature is a great way to increase users engagement.

For the Android part, we used android_alarm_manager_plus package, but to be honest it was not very intuitive and incomplete.

Then, for the iOS part, we couldn't find any package or tutorial to add this feature.

Another issue we found is that when a user kills the app, all processes are terminated so the alarm may not ring. The workaround we thought about was to show a notification when the user kills the app to warn him that the alarm may not ring. Then, he just has to reopen the app to reschedule the alarm.

Therefore, we decided to write our own package to wrap everything and make it easy for everybody.

Under the hood #

Android #

oneShotAt from the package android_alarm_manager_plus, with an two-way communication isolated callback in order to start/stop the alarm and call onRing callback.

iOS #

invokeMethod that plays the alarm audio using AVAudioPlayer.

The issue is that asynchronous native code is suspended when app goes on background for a while. The workaround found is to listen to the app state (when app goes background/foreground), and every time app goes foreground, we check natively if the player is playing. If so, it means alarm is ringing so it's time to trigger the onRing callback.

Getting Started #

iOS installation steps #

To import your alarm audio(s), you will need to drag and drop your asset(s) to your Runner folder in Xcode. I published a Gist to show you the steps to follow, and also give you a tip to save your app some weight using symbolic links. It's right here.

Android installation steps #

In your android/app/build.gradle, make sure you have the following config:

android {
  compileSdkVersion 33
  [...]
  defaultConfig {
    [...]
    multiDexEnabled true
  }
}

After that, add the following to your AndroidManifest.xml within the <manifest></manifest> tags:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- For apps with targetSDK=31 (Android 12) -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>

Next, within the <application></application> tags, add:

<service
    android:name="dev.fluttercommunity.plus.androidalarmmanager.AlarmService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="false"/>
<receiver
    android:name="dev.fluttercommunity.plus.androidalarmmanager.AlarmBroadcastReceiver"
    android:exported="false"/>
<receiver
    android:name="dev.fluttercommunity.plus.androidalarmmanager.RebootBroadcastReceiver"
    android:enabled="false"
    android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

Finally, add your audio asset(s) to your project like usual.

How to use #

Add to your pubspec.yaml:

flutter pub add alarm

First, you have to initialize the Alarm service in your main function:

await Alarm.init()

Then, you have to define your alarm settings:

final alarmSettings = AlarmSettings(
  id: 42,
  dateTime: dateTime,
  assetAudioPath: 'assets/alarm.mp3',
  loopAudio: true,
  fadeDuration: 3.0,
  notificationTitle: 'This is the title',
  notificationBody: 'This is the body',
  enableNotificationOnKill: true,
);

And finally set the alarm:

await Alarm.set(settings: alarmSettings)
Property Type Description
id int Unique identifier of the alarm.
alarmDateTime DateTime The date and time you want your alarm to ring.
assetAudio String The path to you audio asset you want to use as ringtone. Can be local asset or network URL.
loopAudio bool If true, audio will repeat indefinitely until it is stopped.
fadeDuration double Duration, in seconds, over which to fade the alarm volume. Set to 0 by default, which means no fade.
notificationTitle String The title of the notification triggered when alarm rings if app is on background.
notificationBody String The body of the notification.
enableNotificationOnKill bool Whether to show a notification when application is killed to warn the user that the alarm he set may not ring. Enabled by default.

The notification shown on alarm ring can be disabled simply by ignoring the parameters notificationTitle and notificationBody. However, if you want a notification to be triggered, you will have to provide both of them.

If you enabled enableNotificationOnKill, you can chose your own notification title and body by using this method:

await Alarm.setNotificationOnAppKillContent(title, body)

This is how to stop/cancel your alarm:

await Alarm.stop()

This is how to run some code when alarm starts ringing. We implemented it as a stream so even if your app was previously killed, your custom callback can still be triggered.

Alarm.ringStream.stream.listen((_) => yourOnRingCallback());

To avoid unexpected behaviors, if you set an alarm for the same time as an existing one, the new alarm will replace the existing one.

Don't hesitate to check out the example's code, and take a look at the app:

alarm example 1 alarm example 2

Alarm behaviour #

After running multiple tests, iOS and Android seem to have the same behaviour:

iOS and Android (tested on OxygenOS)
Locked screen Still rings.
Silent / Mute Still rings.
Do not disturb Still rings but notification is silenced.
Sleep mode Still rings but notification is silenced.
While playing other media The alarm sound plays along with the media sound.
App killed Doesn't ring. Notification still shows.

FAQ #

My alarm is not firing on a specific Android device #

Some Android manufacturers prefer battery life over proper functionality of your apps. Check out dontkillmyapp.com to find out about more about optimizations done by different vendors, and potential workarounds. Source: https://pub.dev/packages/android_alarm_manager_plus#faq

Feature request #

If you have a feature request, just open an issue explaining clearly what you want and if you convince me I will develop it for you.

Contributing #

We welcome contributions to this package! If you would like to make a change or add a new feature, please follow these steps:

  1. Fork the repository and create a new branch for your changes.
  2. Make your changes
  3. Run flutter format and flutter test to ensure that your code is correctly formatted and passes all tests.
  4. Submit a pull request with a detailed description of your changes.

These are some features that I have in mind that could be useful:

  • Use ffigen and jnigen binding generators to call native code more efficiently instead of using method channels.
  • Optional vibrations when alarm rings
  • Notification actions: stop and snooze
  • Callback when alarm stops ringing
  • Add macOS, Windows, Linux and web support

Thank you for considering contributing to this package. Your help is greatly appreciated!

❤️ Let me know if you like the package by liking it on pub.dev and starring the repo on Github 🙂