A Beginner's Guide to Using the Permission Handler Plugin in Flutter
This article provides a brief overview of how to use the permission handler plugin for Flutter. If you want to learn more, I recommend checking the official plugin or this article.
What are Permissions?
When writing mobile applications, you often want to use native APIs outside of your app to do some cool stuff. A few examples would be using the camera, sending notifications, accessing Bluetooth, and many more. Whenever you want to use those APIs, you need to ask the user for permission; otherwise, you could just write some code that spies on the user without them knowing about it. For example, if you want to access the user's files through your app, you need to ask the user for permission before you can do so. If the user grants that permission, you can access the files; otherwise, you can't. Depending on what permission you are asking the user for and on what platform you're on, you get a Permission
's status
, which is either granted
, denied
, restricted
, permanentlyDenied
, limited
, or provisional
.
Here is an overview of what these mean:
1. granted
• What it means: The permission has been granted, and the app can perform the action associated with it.
• On Android: This status is straightforward — the permission was allowed by the user.
• On iOS: Similar to Android, the permission is fully granted. However, some permissions (e.g., notifications) might still require further configuration by the user (e.g., enabling alerts in notification settings).
2. denied
• What it means: The user explicitly denied the permission, but the app can ask for it again.
• On Android: The user tapped “Deny” in the permission dialog.
• On iOS: The user denied the request, but the app is allowed to re-prompt.
3. restricted
• What it means: The permission cannot be granted because of system-level restrictions.
• On Android: Rarely encountered. Could occur if the device is managed by an enterprise policy.
• On iOS: Common for parental controls or MDM (Mobile Device Management) restrictions.
4. permanentlyDenied
• What it means: The user denied the permission and selected an option to prevent the app from asking again.
• On Android:
• Happens when the user selects “Don’t ask again” in the permission dialog.
• The app must redirect the user to the system settings to enable the permission.
• On iOS: This status is not applicable, as iOS doesn’t provide a “Don’t ask again” option. Instead, users manage permissions through system settings after a denial.
5. limited (iOS only)
• What it means: The user granted limited access to a resource (e.g., a subset of photos or specific features).
• On iOS:
• Relevant for photo library access (introduced in iOS 14). Users can select specific photos instead of granting full access.
• Limited access may require additional prompts if the app needs more functionality.
6. provisional (iOS only)
• What it means: The app has provisional access, meaning the permission is granted temporarily without explicit user approval.
• On iOS:
• Relevant for notifications (introduced in iOS 12). Notifications are delivered quietly (no sound or banner), and the user can later decide to fully enable or disable them.
The permission_handler plugin allows us to manage permissions through Dart code, without the need to write native code. However, we still have some native requirements that we need to set up first. Let's look at that.
Native Requirements
We won’t be coding anything in native code here; we just need to make some configuration changes for both Android and iOS. If you want to ask the user for permission for something, you need to specify that inside the AndroidManifest.xml
file for Android and in your info.plist
file and your Podfile
for iOS, so the operating system knows what you are trying to do when installing the app.
Android
In your project, navigate to /android/app/src/main/AndroidManifest.xml
. This is the configuration file you are going to change. Here, we just need to tell our app what permission we might ask the user for. To do so, you have to add this line of code for each permission you want to ask, directly inside the <manifest></manifest>
tag.
<uses-permission android:name="{PermissionName}"/>
Here is a full list for all the different android permission for this xml
file.
And thats it for android!
iOS
On iOS, the process is similar. Navigate to /ios/Runner/Info.plist and add the following code for each permission you want to ask for, inside the <dict></dict>
tag.
<key>{PermissionName}</key>
<string>Explanation for why you want that permission</string>
The user will see the text inside the string tag in the displayed popup on the screen when the app asks for permission.
Again, here is a full list of all possible permissions.
After that, navigate to /ios/Podfile
, locate this section, and add the permission you want to access.
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
## ad from here
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: the permission you want to add
'PERMISSION_NAME=1',
]
end
## to here
end
end
Here is a full list from the official docs.
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
# You can remove unused permissions here
# for more information: https://github.com/BaseflowIT/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h
# e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.calendar
'PERMISSION_EVENTS=1',
## dart: PermissionGroup.calendarFullAccess
'PERMISSION_EVENTS_FULL_ACCESS=1',
## dart: PermissionGroup.reminders
'PERMISSION_REMINDERS=1',
## dart: PermissionGroup.contacts
'PERMISSION_CONTACTS=1',
## dart: PermissionGroup.camera
'PERMISSION_CAMERA=1',
## dart: PermissionGroup.microphone
'PERMISSION_MICROPHONE=1',
## dart: PermissionGroup.speech
'PERMISSION_SPEECH_RECOGNIZER=1',
## dart: PermissionGroup.photos
'PERMISSION_PHOTOS=1',
## The 'PERMISSION_LOCATION' macro enables the `locationWhenInUse` and `locationAlways` permission. If
## the application only requires `locationWhenInUse`, only specify the `PERMISSION_LOCATION_WHENINUSE`
## macro.
##
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
'PERMISSION_LOCATION=1',
'PERMISSION_LOCATION_WHENINUSE=0',
## dart: PermissionGroup.notification
'PERMISSION_NOTIFICATIONS=1',
## dart: PermissionGroup.mediaLibrary
'PERMISSION_MEDIA_LIBRARY=1',
## dart: PermissionGroup.sensors
'PERMISSION_SENSORS=1',
## dart: PermissionGroup.bluetooth
'PERMISSION_BLUETOOTH=1',
## dart: PermissionGroup.appTrackingTransparency
'PERMISSION_APP_TRACKING_TRANSPARENCY=1',
## dart: PermissionGroup.criticalAlerts
'PERMISSION_CRITICAL_ALERTS=1',
## dart: PermissionGroup.criticalAlerts
'PERMISSION_ASSISTANT=1',
]
end
end
end
This step is necessary for the permission_handler plugin to access the native APIs in order to ask for permission. Otherwise, the plugin would not have access to this native section.
And thats it for iOS!
The permission_handler plugin
Setup
To install the plugin just add this to your pubspec.yaml and run flutter pub get
.
dependencies:
flutter:
sdk: flutter
## this
permission_handler: ^11.3.1
How to use
Import the package.
import 'package:permission_handler/permission_handler.dart';
You can check the status of a permission by doing this:
// example for the permission to send notifications
var status = await Permission.notification.status;
// status.isDenied
// status.isGranted
// status.isLimited
// status.isPermanentlyDenied
// status.isProvisional
// status.isRestricted
This will return a PermissionStatus
object.
You can request permission like this:
var status = await Permission.notification.request();
This will open the dialog for the user, asking for permission and again returning a PermissionStatus
object. If the permission is already granted, it won't open the dialog and will just return the PermissionStatus
object.
If you want to handle the different cases when calling the request methods (you should always handle both a denied and granted case), you can use the callback provided by the plugin like this:
Permission.notification
.onDeniedCallback((){
// do something
})
.onGrantedCallback((){
// do something
})
.onRestrictedCallback((){
// do something
})
.onPermanentlyDeniedCallback((){
// do something
})
.request();
And that's it already; now you know the basics of using the permission_handler plugin.
Conclussion
In conclusion, the permission_handler plugin is a powerful tool for managing permissions in your Flutter applications, allowing you to seamlessly integrate native API access with minimal configuration. By understanding the different permission statuses and setting up the necessary native requirements, you can ensure a smooth user experience while maintaining security and privacy. Thank you for taking the time to read this article. I hope you found it helpful and informative. Feel free to leave your thoughts or questions in the comments section below, and don't hesitate to share this guide with others who might benefit from it. Happy coding!
Subscribe to my newsletter
Read articles from Robin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by