How to create a scheduled service in Flutter - service

How can you create a scheduled service in Flutter, which will be triggered at a specific time every day, and it will run some code? It needs to work for both Android and IOS and even if the app is terminated.

You could make use of the alarm manager package.
A simple implementation of the same would look like below.
import 'dart:async';
import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:flutter/widgets.dart';
void doStuff() {
print("do stuff every minute");
}
Future<void> main() async {
final int periodicID = 0;
// Start the AlarmManager service.
await AndroidAlarmManager.initialize();
runApp(const Center(
child:
Text('See device log for output', textDirection: TextDirection.ltr)));
await AndroidAlarmManager.periodic(
const Duration(minutes: 1), periodicID, doStuff,
wakeup: true);
}

Related

How to update the values of varaible when background service changes its value?

We are working in a flutter group project. In which we are doing some tasks with background service. Basically we are fetching the usage time of all the third party applications for every 1 minute. Basically, we use app_usage package for getting the usage time of all the apps. This package returns the list of apps with usage_time, appName, packageName, etc.. whenever we are calling app_usage package with starting time and ending time it will return the list of apps with usage time for the given duration.
i.e.,
List<AppUsageInfo> apps = await AppUsage.getAppUsage(starting, ending);
This line will return the list of apps at the particular instance. But for background task we call the same line in the Timer.periodic function with the duration of 1 minute. So, we thought this will return the usage time of apps for every 1 minute. But when we printing the apps usage time...its not updating but if there some refresh is done to the app the updated values are displaying. for eg. If the refreshing action is made after the 5th minute the value exactly changes to 5th minute by skipping the previous values. So, is there any way to update the values at real time in background.
This is sample code.
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
// ignore: depend_on_referenced_packages
import 'package:flutter_background_service_android/flutter_background_service_android.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:device_apps/device_apps.dart';
import 'package:app_usage/app_usage.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await initializeService();
runApp(const MyApp());
}
var item = AppModel(name: 'untitled', usage: 2000);
Future<void> initializeService() async {
final service = FlutterBackgroundService();
await service.configure(
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: true,
isForegroundMode: true,
),
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will be executed when app is in foreground in separated isolate
onForeground: onStart,
// you have to enable background fetch capability on xcode project
onBackground: onIosBackground,
),
);
service.startService();
}
// to ensure this is executed
// run app from xcode, then from xcode menu, select Simulate Background Fetch
bool onIosBackground(ServiceInstance service) {
WidgetsFlutterBinding.ensureInitialized();
print('FLUTTER BACKGROUND FETCH');
return true;
}
void getUsageStats() async {
try {
DateTime ending = DateTime.now();
int daySubtracter = ending.hour;
int minSubtracter = ending.minute;
int secSubtracter = ending.second;
DateTime starting = ending.subtract(
Duration(
hours: daySubtracter,
minutes: minSubtracter,
seconds: secSubtracter,
),
);
print(starting);
print(ending);
List<AppUsageInfo> apps = await AppUsage.getAppUsage(starting, ending);
for (var app in apps) {
if (app.appName == item.name) {
if ((item.usage - app.usage.inSeconds) < 10) {
print("Time is equal");
} else {
print("Remaining seconds: ${item.usage - app.usage.inSeconds}");
}
}
}
} on AppUsageException catch (exception) {
print(exception);
}
}
void onStart(ServiceInstance service) async {
// Only available for flutter 3.0.0 and later
DartPluginRegistrant.ensureInitialized();
// For flutter prior to version 3.0.0
// We have to register the plugin manually
if (service is AndroidServiceInstance) {
service.on('setAsBackground').listen((event) {
service.setAsBackgroundService();
});
}
// bring to background
Timer.periodic(
const Duration(seconds: 20),
(timer) async {
if (service is AndroidServiceInstance) {
service.setForegroundNotificationInfo(
title: "REMIT application is running",
content: "Timer running",
);
}
//external plugin for background
if (Platform.isAndroid) {
getUsageStats();
}
},
);
}
class AppModel {
late String name;
late int usage;
AppModel({required this.name, required this.usage});
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String text = "Stop Service";
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Service App'),
),
body: Center(
child: Column(
children: [
ElevatedButton(
child: const Text("Background Mode"),
onPressed: () {
FlutterBackgroundService().invoke("setAsBackground");
},
),
],
),
),
),
);
}
}
We are calling the getUsageStats method for every 20 seconds for updated usage time. To cross check the code we are printing it on the terminal but the usage time not updating untill any refresh happens to the code.

Flutter Workmanager Task not updating with app update

So I have an issue where my existing Flutter Workmanager background task is not updating automatically following the app's update.
I have the example code which sets up a periodic Workmanager job.
void main() async
{
WidgetsFlutterBinding.ensureInitialized();
Workmanager().initialize(
callbackDispatcher
);
await Workmanager().registerPeriodicTask(
"ExampleTask",
"ExampleTaskPeriodicTask",
initialDelay: Duration(minutes: 15,
frequency: Duration(hours: 1)
);
}
void callbackDispatcher() async
{
Workmanager().executeTask((task, inputData) async
{
await DoSomething();
return Future.value(true);
});
}
If I update DoSomething() in my background task, currently it does not update for the user and it would continue doing the old thing, not the new thing.
Is there any way to update the background task without the user having to do anything following the apps automatic update?
Through testing and debugging using adb to update the app (flutter run is not suitable), the resolution was to add existingWorkPolicy: ExistingWorkPolicy.append to the periodic task registry.

How to run some dart code in the background, every 15 seconds

I've created app that checks the call log list every 15 seconds. I have used Timer.periodic() to achieve this. And everything works fine but only if app is not running in the background. After couple of minutes when app is in the background, the task which is scheduled by Timer.periodic is not executing anymore. I have tried to use android_alarm_manager https://pub.dev/packages/android_alarm_manager but it doesn't work at all. It's logging /FlutterBackgroundExecutor(11431): Starting AlarmService... but then nothing happends.
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:android_alarm_manager/android_alarm_manager.dart';
void main() async{
await WidgetsFlutterBinding.ensureInitialized();
await AndroidAlarmManager.initialize();
runApp(MyApp());
final int helloAlarmID = 0;
await AndroidAlarmManager.periodic(Duration(seconds: 5), helloAlarmID, printHello);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
void printHello() {
final DateTime now = DateTime.now();
final int isolateId = Isolate.current.hashCode;
print("[$now] Hello, world! isolate=${isolateId} function='$printHello'");
}
Do I have any other possibilities to reach my goal ?
Android limits background usage to every 15 minutes or so. There are several packages on pub.dev that can run code in background even when the application is closed. However i don't think any of them can run your code every 15 seconds.
Packages include:
background_fetch
workmanager
flutter_background_service
There are several more.

How do I initialize Firebase App in Flutter widget testing

So I am new in flutter and trying to perform widget testing on my app, but I am keep getting this weird error.
below is my test file
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:folk_team_app/provider/auth_provider.dart';
import 'package:folk_team_app/screens/phone_login.dart';
import 'package:provider/provider.dart';
void main() async {
TestWidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
Widget loginScreen = ChangeNotifierProvider<AuthProvider>(
create: (context) => AuthProvider(),
builder: (context, child) {
return MaterialApp(
home: PhoneLogineScreen(),
);
});
testWidgets('Phone Authetication Page', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(loginScreen);
await tester.pump(const Duration(seconds: 10));
final titleText = find.text('Screen Title');
// Verify that our counter starts at 0.
expect(titleTextt, findsOneWidget);
});
}
here is the error :
You can't directly test Firebase because it requires platform configurations in order to initialize it properly.
You need to mock Firebase in the test environment using mockito.
You may find this comment and tutorial video helpful.

How to automatically awake the application in flutter?

I am coding an alarm on my own and I would like that the alarm would wake up the phone and show the Alert Dialog. Can someone give me some insight on how to do this please?
You can use android_alarm_maganer to achive what you need. Simply run it every second or so and check if DateTime.now() meets your criteria.
Example:
import 'package:android_alarm_manager/android_alarm_manager.dart';
void checkAlarms() {
if(DateTime().now == alarm){
//Do something
}
}
main() async {
final int helloAlarmID = 0;
await AndroidAlarmManager.initialize();
runApp(...);
await AndroidAlarmManager.periodic(const Duration(seconds: 1), helloAlarmID, checkAlarms);
}
Then you can run another Activity as described here