Requesting permissions usually become a messy task when there's a lot of paths you want to take your user on based on the permissions. To start the clean up process of all the permissions code we'll wrap it in a service with dedicated permission request functions on it.

In this tutorial we'll be using the permissions_handler package to request our permissions so lets add that to the pubspec.

permission_handler : ^3.1.0

We'll create functions to request two types of permission, we'll do Location as well as Contacts. First we need to tell the OS that our app will be using these permissions.

In the AndroidManifest add the uses-permission tags for the two features.

< uses-permission android: name = " android.permission.READ_CONTACTS " /> < uses-permission android: name = " android.permission.WRITE_CONTACTS " /> < uses-permission android: name = " android.permission.ACCESS_FINE_LOCATION " />

In the info.plist file add the keys along with your message

< key > NSContactsUsageDescription </ key > < string > This app requires contacts access to function. </ string > < key > NSLocationWhenInUseUsageDescription </ key > < string > This app requires access to your location when in use to show relevan information. </ string > < key > NSLocationAlwaysUsageDescription </ key > < string > This app requires always on access to to your location to notifiy you when are near a store. </ string >

The PermissionsService will have a dedicated function on it for the permissions that you require. This way it can be called when the user wants to use the functionality that requires it. It will also be easy to write custom logic per function(group) through providing callbacks. Create a new file called permissions_service.dart and in it we'll make a class that has an instance of the PermissionHandler from the package.

import 'package:permission_handler/permission_handler.dart' ; class PermissionsService { final PermissionHandler _permissionHandler = PermissionHandler ( ) ; }

Then we can add a generic function that takes in a PermissionGroup to request a permission of what we want.

. . . Future < bool > _requestPermission ( PermissionGroup permission ) async { var result = await _permissionHandler . requestPermissions ( [ permission ] ) ; if ( result [ permission ] == PermissionStatus . granted ) { return true ; } return false ; } . . .

And using this function we can create specific functions for each permission.

. . . Future < bool > requestContactsPermission ( ) async { return _requestPermission ( PermissionGroup . contacts ) ; } Future < bool > requestLocationPermission ( ) async { return _requestPermission ( PermissionGroup . locationWhenInUse ) ; } . . .

Many of the times when it comes to permissions we want to do something custom or want to prompt the user again to allow us the permissions. Because we have dedicated functions we can now handle each permission request in a custom way. Lets say the app needs to have access to the contacts to work, something like whatsapp. We can supply a function that will be called when the permission is denied so that we can show a dialog on the outside. Checkout this tutorial for quick dialogs

We'll pass in a onPermissionDenied function that will get called when the user declines a permission.

Future < bool > requestContactsPermission ( { Function onPermissionDenied } ) async { var granted = await _requestPermission ( PermissionGroup . contacts ) ; if ( ! granted ) { onPermissionDenied ( ) ; } return granted ; }

Now on the outside you can pass in your function, show your dialog when it's denied and then request it again if the user chooses to do so :)

Another thing is to check if the app has a permission already. We'll create the same setup, a generic function that takes in a PermissionGroup and then use dedicated functions for specific permissions. You don't have to do this I just find it easier to maintain and it makes the outside code less dependent on the PermissionHandler package.

. . . Future < bool > hasContactsPermission ( ) async { return hasPermission ( PermissionGroup . contacts ) ; } Future < bool > hasPermission ( PermissionGroup permission ) async { var permissionStatus = await _permissionHandler . checkPermissionStatus ( permission ) ; return permissionStatus == PermissionStatus . granted ; } . . .

In the code we can now use the service to request permissions like this.

class MyApp extends StatelessWidget { @override Widget build ( BuildContext context ) { return MaterialApp ( title : 'Flutter Demo' , home : Scaffold ( body : Center ( child : MaterialButton ( color : Colors . yellow [ 300 ] , child : Text ( 'Request contacts permission' ) , onPressed : ( ) { PermissionsService ( ) . requestContactsPermission ( onPermissionDenied : ( ) { print ( 'Permission has been denied' ) ; } ) ; } , ) , ) , ) ) ; } }

Services should be injected or located as shown here using provider only or in an architecture like this with Provider and get_it. Having your functionality wrapped in a service removes any relation between your code and third party implementation details so it's always a preferred solution for me.

Check out more of the snippets on the site. New snippets every weekday.