Flutter in-app lock screens

Tom Alabaster
3 min readDec 21, 2019

Flutter is getting more popular by the day, especially with the recent 1.12 announcement at Flutter Interact in Brooklyn, New York.

We’ve learnt that Flutter has grown to the #2 fastest growing open source project and is being used in loads of different sectors. Some of these sectors have sensitive information at the core of an app, and user’s data needs protecting at an app level - not just at a remote service level.

A person using their phone, hopefully looking at an in-app lock screen.
A person using their phone, hopefully looking at an in-app lock screen.

A lot of fin-tech apps such as Monzo and ClearScore using in-app lock screens for protecting the app from unauthorized users. These work by requiring the user to enter a password, passcode or use biometrics before being allowed on to the app from a cold launch, as well as when going away from the app and coming back.

In this post, we’ll look at showing lock screens when a user goes away from the app and comes back.

Flutter provides us with the lifecycle events we need to implement this without the need to manually hook in to lifecycle events using method channels. On a given State, simply use the WidgetsBindingObserver as a mixin.

class _MyWidgetState extends State<MyWidget> with WidgetsBindingObserver {  @override
Widget build(BuildContext context) {
...
}
}

Once you’ve added WidgetsBindingObserver as a mixin, you can now add this class as an observer on the WidgetsBinding instance which provides the app lifecycle events. You do this in initState and remove this class as an observer in the dispose method:

@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.initState();
}

Once you’ve done this, you can now listen to app lifecycle change events using the didChangeAppLifecycleState method the WidgetsBindingObserver gives you.

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
}

AppLifecycleState is an enum and can be either resumed, inactive, paused or detached. The main one we need to worry about though is paused. We need to keep track of whether the app has been paused or not so make a bool property on your State to keep track of this, otherwise multiple lock screens could be shown.

bool _isPaused = false;@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused && !_isPaused) {
_isPaused = true;
_showLockScreen(); // this should use the `Navigator` to push a new route
}
super.didChangeAppLifecycleState(state);
}

The _showLockScreen() method I mentioned in the code snippet above should use the Navigator to push a route fir for your own implementation of a lock screen, which is a Widget wrapped in a WillPopScope widget to prevent the user from dismissing the lock screen using the Android back button or the iOS swipe gesture. Below is a simple example using a MaterialPageRoute:

void _showLockScreen() async {
await Navigator.of(context).push(MaterialPageRoute(builder: (context) =>
WillPopScope(
child: ...,
onWillPop: () => Future.value(false), // prevents the system from dismissing this route
)));

_isPaused = false;
}

The widget for the lock screen can still dismiss itself using Navigator.of(context).pop(); once a successful login has occurred.

And that’s it! This should be enough to help you show a lock screen when the app is no longer visible to the user.

“But Tom, didn’t you mentioned showing an in-app lock screen on launch?”

There are many different ways of deciding whether or not to show the lock screen on app launch which is why I didn’t choose to discuss them here, but I’ve written a Flutter package which provides a short and neat way of doing this, as well as handling subsequent app pauses!

Check it out here: https://pub.dev/packages/flutter_app_lock

Thanks for reading!
https://www.linkedin.com/in/tom-a/
https://github.com/tomalabaster

--

--

Tom Alabaster

Mobile developer focusing on and pushing the use Flutter for modern app development.