How to implement Android runtime permission flow in Flutter

Many Android apps require what Android deems a dangerous permission. For example using the camera, adding an event to the user calendar, or reading the user contacts. Previously, Android used to ask for those permissions at install time, but since Marshmallow, it does it at runtime. So, how do you implement the Android runtime permission flow in Flutter?

A search of Flutter plugins currently shows no results, so I had to figure it out myself for my app Preset SMSs.

In this code tutorial, we will create an app that shows a list of all contacts with a mobile phone number. The app displays a loading screen while it obtains the contacts and an error Snackbar when the app has no permission. The Android code itself is based on the official Requesting Permissions at Run Time guide. For communicating between Flutter and Android, we will use Method Channels.

Setting up the app

The app has one screen, which has a list, as well as a CircularProgressIndicator. It handles errors with snackbars. We will use a basic MVP structure for this screen.

To follow the code tutorial, create a new app as follows.

If you’re unsure how to set up a Flutter app, check out Getting started with Flutter official tutorial.

Firstly, we create a Material app in main.dart, which will launch the HomePage widget.

 

Secondly, we create home_page.dart. This displays a list or an in progress indicator, depending on its state.

 

Thirdly, we define a simple Contact, with a display name and a mobile phone number, in contact.dart.

Setting up the MVP structure

I like to use “contracts” when using MVP. Contracts are interfaces (in Java)  or abstract classes (in Dart) that define the methods for each component of the feature, ie View, Model, and Presenter.

Note: You do not need to set up contracts for applying MVP, but I find it very helpful to have them. I define them all in one file, and this makes it easy to understand what a feature does.  When I worked as an Android DPE at Google, I worked on the first release of the Android Architecture Blueprints project and we decided to use contracts. I have used contracts on all my professional projects since, and I haven’t looked back: this really helps make a complex app maintainable!

So let’s set up our contract for this feature, by creating home_contract.dart.

 

The only user action per se is the user starting the app to show the screen, ie view displayed. This is async, because it will update the view based on async data responses from the Model.

 

Getting the contacts is 2 separate data actions: check if we can get contacts, and get contacts. The former takes care of requesting permission if the app hasn’t got it.

 

Finally, the view has 4 possible states: loading in progress, contacts list, display error message when permission is denied, and display permission rationale.

 

Now, we create Model and Presenter classes that implement the abstract classes. The View abstract class is implemented in HomePage.

Firstly, let’s start with home_presenter.dart. The Presenter has a reference to the View and the Model, as it acts as a “coordinator” between View and Model.

Note: in case of permission denied, we add a 1 second wait. This is because the Android SDK somehow still holds the UI (due to the permission dialog). If we don’t add this delay, the error snackbar isn’t shown. You may want to play with the duration value, but I found that 1 second worked on all the devices I tested it on.

Secondly, let’s set up home_model.dart.

 

And, lastly, HomePage itself will implement the View, and will create the Presenter when initialised.

Checking and requesting permission

Firstly, we add the permission to the Android app manifest.

 

Secondly, to check and request a permission, we need to use the Android SDK. Therefore, we use a MethodChannel to communicate between Flutter and the Android SDK.

On the Flutter side, it is pretty simple. We set up the channel in home_model.dart, as per below.

Note: for the permission status, the channel returns an int, which corresponds to the index of the PermissionState value.

On the Android side, we need to set it up in MainActivity.java as below. When requesting a permission, the process is async, relying on a system callback in the Activity. So we define our own Callback, to be able to send the result back to the Channel. The permission code itself is copied from the official Android documentation – check it out if you need more explanations.

Note: the Android SDK has no method to indicate that the rationale has been shown. When the user has just seen the rationale, the app is expected to request the permission directly, without checking if we should show the rationale (as this will return true and we will be stuck in a loop). To handle this, we are using a boolean rationaleJustShown. We handle this in the Android code and not the Flutter code because it is an Android SDK detail, and the implementation on iOS may well be different.

Lastly, don’t forget to add the support library to build.gradle.

Getting contacts with a mobile phone number

The process to get the contacts is similar. We need to use the Android SDK to query the contacts, so we set up a Method Channel.

In Flutter, we do this in home_model.dart.

 

In Android, we set it up in MainActivity.java. To avoid blocking the UI thread, we use an AsyncTask to get the contacts; to send the results back to the channel,  we use a callback setup similar to permission. If you didn’t use an AsyncTask to query the contacts, the circular progress bar would freeze.

What next?

This code tutorial includes an introduction to MVP. App architecture is probably the most important factor determining app longevity. With good architecture, it is easy to add or change features, and therefore, the app is a pleasure to maintain. So it’s well worth keeping an eye on Flutter Architecture Samples,  a project inspired, in part, by Android Architecture Blueprints.

Android app developer with 8 years experience, ranging from start ups to large tech (Google) and non tech (British Airways) companies. Currently freelancing and learning Flutter. LinkedIn natalie ( at ) cogitas (dot) net

Author: Natalie Masse Hooper

Android app developer with 8 years experience, ranging from start ups to large tech (Google) and non tech (British Airways) companies. Currently freelancing and learning Flutter. LinkedIn natalie ( at ) cogitas (dot) net

2 thoughts on “How to implement Android runtime permission flow in Flutter”

    1. I plan to do it, but it will take me a few weeks: I need to sort out access to a Mac & iPhone, which I currently don’t have (I’m an Android/Linux user).

Leave a Reply

Your email address will not be published. Required fields are marked *