Baseflow / flutter-permission-handler

Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions.
https://baseflow.com
MIT License
2.05k stars 858 forks source link

Storage Permission not working #885

Closed gegobyte closed 1 year ago

gegobyte commented 2 years ago

🔙 Regression

I have an app which asks user for storage permission and then proceeds to download a file in the Download directory on the device. I am using the latest version of Permission Handler which is 10.0.0 but on my new app created with the latest version of Flutter, getting this error:

FileSystemException: Cannot open file, path = '/storage/emulated/0/Download/abc.pdf' (OS Error: Permission denied, errno = 13)

Here is the code for request permission and saving the file to Download folder:

try {
      final output = await getExternalStorageDirectory();
      RegExp pathToDownloads = RegExp(r'.+0\/');
      final outputPath = '${pathToDownloads.stringMatch(output!.path).toString()}Download'; // returns /storage/emulated/0/Download
      final filePath = '$outputPath/abc.pdf';
      var file = File(filePath);

      // Ask for storage permission
      if (await Permission.storage.request().isGranted) {
        await file.writeAsBytes(pdfBytes);
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('File has been downloaded'),
            duration: Duration(seconds: 2),
          ),
        );
      }
    } catch (error) {
      print(error);
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text(
              'Allow storage permission so that file pdf can be saved'),
          duration: Duration(seconds: 2),
        ),
      );
    }

The above code asks for permission but despite tapping on Allow, the catch part is triggered and it gives the above permission error. Permission is also set in the manifest file:

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

Old (and correct) behavior

The above code used to work flawlessly on my old app and still works with the latest version 10.0.0 but my new app created with latest version of Flutter does not work.

Current behavior

These are the minimum and target sdk version in build.gradle

minSdkVersion 21
targetSdkVersion 33

Configuration

Permission Handler Version: 10.0.0 Flutter Version: 3.0.5

Platform:

JDDV commented 2 years ago

Hi @gegobyte, It seems like I can reproduce it half of the time using your code strange enough. I had it succeeded, where the file abc.pdf is created. But also times where he said the permission wasn't granted.

I tested it on API 31 (Android 12).

Can you provide me a bit more information, and tell me on what Android version you're testing this?

gegobyte commented 2 years ago

Can you provide me a bit more information, and tell me on what Android version you're testing this?

I've also tested on Android 12. I am also getting the same result - sometimes it downloads successfully, sometimes I get permission error.

gegobyte commented 2 years ago

@JDDV Do you recommend any temporary solution until this is fixed?

armandojimenez commented 2 years ago

Any fix for this?

naumanmir commented 2 years ago

@gegobyte you need to use "manageExternalStorage" permission both at runtime and in manifest along with storage permission.

PeterNjeim commented 2 years ago

The temporary solution is to go to the app's settings and revoke the file permission, then regrant the permission. Then you can open the app again and it should have file access.

PeterNjeim commented 2 years ago

Android 13: works fine Android 12 and 12.1/12L: permission is "fake" granted, user needs to go to app's settings (in Android settings) and revoke and regrant the file access permission for it to actually apply. Android 11: needs testing Android 10: needs testing

This is with WRITE_EXTERNAL_STORAGE permission with a targetSdkVersion of 29 (Android 10), that way I can use the requestLegacyExternalStorage="true" option.

Someone else should test this on Android 11 and Android 10 to see if it's limited to Android 12 and 12.1 / 12L only

gegobyte commented 2 years ago

@gegobyte you need to use "manageExternalStorage" permission both at runtime and in manifest along with storage permission.

Would the app not get rejected after using manage external storage permission? I have read a few instances of apps getting rejected using this permission and targeting Android 11 without giving a good reason.

PeterNjeim commented 2 years ago

Can people try my workaround? I'm waiting to see if it's a real workaround or not, 2 people have had success with it so far

Edit: 4 now

Shvet commented 2 years ago

Android 33 Emulator not working

dsingh06 commented 2 years ago

I have the exact same problem, very similar code with:

minSdkVersion 21 targetSdkVersion 33

Checking on a physical device, there is no permission popup.

PeterNjeim commented 2 years ago

@dsingh06 can you try my workaround and reply back to me?

dsingh06 commented 2 years ago

@dsingh06 can you try my workaround and reply back to me?

Hi, it is not fully clear to me what your workaround is and steps to be followed.

When I goto app settings, I cannot see individual permissions mentioned where I can revoke them (mentioning it in case this is part of your workaround)

PeterNjeim commented 2 years ago

@dsingh06 See the attached images. Press "Don't allow" then "Allow" Screenshot_20221016-134754_Settings~2.png

Screenshot_20221016-134625_Permission_controller~2.png

Screenshot_20221016-134923_Permission_controller~2.png

dsingh06 commented 2 years ago

I do not see 'Files Permission' mentioned anywhere (neither in 'Allowed' nor 'Not Allowed'. My Manifest files do have external storage mentioned. Screenshot 2022-10-16 at 23 33 56

PeterNjeim commented 2 years ago

@dsingh06 The lack of the permission in the permissions list is probably your problem, not related to this issue. Since you're targeting Android SDK 33, I don't believe you can use external storage permission anymore. Target a lower SDK version and try again

StarkZzzOoo commented 1 year ago

I change permmission in settings ,and it work.but it's not a good method for user.

aacsus commented 1 year ago

I have the same problem. Emulator does not ask External Storage Permission. I load the .apk to my Android 11, API 33 phone, and it works fine. I use the latest Android Studio. Both Emulator and Phone ask AUDIO permission though.

PeterNjeim commented 1 year ago

@aacsus can you try my workaround and see if it works?

aacsus commented 1 year ago

@aacsus can you try my workaround and see if it works?

I tried to downgrade SDK 33 to SDK 30. Everything got screwed up. A lot of errors. I then lowered the other components' versions too. No help. SDK 30 was pushing me to SDK 31. When switched to 31, it in turn pushed me to 32. I ended up going back to SDK 33. Now, it stopped asking AUDIO too. No permissions asked, it runs the program (in emulator)!

PeterNjeim commented 1 year ago

@aacsus Which permission are you requesting? If you can't see the permission in the settings page, then you probably are using a deprecated permission.

aacsus commented 1 year ago

@PeterNjeim FILE and AUDIO permissions (multi permissions). I improved the code little bit, it started asking AUDIO again (in SDK 33). However, FILE permission is still the same; works in Android phone (V11, API 33), but does not work in the Emulator. The SETTINGS page in Emulator does not show FILE permission, while both are visible in phone.

aeaevo commented 1 year ago

Does anyone have a real fix for this issue yet? Please don't tell me that the user has to revoke rights in the settings and regrant them, that is not a fix 😂

await Permission.storage.request().isGranted does not show a popup to grant permission. Other permissions work fine.

PeterNjeim commented 1 year ago

It's fine to say you want a fix (that's what everyone here is for anyways), it's not fine to say someone else is lying about their "fix". I never said it was a fix, I said it was a workaround, which is a big difference. My message only serves to help people temporarily while a fix is waited for. Please adjust your comment to say that you don't care about workarounds, instead of misrepresenting my comments

aeaevo commented 1 year ago

@PeterNjeim I really did not mean to offend you at all and I do appreciate everyone's efforts here! Classic misunderstanding... Let's just concentrate on solving this issue. I am curious how such a major bug persists since August last year - is there a bigger underlying problem?

Did someone try to switch from stable flutter version to master?

aeaevo commented 1 year ago

Same issue for flutter latest stable & master channel

blue492 commented 1 year ago

Same here, https://github.com/Baseflow/flutter-permission-handler/issues/972

aeaevo commented 1 year ago

I guess @PeterNjeim already did mention the main reason why most of us (maybe even all of us) are facing this problem earlier in this thread. We don't need to ask for the READ_EXTERNAL_STORAGE permission since targetSDK 33 anymore. Check this thread on StackOverflow.

So this works without any permission request:

Directory? storageDirectory; 
if (Platform.isAndroid) {
  storageDirectory = await getExternalStorageDirectory();
} else if (Platform.isIOS) {
  storageDirectory = await getApplicationDocumentsDirectory();
}
NawrasBukhari commented 1 year ago

this issue still presents till today

AndersonMichellin commented 1 year ago

I had the same problem as described here and I haven't found any definitive solution so far. Here's what I did to resolve it: 1o. I put this permission in the AndroidManifest.xml: <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

2o. I updated the package_info_plus, file_picker, permission_handler and device_info_plus to the latest versions and everything is working again.

3o. However, it is worth remembering that it is necessary to treat the SDK version to verify the permissions and plataform (IOS or Android) commands:

  Future<bool> ePermitidoGravar() async {
    DeviceInfoPlugin plugin = DeviceInfoPlugin();
    AndroidDeviceInfo android = await plugin.androidInfo;
    if( android.version.sdkInt < 33 ){
      var status = Platform.isAndroid
        ? await Permission.storage.status
        : await Permission.photos.status;               //https://github.com/Baseflow/flutter-permission-handler/issues/440
      if (!status.isGranted) {
        if(Platform.isAndroid){
          status = await Permission.storage.request();
          if(status.isPermanentlyDenied){
            await openAppSettings();
            status = await Permission.storage.status;              //https://github.com/Baseflow/flutter-permission-handler/issues/440
          }
        }else{
          status = await Permission.photos.request();
          if(status.isPermanentlyDenied){
            await openAppSettings();
            status = await Permission.photos.status;               //https://github.com/Baseflow/flutter-permission-handler/issues/440
          }
        }
        if(!status.isGranted){
          return false;
        }
      }
    }else {
      var status = Platform.isAndroid
        ? await Permission.manageExternalStorage.status
        : await Permission.photos.status;                 //https://github.com/Baseflow/flutter-permission-handler/issues/440
      if (!status.isGranted) {
        if (Platform.isAndroid) {
          status = await Permission.manageExternalStorage.request();
          if(status.isPermanentlyDenied){
            await openAppSettings();
            status = await Permission.storage.status;              //https://github.com/Baseflow/flutter-permission-handler/issues/440
          }
        } else {
          status = await Permission.photos.request();
          if (status.isPermanentlyDenied) {
            await openAppSettings();
            status = await Permission.photos.status;
          }
        }
      }
    }
    return true;
  }
petermusembi69 commented 1 year ago

Add this permission in the manifest file - source

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
VirtualAstronaut commented 1 year ago

MANAGE_EXTERNAL_STORAGE

This is sensitive permission and should not be used if does not full-fill use case list

mvanbeusekom commented 1 year ago

Duplicate of issue #955.

The permission_handler is working as intended, have a look at this comment for more details.