If you want to access resources or features considered sensitive in devices, then you have to ask for permission from the user. As such a plugin to provide easy to use , cross platform(iOS and Android) API for requesting and handling of permissions is of paramount importance.

Such a plugin is the Permission Handler library. This tutorial explores step by step how to use it.

Step 1: Install

The first step is to install this plugin. You do that by adding the permission_handler as a dependency in your pubspecy.yaml:

  permission_handler: ^8.1.4+2

Sync from your IDE or run flutter pub get from the terminal/

How To Easily Use Flutter Wrap Widget – Flutter Example Code

How To Easily Use Flutter Wrap Widg...
How To Easily Use Flutter Wrap Widget – Flutter Example Code

Step 2: Setup

Both operating systems: Android and iOS require their own unique setup methods when it comes to permissions.


The later versions of this plugin requires AndroidX. To switch to AndroidX add the following to your gradle.properties file:


Then make sure the compileSdkVersion in your android/app/build.gradle is set to atleast 30:

android {
  compileSdkVersion 30

If there are android dependencies with the dependencies closure, make sure they are replaced to their AndroidX counterparts. More info can be found here).

Add the permissions you need inside the main folders AndroidManifest.xml. Here is a list of possible permissions.


For iOS, add permission to your Info.plist file. Here's an example Info.plist.

The permission_handler plugin use macros to control whether a permission is enabled.

You must list permission you want to use in your application :

Add the following to your Podfile file:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      ... # Here are some configurations automatically generated by flutter

      # You can enable the permissions needed here. For example to enable camera
      # permission, just remove the `#` character in front so it looks like this:
      # ## dart: PermissionGroup.camera
      #  Preprocessor definitions can be found in: https://github.com/Baseflow/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [

        ## dart: PermissionGroup.calendar
        # 'PERMISSION_EVENTS=1',

        ## dart: PermissionGroup.reminders

        ## dart: PermissionGroup.contacts

        ## dart: PermissionGroup.camera
        # 'PERMISSION_CAMERA=1',

        ## dart: PermissionGroup.microphone

        ## dart: PermissionGroup.speech

        ## dart: PermissionGroup.photos
        # 'PERMISSION_PHOTOS=1',

        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]

        ## dart: PermissionGroup.notification

        ## dart: PermissionGroup.mediaLibrary

        ## dart: PermissionGroup.sensors

        ## dart: PermissionGroup.bluetooth

        ## dart: PermissionGroup.appTrackingTransparency

        ## dart: PermissionGroup.criticalAlerts


Remove the # character in front of the permission you do want to use. For example if you need access to the calendar make sure the code looks like this:

        ## dart: PermissionGroup.calendar

Delete the corresponding permission description in Info.plist e.g. when you don't need camera permission, just delete 'NSCameraUsageDescription'

Step 3: Write Code

You start by importing it as follows:

import 'package:permission_handler/permission_handler.dart';

Now get the permission status, it can be granted, denied, restricted or permanently denied:

var status = await Permission.camera.status;
if (status.isDenied) {
  // We didn't ask for permission yet or the permission has been denied before but not permanently.

// You can can also directly ask the permission about its status.
if (await Permission.location.isRestricted) {
  // The OS restricts access, for example because of parental controls.

Next request the permission by invoking the request() function:

if (await Permission.contacts.request().isGranted) {
  // Either the permission was already granted before or the user just granted it.

// You can request multiple permissions at once.
Map<Permission, PermissionStatus> statuses = await [

If the permission has an associated service, e.g the location or acceleration sensor permissions, then you need to check if those services are enabled or disabled;

if (await Permission.locationWhenInUse.serviceStatus.isEnabled) {
  // Use location.

Here's how you can open the app's settings:

if (await Permission.speech.isPermanentlyDenied) {
  // The user opted to never again see the permission request dialog for this
  // app. The only way to change the permission's status now is to let the
  // user manually enable it in the system settings.

For android, you can show a permission rationale:

bool isShown = await Permission.contacts.shouldShowRequestRationale;

Full Example

Below is a full permission handler example.


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

void main() {
      pluginName: 'Permission Handler',
      githubURL: 'https://github.com/Baseflow/flutter-permission-handler',
      pubDevURL: 'https://pub.dev/packages/permission_handler',
      pages: [PermissionHandlerWidget.createPage()]));

///Defines the main theme color
final MaterialColor themeMaterialColor =
        const Color.fromRGBO(48, 49, 60, 1));

/// A Flutter application demonstrating the functionality of this plugin
class PermissionHandlerWidget extends StatefulWidget {
  static ExamplePage createPage() {
    return ExamplePage(
        Icons.location_on, (context) => PermissionHandlerWidget());

  _PermissionHandlerWidgetState createState() =>

class _PermissionHandlerWidgetState extends State<PermissionHandlerWidget> {
  Widget build(BuildContext context) {
    return Center(
      child: ListView(
          children: Permission.values
              .where((permission) {
                if (Platform.isIOS) {
                  return permission != Permission.unknown &&
                      permission != Permission.sms &&
                      permission != Permission.storage &&
                      permission != Permission.ignoreBatteryOptimizations &&
                      permission != Permission.accessMediaLocation &&
                      permission != Permission.activityRecognition &&
                      permission != Permission.manageExternalStorage &&
                      permission != Permission.systemAlertWindow &&
                      permission != Permission.requestInstallPackages &&
                      permission != Permission.accessNotificationPolicy;
                } else {
                  return permission != Permission.unknown &&
                      permission != Permission.mediaLibrary &&
                      permission != Permission.photos &&
                      permission != Permission.photosAddOnly &&
                      permission != Permission.reminders &&
                      permission != Permission.appTrackingTransparency &&
                      permission != Permission.criticalAlerts;
              .map((permission) => PermissionWidget(permission))

class PermissionWidget extends StatefulWidget {
  /// Constructs a [PermissionWidget] for the supplied [Permission].
  const PermissionWidget(this._permission);

  final Permission _permission;

  _PermissionState createState() => _PermissionState(_permission);

class _PermissionState extends State<PermissionWidget> {

  final Permission _permission;
  PermissionStatus _permissionStatus = PermissionStatus.denied;

  void initState() {


  void _listenForPermissionStatus() async {
    final status = await _permission.status;
    setState(() => _permissionStatus = status);

  Color getPermissionColor() {
    switch (_permissionStatus) {
      case PermissionStatus.denied:
        return Colors.red;
      case PermissionStatus.granted:
        return Colors.green;
      case PermissionStatus.limited:
        return Colors.orange;
        return Colors.grey;

  Widget build(BuildContext context) {
    return ListTile(
      title: Text(
        style: Theme.of(context).textTheme.bodyText1,
      subtitle: Text(
        style: TextStyle(color: getPermissionColor()),
      trailing: (_permission is PermissionWithService)
          ? IconButton(
              icon: const Icon(
                color: Colors.white,
              onPressed: () {
                    context, _permission as PermissionWithService);
          : null,
      onTap: () {

  void checkServiceStatus(
      BuildContext context, PermissionWithService permission) async {
      content: Text((await permission.serviceStatus).toString()),

  Future<void> requestPermission(Permission permission) async {
    final status = await permission.request();

    setState(() {
      _permissionStatus = status;

Download the full example below.


here are the code reference links:

Number Link
1. Download example
2. Read more
3. Follow library author