Permission Handling in Flutter
Managing Permissions in Flutter: Best Practices with permission_handler
Permissions are crucial when building mobile applications that require access to device features such as location, camera, contacts, and more. In Flutter, handling these permissions effectively ensures that the app provides a seamless user experience while adhering to privacy and security requirements. One popular package to manage permissions in Flutter is permission_handler
.
This article will walk you through how to request, check, and handle different permissions in Flutter using permission_handler
, with practical examples based on the permission_handler
.
Installing permission_handler
and fluttertoast
First, add the permission_handler
and fluttertoast
package to your pubspec.yaml
file:
dependencies:
permission_handler: ^11.3.1
fluttertoast: ^8.2.4
Then, run:
flutter pub get
Handling Permissions in Flutter
The permission_handler
package provides a simple way to request permissions and check their statuses. Below is a complete breakdown of handling different permissions such as phone calls, contacts, location, SMS, and camera/microphone.
Permission Handler can handle all of these types of permissions: Calendar, Camera, Contacts, Location, Media Library, Microphone, Phone, Photos, Reminders, Sensors, SMS, Speech Recognition, Storage, Ignore Battery Optimizations, Notifications, Access Media Location, Activity Recognition, Bluetooth Permissions, Manage External Storage, System Alert Window, Request Install Packages, App Tracking Transparency, Critical Alerts, Access Notification Policy, Nearby Wi-Fi Devices, Audio, Schedule Exact Alarm, SensorsAlways, CalendarReadOnly and CalendarFullAccess but we are going to cover a few in this article
Below is a detailed guide on how to request each type of permission, handle scenarios like denial or permanent denial, and what each permission grants access to.
1. Calendar Permissions
Permissions:
calendar
,calendarReadOnly
,calendarFullAccess
Use Case: Access the user's calendar to read or write events.
Future<void> requestCalendarPermission() async {
var status = await Permission.calendar.request();
if (status.isGranted) {
// Permission granted, proceed with calendar access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Calendar permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Calendar permission denied',
);
}
}
2. Camera Permissions
Permission:
camera
Use Case: Access the device's camera for capturing photos or videos.
Future<void> requestCameraPermission() async {
var status = await Permission.camera.request();
if (status.isGranted) {
// Permission granted, proceed with camera access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Camera permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Camera permission denied',
);
}
}
3. Contacts Permissions
Permission:
contacts
Use Case: Access the user's contact list for reading or modifying contacts.
Future<void> requestContactsPermission() async {
var status = await Permission.contacts.request();
if (status.isGranted) {
// Permission granted, proceed with contacts access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Contacts permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Contacts permission denied',
);
}
}
4. Location Permissions
Permissions:
location
,locationAlways
,locationWhenInUse
,accessMediaLocation
Use Case: Access the user's location for navigation, geofencing, or nearby services.
Future<void> requestLocationPermission() async {
var status = await Permission.location.request();
if (status.isGranted) {
// Permission granted, proceed with location access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Location permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Location permission denied',
);
}
}
5. Media Library Permissions
Permission:
mediaLibrary
Use Case: Access the user's media library (iOS only).
Future<void> requestMediaLibraryPermission() async {
var status = await Permission.mediaLibrary.request();
if (status.isGranted) {
// Permission granted, proceed with media library access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Media Library permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Media Library permission denied',
);
}
}
6. Microphone Permissions
Permission:
microphone
Use Case: Access the device’s microphone for recording audio.
Future<void> requestMicrophonePermission() async {
var status = await Permission.microphone.request();
if (status.isGranted) {
// Permission granted, proceed with microphone access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Microphone permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Microphone permission denied',
);
}
}
7. Phone Permissions
Permission:
phone
Use Case: Make phone calls, read phone state, or access call logs.
Future<void> requestPhonePermission() async {
var status = await Permission.phone.request();
if (status.isGranted) {
// Permission granted, proceed with phone access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Phone permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Phone permission denied',
);
}
}
8. Photos Permissions
Permissions:
photos
,photosAddOnly
Use Case: Access the user's photo library for reading or adding photos.
Future<void> requestPhotosPermission() async {
var status = await Permission.photos.request();
if (status.isGranted) {
// Permission granted, proceed with photos access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Photos permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Photos permission denied',
);
}
}
9. Reminders Permissions
Permission:
reminders
Use Case: Access and manage reminders on the user’s device.
Future<void> requestRemindersPermission() async {
var status = await Permission.reminders.request();
if (status.isGranted) {
// Permission granted, proceed with reminders access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Reminders permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Reminders permission denied',
);
}
}
10. Sensors Permissions
Permissions:
sensors
,sensorsAlways
Use Case: Access the device’s sensors like accelerometer and gyroscope.
Future<void> requestSensorsPermission() async {
var status = await Permission.sensors.request();
if (status.isGranted) {
// Permission granted, proceed with sensors access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Sensors permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Sensors permission denied',
);
}
}
11. SMS Permissions
Permission:
sms
Use Case: Access SMS features, including reading or sending SMS messages.
Future<void> requestSmsPermission() async {
var status = await Permission.sms.request();
if (status.isGranted) {
// Permission granted, proceed with SMS access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'SMS permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'SMS permission denied',
);
}
}
12. Speech Recognition Permissions
Permission:
speech
Use Case: Access speech-to-text features.
Future<void> requestSpeechPermission() async {
var status = await Permission.speech.request();
if (status.isGranted) {
// Permission granted, proceed with speech recognition
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Speech recognition permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Speech recognition permission denied',
);
}
}
13. Storage Permissions
Permissions:
storage
,manageExternalStorage
Use Case: Access the user’s internal or external storage to read or write files.
Future<void> requestStoragePermission() async {
var status = await Permission.storage.request();
if (status.isGranted) {
// Permission granted, proceed with storage access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Storage permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Storage permission denied',
);
}
}
14. Ignore Battery Optimizations
Permission:
ignoreBatteryOptimizations
Use Case: Request the system to exclude the app from battery optimization measures.
Future<void> requestIgnoreBatteryOptimizationsPermission() async {
var status = await Permission.ignoreBatteryOptimizations.request();
if (status.isGranted) {
// Permission granted, proceed with ignoring battery optimizations
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Battery optimization permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Battery optimization permission denied',
);
}
}
15. Notification Permissions
Permission:
notification
Use Case: Allow your app to send notifications.
Future<void> requestNotificationPermission() async {
var status = await Permission.notification.request();
if (status.isGranted) {
// Permission granted, proceed with notifications access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Notification permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Notification permission denied',
);
}
}
16. Bluetooth Permissions
Permissions:
bluetooth
,bluetoothScan
,bluetoothAdvertise
,bluetoothConnect
Use Case: Access Bluetooth features for connecting to or managing Bluetooth devices.
Future<void> requestBluetoothPermission() async {
var status = await Permission.bluetooth.request();
if (status.isGranted) {
// Permission granted, proceed with Bluetooth access
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'Bluetooth permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'Bluetooth permission denied',
);
}
}
17. App Tracking Transparency
Permission:
appTrackingTransparency
Use Case: Request tracking permission from the user, a requirement for app tracking in iOS.
Future<void> requestAppTrackingTransparencyPermission() async {
var status = await Permission.appTrackingTransparency.request();
if (status.isGranted) {
// Permission granted, proceed with app tracking
} else if (status.isPermanentlyDenied) {
ShowToast.showErrorText(
text: 'App tracking permission permanently denied. Please enable it in the app settings.',
);
openAppSettings();
} else {
ShowToast.showErrorText(
text: 'App tracking permission denied',
);
}
}
Permissions play a critical role in providing users with a seamless experience while respecting their privacy. It’s essential to handle these permissions gracefully and educate users on why your app requires them.
By using the permission_handler
package, you can request, check, and manage all the necessary permissions for your Flutter application across both Android and iOS platforms. Always provide users with meaningful feedback and consider adding alternative flows in case permissions are denied or revoked.
Android and iOS configurations
It’s essential to include the necessary Android and iOS configurations. For Android, this means updating the AndroidManifest.xml
with the correct permission declarations. For iOS, permission usage descriptions must be added to the Info.plist
file to inform users why certain permissions are being requested.
Android AndroidManifest.xml
Configuration
For each permission in the 17 examples, you need to add the corresponding <uses-permission>
tag in the AndroidManifest.xml
. Here's how the permissions align with the permission_handler
package:
Camera Permission
<uses-permission android:name="android.permission.CAMERA" />
Contacts Permission
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" />
Location Permissions
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
Media Library/Storage Permission
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
Microphone Permission
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Phone Permission
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Photos Permission
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Reminders Permission (No explicit Android permission)
Sensors Permission
<uses-permission android:name="android.permission.BODY_SENSORS" />
SMS Permission
<uses-permission android:name="android.permission.READ_SMS" /> <uses-permission android:name="android.permission.SEND_SMS" />
Speech Recognition Permission
<uses-permission android:name="android.permission.RECORD_AUDIO" />
Ignore Battery Optimizations
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Notifications Permission (Handled natively in Android 13+)
Access Media Location Permission
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
Activity Recognition Permission
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
Bluetooth Permissions
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
App Tracking Transparency Permission (iOS only)
iOS Info.plist
Configuration
For iOS, you must provide descriptive keys in the Info.plist
file to inform users why your app needs specific permissions. Below are the configurations for each permission example:
Camera Permission
<key>NSCameraUsageDescription</key> <string>We need access to your camera for taking pictures.</string>
Contacts Permission
<key>NSContactsUsageDescription</key> <string>We need access to your contacts for better communication.</string>
Location Permissions
<key>NSLocationWhenInUseUsageDescription</key> <string>We need access to your location to provide location-based services.</string> <key>NSLocationAlwaysUsageDescription</key> <string>We need access to your location to track your movement even when the app is not active.</string>
Media Library/Storage Permission
<key>NSPhotoLibraryUsageDescription</key> <string>We need access to your photos for sharing or uploading media.</string>
Microphone Permission
<key>NSMicrophoneUsageDescription</key> <string>We need access to your microphone for voice recording.</string>
Phone Permission
<key>NSPhoneUsageDescription</key> <string>We need access to phone services to enable calls.</string>
Photos Permission
<key>NSPhotoLibraryAddUsageDescription</key> <string>We need permission to add photos to your library.</string>
Reminders Permission
<key>NSRemindersUsageDescription</key> <string>We need access to your reminders for task management.</string>
Sensors Permission
<key>NSSensorsUsageDescription</key> <string>We need access to your sensors for fitness tracking.</string>
SMS Permission (Handled automatically by iOS if SMS services are requested)
Speech Recognition Permission
<key>NSSpeechRecognitionUsageDescription</key>
<string>We need access to speech recognition for voice commands.</string>
Ignore Battery Optimizations (Not applicable on iOS)
Notifications Permission
<key>NSUserNotificationUsageDescription</key>
<string>We need permission to send notifications.</string>
Access Media Location Permission (Handled automatically on iOS)
Activity Recognition Permission
<key>NSMotionUsageDescription</key>
<string>We need access to motion data for fitness tracking.</string>
- Bluetooth Permissions
<key>NSBluetoothPeripheralUsageDescription</key>
<string>We need access to Bluetooth for device connectivity.</string>
- App Tracking Transparency
<key>NSUserTrackingUsageDescription</key>
<string>We need permission to track your activity across apps and websites for personalized ads.</string>
To make your app fully functional and compliant with the latest privacy regulations, it’s essential to manage permissions properly. By updating both AndroidManifest.xml
and Info.plist
, along with implementing the correct permission-handling logic in your Flutter app, you provide a seamless and transparent experience for users while requesting access to sensitive features.
Always ensure you test permissions on both platforms and provide meaningful explanations to users about why the permissions are needed to avoid rejection during app store reviews.
For more in-depth research consider checking the official permission handler documentation to explore other permission types. Make sure to also update your platform-specific files (such as AndroidManifest.xml
and Info.plist
) with the necessary declarations for each permission type.