How to Handle Permissions in Flutter

To use features like location, camera, or Bluetooth in your Flutter application, you need the user’s permission. Fortunately, handling permissions in Flutter is very easy. In this post, we will handle permissions for both Android and iOS.

Install the Permission Handler Package

To handle permissions in Flutter, we first need to install the Permission Handler package into our project. We can install the package by executing the following command inside our project:

flutter pub add permission_handler

Once the command is executed, make sure to check your pubspec.yaml file for the added dependencies. You should see the Permission Handler package included in the dependencies section, like this:

dependencies:
  permission_handler: ^11.3.1

Android Configurations

To access any permission in Android we need to add an entry inside the app/src/main/AndroidManifest.xml for each permission our application needs. For example, to access the location, we need to add the following uses-permission entry.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <application

Ensure that you add the entry between the <manifest> and <application> tag. If you need multiple permissions you have to create separate uses-permission entries, like so:

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

You can find all the Android permissions here.

iOS Configurations

For accessing permissions in iOS we need to add entries inside the ios/Runner/info.plist file. For example, if we want to access the location we need to add the following entry:

<dict>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>This application needs access to the location</string>
    ...
</dict>

Make sure the entries are placed within the <dict> tag. The text inside the <key> tag specifies the permission, while the text inside the <string> tag provides the description. You can modify the description as needed, since it will be shown to the user when requesting access.

For multiple entries, you need to add multiple keys with descriptions for each permission, as done below:

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This application needs access to the location</string>
<key>NSCameraUsageDescription</key>
<string>This application needs access to camera</string>

You can find all the iOS permissions here.

Handling Location Permission in Flutter

To demonstrate how you can request permissions from the user, let us ask the user if we can access his location. See the code below:

import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  void _requestLocationPermission(BuildContext context) async {
    await Permission.location.request().then((PermissionStatus status) {
      switch (status) {
        case PermissionStatus.granted:
          _showSnackBar(context, 'Permission granted', Colors.green);
        case PermissionStatus.denied:
          _showSnackBar(context, 'Permission denied', Colors.amber);
        case PermissionStatus.permanentlyDenied:
          _showSnackBar(context, 'Permanently denied', Colors.redAccent);
        default:
          _showSnackBar(context, 'Something went wrong', Colors.red);
      }
    });
  }

  void _showSnackBar(BuildContext context, String text, Color color) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      content: Text(text, textAlign: TextAlign.center),
      backgroundColor: color,
    ));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          style: ElevatedButton.styleFrom(minimumSize: const Size(200, 50)),
          onPressed: () => _requestLocationPermission(context),
          child: const Text(
            'Request Location Permission',
            style: TextStyle(fontSize: 20),
          ),
        ),
      ),
    );
  }
}

In this code snippet, we create a HomePage widget that shows a button that will call the _requestLocationPermission function when pressed. The _requestLocationPermission function will start by calling the request() function on the location permission.

We await this function call, and once it is finished, it will return a PermissionStatus. Based on the permission status, the application shows a SnackBar message at the bottom of the screen using the _showSnackBar function. For example, if the location permission is granted, a green SnackBar message will be shown.

Opening the Application Settings From the Application

To improve our application’s functionality, we can use the package’s openAppSettings function, which allows users to access the application’s permissions settings directly.

This way, if the user denies permission or accidentally misclicks, they will be redirected to the application’s settings. This allows them to change the permissions.

void _requestLocationPermission(BuildContext context) async {
  await Permission.location.request().then((PermissionStatus status) {
    switch (status) {
      case PermissionStatus.granted:
        _showSnackBar(context, 'Permission granted', Colors.green);
      case PermissionStatus.denied:
        openAppSettings();
      case PermissionStatus.permanentlyDenied:
        openAppSettings();
      default:
        _showSnackBar(context, 'Something went wrong', Colors.red);
    }
  });
}

In the updated _requestLocationPermission function, we have modified the denied cases to call the openAppSettings function. Now, when the user denies permission, the application will automatically open the application’s settings, giving the user the option to adjust their permission preferences.

Handling Multiple Permissions at Once

So far we have discussed how to handle a single permission. However, the package can also be used to handle multiple permissions at once.

import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  void _requestPermissions(BuildContext context) async {
    await [Permission.location, Permission.camera].request().then((Map<Permission, PermissionStatus> statuses) {
      if (statuses.values.contains(PermissionStatus.denied)) {
        openAppSettings();
        return;
      }

      if (statuses.values.contains(PermissionStatus.permanentlyDenied)) {
        openAppSettings();
        return;
      }
      
      if (statuses.values.contains(PermissionStatus.granted)) {
        _showSnackBar(context, 'Permissions granted', Colors.green);
        return;
      }
      
      _showSnackBar(context, 'Something went wrong', Colors.red);
    });
  }

  void _showSnackBar(BuildContext context, String text, Color color) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      content: Text(text, textAlign: TextAlign.center),
      backgroundColor: color,
    ));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          style: ElevatedButton.styleFrom(minimumSize: const Size(200, 50)),
          onPressed: () => _requestPermissions(context),
          child: const Text(
            'Request Permissions',
            style: TextStyle(fontSize: 20),
          ),
        ),
      ),
    );
  }
}

In the above code, we changed the name of the _requestLocationPermission function to _requestPermissions because it will now be requesting multiple permissions.

To request multiple permissions we can call the request function on a list of permissions. In this case, we use the location and camera permission. Inside our then clause we will now receive a map with the permissions and their statuses.

To simplify the function we will check if the statuses contains either denied, permanentlyDenied or granted. Based on the outcome we either show a Snackbar message or open the application’s settings.

Conclusion

In this post, you have learned how to handle permissions in Flutter using the Permission Handler package. We started by installing the package and configuring permissions for both Android and iOS. Afterward, we handled a single permission, opened the application’s settings and handled multiple permissions at once.

Tijn van den Eijnde
Tijn van den Eijnde
Articles: 40

Leave a Reply

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