I was very troubled with this issue After applying several solutions I found this solution. So I want to share it with everyone, that's why I asked the question and I answered
On most operating systems, permissions aren't just granted to apps at install time. Rather, developers have to ask the user for permissions while the app is running.
The best way to handle permissions is by using the permission_handler
plugin. This plugin provides a cross-platform (iOS, Android) API to request permissions and check their status.
We can also open the device's app settings so users can grant permission.
On Android, we can show a rationale for requesting permission.
Add this to your package's pubspec.yaml
file:
dependencies:
permission_handler: ^5.0.1+1
Now in your Dart code, you can use:
import 'package:permission_handler/permission_handler.dart';
While the permissions are being requested during runtime, you'll still need to tell the OS which permissions your app might potentially use. That requires adding permission configuration to Android- and iOS-specific files.
iOS
- Add permission to your?Info.plist?file. Here's an example?Info.plist?with a complete list of all possible permissions.
IMPORTANT: You will have to include all permission options when you want to submit your App. This is because the permission_handler
plugin touches all different SDKs and because the static code analyser (run by Apple upon App submission) detects this and will assert if it cannot find a matching permission option in the Info.plist
. More information about this can be found here.
Add the following to your Podfile
file:
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
## dart: PermissionGroup.calendar
'PERMISSION_EVENTS=0',
## dart: PermissionGroup.reminders
'PERMISSION_REMINDERS=0',
## dart: PermissionGroup.contacts
# 'PERMISSION_CONTACTS=0',
## dart: PermissionGroup.camera
# 'PERMISSION_CAMERA=0',
## dart: PermissionGroup.microphone
# 'PERMISSION_MICROPHONE=0',
## dart: PermissionGroup.speech
'PERMISSION_SPEECH_RECOGNIZER=0',
## dart: PermissionGroup.photos
# 'PERMISSION_PHOTOS=0',
## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
'PERMISSION_LOCATION=0',
## dart: PermissionGroup.notification
# 'PERMISSION_NOTIFICATIONS=0',
## dart: PermissionGroup.mediaLibrary
'PERMISSION_MEDIA_LIBRARY=0',
## dart: PermissionGroup.sensors
'PERMISSION_SENSORS=0'
]
end
end
end
Remove the #
character in front of the permission you do not want to use. For example if you don't need access to the calendar make sure the code looks like this:
## dart: PermissionGroup.calendar
'PERMISSION_EVENTS=0',
Android
Add the following to your "gradle.properties
" file:
android.useAndroidX=true
android.enableJetifier=true
Make sure you set the?compileSdkVersion
?in your "android/app/build.gradle
" file to 28:
android {
compileSdkVersion 30
...
}
Make sure you replace all the?android.?dependencies to their AndroidX counterparts (a full list can be found here:?https://developer.android.com/jetpack/androidx/migrate)
Add permissions to your?AndroidManifest.xml
?file. There's a?debug
,?main
?and?profile
?version which are chosen depending on how you start your app. In general, it's sufficient to add permission only to the?main
?version.?Here's an example?AndroidManifest.xml
?with a complete list of all possible permissions.
Finally you can use like this
There are a number of?Permissions. You can get a?Permission
's?status
, which is either?granted
,?denied
,?restricted
?or?permanentlyDenied
.
var status = await Permission.photos.status;
if (status.isDenied) {
// We didn't ask for permission yet.
}
// 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.
}
Call `request()` on a `Permission` to request it. If it has already been granted before, nothing happens.
request()
returns the new status of the Permission
.
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 [
Permission.location,
Permission.storage,
].request();
print(statuses[Permission.location]);
On Android, you can show a rationale for using permission:
bool isShown = await Permission.contacts.shouldShowRequestRationale;
Full Example
Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: Icon(Icons.camera_enhance),
title: Text(getTranslated(context, "Camera")),
onTap: () async {
var status = await Permission.photos.status;
if (status.isGranted) {
final pickedFile =
await _picker.getImage(source: ImageSource.camera);
final File file = File(pickedFile.path);
imageSelected(file);
} else if (status.isDenied) {
final pickedFile =
await _picker.getImage(source: ImageSource.camera);
final File file = File(pickedFile.path);
imageSelected(file);
} else {
showDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text('Camera Permission'),
content: Text(
'This app needs camera access to take pictures for upload user profile photo'),
actions: <Widget>[
CupertinoDialogAction(
child: Text('Deny'),
onPressed: () => Navigator.of(context).pop(),
),
CupertinoDialogAction(
child: Text('Settings'),
onPressed: () => openAppSettings(),
),
],
));
}
}),
],
),
)