With the previous Flutter AlarmManager package deprecated, it has been now recommended that you use the Flutter AlarmManager Plus, which this tutorial covers. You can use this package to create an Alarm or Scheduling application with Flutter Android.
flutter_alarm_manager_plus is a Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire.
Note that this plugin supports only Android.
Here is how you use it.
Step 1: Install it
Start by installing the flutter_alarm_manager_plus
by declaring the following in your pubspec.yaml
:
dependencies:
android_alarm_manager_plus: ^2.0.2
Then sync to fetch it.
You can also fetch it by executing the following in your terminal:
flutter pub add android_alarm_manager_plus
Step 2: Add Permissions
In your AndroidManifest.xml
add the following permissions:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
Then within the same AndroidManifest.xml
, but inside the <application>..</application>
tags, add the following:
<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">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
Step 3: Import
Then import it into your project:
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
Step 4: Write Code
For example, let's say you want to run a printHellow()
function that greets the user every minute:
Here is the defintion of the method:
static void printHello() {
final DateTime now = DateTime.now();
final int isolateId = Isolate.current.hashCode;
print("[$now] Hello, world! isolate=${isolateId} function='$printHello'");
}
Then here is the main function:
main() async {
// Be sure to add this line if initialize() call happens before runApp()
WidgetsFlutterBinding.ensureInitialized();
await AndroidAlarmManager.initialize();
runApp(...);
final int helloAlarmID = 0;
await AndroidAlarmManager.periodic(const Duration(minutes: 1), helloAlarmID, printHello);
}
printHello
will then run (roughly) every minute, even if the main app ends. However, printHello
will not run in the same isolate as the main application. Unlike threads, isolates do not share memory and communication between isolates must be done via message passing
Full Example
- Start by installing the package as has been described.
- Add permissions as has been described.
- Replace your
main.dart
with the following code:
main.dart
import 'dart:isolate';
import 'dart:math';
import 'dart:ui';
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';
/// The [SharedPreferences] key to access the alarm fire count.
const String countKey = 'count';
/// The name associated with the UI isolate's [SendPort].
const String isolateName = 'isolate';
/// A port used to communicate from a background isolate to the UI isolate.
final ReceivePort port = ReceivePort();
/// Global [SharedPreferences] object.
SharedPreferences prefs;
Future<void> main() async {
// ignore: todo
// TODO(bkonyi): uncomment
WidgetsFlutterBinding.ensureInitialized();
// Register the UI isolate's SendPort to allow for communication from the
// background isolate.
IsolateNameServer.registerPortWithName(
port.sendPort,
isolateName,
);
prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey(countKey)) {
await prefs.setInt(countKey, 0);
}
runApp(const AlarmManagerExampleApp());
}
/// Example app for Espresso plugin.
class AlarmManagerExampleApp extends StatelessWidget {
const AlarmManagerExampleApp({Key key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: _AlarmHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class _AlarmHomePage extends StatefulWidget {
const _AlarmHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_AlarmHomePageState createState() => _AlarmHomePageState();
}
class _AlarmHomePageState extends State<_AlarmHomePage> {
int _counter = 0;
@override
void initState() {
super.initState();
AndroidAlarmManager.initialize();
// Register for events from the background isolate. These messages will
// always coincide with an alarm firing.
port.listen((_) async => await _incrementCounter());
}
Future<void> _incrementCounter() async {
print('Increment counter!');
// Ensure we've loaded the updated count from the background isolate.
await prefs.reload();
setState(() {
_counter++;
});
}
// The background
static SendPort uiSendPort;
// The callback for our alarm
static Future<void> callback() async {
print('Alarm fired!');
// Get the previous cached count and increment it.
final prefs = await SharedPreferences.getInstance();
final currentCount = prefs.getInt(countKey);
await prefs.setInt(countKey, currentCount + 1);
// This will be null if we're running in the background.
uiSendPort ??= IsolateNameServer.lookupPortByName(isolateName);
uiSendPort?.send(null);
}
@override
Widget build(BuildContext context) {
final textStyle = Theme.of(context).textTheme.headline4;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Alarm fired $_counter times',
style: textStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Total alarms fired: ',
style: textStyle,
),
Text(
prefs.getInt(countKey).toString(),
key: const ValueKey('BackgroundCountText'),
style: textStyle,
),
],
),
ElevatedButton(
key: const ValueKey('RegisterOneShotAlarm'),
onPressed: () async {
await AndroidAlarmManager.oneShot(
const Duration(seconds: 5),
// Ensure we have a unique alarm ID.
Random().nextInt(pow(2, 31)),
callback,
exact: true,
wakeup: true,
);
},
child: const Text(
'Schedule OneShot Alarm',
),
),
],
),
),
);
}
}
Reference
Find the reference links below:
Number | Link |
---|---|
1. | Download Example |
2. | Read more |
Example 2: Using android_alarm_manager
package
This is an example using the now deprecated android_alarm_manager
plugin.
android_alarm_manager
is a Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire.
Step 1: Install android_alarm_manager
Go to your pubspec.yaml
and add the android_alarm_manager
as a dependency, as follows:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.3
android_alarm_manager: ^0.4.5+14
Step 2: Add Permissions
Go to your /Android/app/src/main/AndroidManifest.xml
and add the following two permissions:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
Then within the same file, but inside the <application>..</application>
tag, add the following:
<service
android:name="io.flutter.plugins.androidalarmmanager.AlarmService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<receiver
android:name="io.flutter.plugins.androidalarmmanager.AlarmBroadcastReceiver"
android:exported="false"/>
<receiver
android:name="io.flutter.plugins.androidalarmmanager.RebootBroadcastReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
Step 4: Write Code
Go to your main.dart
file and add the following imports:
import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:flutter/material.dart';
Create an async
main method as follows:
main() async {
WidgetsFlutterBinding.ensureInitialized();
await AndroidAlarmManager.initialize();
runApp(MyApp());
}
Extend the StatefulWidget
:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
Here is the function that will be run periodically:
showprint() {
print('alarm done');
}
Hereis the State
class:
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: OutlineButton(
child: Text('Alarm now'),
onPressed: () {
AndroidAlarmManager.oneShot(Duration(seconds: 3), 0, showprint);
},
),
),
),
);
}
}
Here is the full code:
main.dart
import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:flutter/material.dart';
main() async {
WidgetsFlutterBinding.ensureInitialized();
await AndroidAlarmManager.initialize();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
showprint() {
print('alarm done');
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: OutlineButton(
child: Text('Alarm now'),
onPressed: () {
AndroidAlarmManager.oneShot(Duration(seconds: 3), 0, showprint);
},
),
),
),
);
}
}
Reference
Download the code here