How to detect when app is minized in flutter - flutter

Is there a way to detect when the app has been minimized? Simply using WidgetsBindingObserver with the paused event doesn't work as it's indistinguishable from when the user turns off the screen / phone locks. Note, I need this to work for both android and ios.
A bit of context of what I'm doing. In the application, I'm running a timer. I want to stop this timer if the user minimizes the app (e.g. uses its phone for something else). If the user, however, turns off the screen/locks it, I want the timer to continue.

I suggest to take a look at this package: is_lock_screen
As the description suggest
Useful for determining whether app entered background due to locking screen or leaving app.
I would try with this:
#override
void didChangeAppLifecycleState(AppLifecycleState state) async {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.inactive) {
final isLock = await isLockScreen();
if(!isLock){
print('app inactive MINIMIZED!');
}
print('app inactive in lock screen!');
} else if (state == AppLifecycleState.resumed) {
print('app resumed');
}
}

Related

Is there a way to terminate user status in flutter when going to background

I am developing an app and one of the requests is, when the user goes from the app to the background, to another app or something like this, when they reopen it the app has to go to splash screen again so they do the pincode again.
I cant find an answer on how to do it. Is it possible?
use WidgetsBindingObserver it help to listen for app life cycle,
class FooClass extends State<FooClass> with WidgetsBindingObserver {
// ... some code
}
on initState listen for app state change
WidgetsBinding.instance.addObserver(this);
override didChangeAppLifecycleState when app lifecycle changes this method will called with current lifecycle state
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
case AppLifecycleState.resumed:
}
}
and finally in dispose if you wan to remove listener
WidgetsBinding.instance.removeObserver(this);
for more details
https://api.flutter.dev/flutter/widgets/WidgetsBindingObserver-class.html

Flutter Background Service

Hi I'm building a VoIP App in Flutter. I use background_fetch to run a headless task in order to work even if the app is closed. The listener is working, and a notification is sent. But, as the application is closed, the push notification with wake up the app (so home.dart for example) and I would like the push my call screen widget. I see two solution but I don't know how to do it :
the headless task from background_fetch is independent, so I can't transfer my service call data to my app (main) when the user open it, so the call is lost ...
I try to push the right widget (Router.go(/callscreen)) but it's not working.
What can I do in order to fix this ? Thank !
You are using 2 services in background, flutter-local-notification and background-fetch. It's too much. You can use flutter-local-notification in backgound only. Have a look here.
final newRouteName = "callScreen";//Future onSelectNotification(String payload) async
bool isNewRouteSameAsCurrent = false;
Navigator.popUntil(context, (route) {
if (route.settings.name == newRouteName) {
isNewRouteSameAsCurrent = true;
}
return true;
});
if (!isNewRouteSameAsCurrent) {
Navigator.of(context).push(CallScreen())
}

Flutter : Strange behavior of Shared Preferences

I have a problem with inconsistent shared preferences value. I will try to describe it as simple as possible.
I'm using Firebase Cloud Messaging for push notifications. When app is in background and notification came in, background handler bellow is invoked.
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final int counter = (prefs.getInt('badge') ?? 0) + 1;
prefs.setInt('badge', counter).then((bool success) {
print(counter);
});
}
My widget uses WidgetsBindingObserver to determine lifecycle state. When I enter the app, state of that widget is onResume and there I want to read that badge value from shared preferences like this.
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final int counter = (prefs.getInt('badge') ?? 0);
print(counter);
}
}
Scenario 1:
App opened, notification came in - set badge field to 1.
App in background, notification came in - background handler set badge field to 2.
App resumed, read that badge field, it's still 1.
Scenario 2:
App opened, notification came in - set badge field to 1.
App in background, notification came in - background handler set badge field to 2.
App in background, notification came in - background handler set badge field to 3.
App resumed, read that badge field, it's still 1.
Question: Any idea why field isn't updated?
SharedPreferences can be used on background events handlers. The problem is that the background handler run in a different isolate so, when you try to get a data, the shared preferences instance is empty. To avoid this you simply have to force a refresh:
SharedPreferences prefs= await SharedPreferences.getInstance();
await prefs.reload();
final int counter = (prefs.getInt('badge') ?? 0);
In the same mode, if the shared preferences can be modified in a background hadler, be sure you call this "reload" function in the main isolate when you try to read from theirs.
SharedPreferences or any other local storage won't work in the _firebaseMessagingBackgroundHandler.
You should capture it on getInitialMessage or onMessageOpenedApp.
https://firebase.flutter.dev/docs/messaging/notifications/
TL;DR:
getInitialMessage gets triggered when the application is opened from a terminated state. While onMessageOpenedApp gets triggered when the application is opened from background state.
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage message) {
if (message != null) {
Navigator.of(context).pushNamed('/messages', arguments: message.data);
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
if (message != null) {
Navigator.of(context).pushNamed('/messages', arguments: message.data);
}
});

how to close all notifications when app is closed flutter?

Does anyone have idea? Whenever I close my app, the notification also will automatically close. I try to using "AppLifecycleState.detached" but still doesn't work. It's didn't call out the function of "notifications.cancelAll()". Does anyone got idea to fix this other than using AppLifecycleState? Below are my code:
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
print("State: "+state.toString());
if(state == AppLifecycleState.detached){
print("detached");
notifications.cancelAll();
}
}

Flutter : cancel Timer if AppLifecycleState == resumed

i want try implementation AppLifecycleState using flutter.
I have Model like this :
(string) id
(string) name
(bool) fingerprintStatus = false
(bool) tokenExpiry = false
I want detect If the user exit From the App , If the user exit more than X Second i want change status tokenExpiry == true . So for handle my case i detect user Activity Using AppLifecycleState and Timer
But the problem is i don't know logic to do that. In my mind If user exit/close app , running timer for X second then update tokenExpiry . If user comeback again but the Timer not finished, Cancel and Reset Timer then do nothing.
How can i do this ?
My Expected
AppLifecycleState _appLifecycleState;
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
print(state.toString());
if(_appLifecycleState == AppLifecycleState.inactive || _appLifecycleState ==
AppLifecycleState.paused){
=> Running The Timer For 10 Second
}
else{
=> Cancel The Timer and Do Nothing
}
super.didChangeAppLifecycleState(state);
}
I know this is coming late but the best approach will be to save a Timestamp into SharedPreferences and then when the app AppLifecycleState resumes you retrieve that Timestamp and compare it with the current time AppLifecycleState Resumes.