android_alarm_manager 2.0.0-nullsafety android_alarm_manager: ^2.0.0-nullsafety copied to clipboard
Flutter plugin for accessing the Android AlarmManager service, and running Dart code in the background when alarms fire.
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
import 'dart:isolate';
import 'dart:math';
import 'dart:ui';
import 'package:android_alarm_manager/android_alarm_manager.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.
late SharedPreferences prefs;
Future<void> main() async {
// 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(AlarmManagerExampleApp());
}
/// Example app for Espresso plugin.
class AlarmManagerExampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: _AlarmHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class _AlarmHomePage extends StatefulWidget {
_AlarmHomePage({Key? key, required 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();
int currentCount = prefs.getInt(countKey) ?? 0;
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: ValueKey('BackgroundCountText'),
style: textStyle,
),
],
),
ElevatedButton(
child: Text(
'Schedule OneShot Alarm',
),
key: ValueKey('RegisterOneShotAlarm'),
onPressed: () async {
await AndroidAlarmManager.oneShot(
const Duration(seconds: 5),
// Ensure we have a unique alarm ID.
Random().nextInt(pow(2, 31).toInt()),
callback,
exact: true,
wakeup: true,
);
},
),
],
),
),
);
}
}