0

I'm trying to create a new JSON file generated by my Flutter application and I wanna let the user to choose where to store this file.

I'm currently using file_picker package to let the user to choose the path to store the generated file. If I select the Documents folder (/storage/emulated/0/Documents) I can create that file, but if I choose another path (like /storage/emulated/0/DCIM or a custom folder created by the user named Test for example) I get the following exception: FileSystemException: Cannot open file, path = '/storage/emulated/0/Test/backup.json' (OS Error: Operation not permitted, errno = 1)

Note that I'm running my app on an emulator that have Android 13. I also tried to add this permissions in the Manifest:

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

And tried to request storage permissions with the package permission_handler but nothing change.

Melom
  • 400
  • 1
  • 5
  • 14

4 Answers4

0

DCIM maybe is part from media or photos

so try this if work, I do usually include in my manifest

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 // try to add this 2 lines
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
 // Optional to add this 
 <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>

and setting my gradle as like this

  android {
     compileSdkVersion 33
     ....
     // from deafult config 
     defaultConfig{
      ...
      mindSdkVersion 28
      targetSdkVersion 33

  }

then for permission you can either put them on list just in case when requesting

 // You can either call this in initState or any listener you have
 // as long ass it can be triggered first on page
 static Future<void> requestStorageorPhotos() async{
    await [
       Permission.photos,
       Permission.storage,
     ].request();
    // try to listen from its changes permission
    if((await Permission.photos.status.isGranted) || (await 
      Permission.storage.status.isGranted)){
      // Do your thing if allow
    }else{
     // or anything in here from not allowing it.
    }
  }
Arbiter Chil
  • 1,061
  • 1
  • 6
  • 9
0

If you are targeting Android 11 and up(targetSdkVersion 30) then you require the following permissions in AndroidManifest.xml for modifying and document access.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

You can find more details in here https://stackoverflow.com/a/66366102/19292778

MrShakila
  • 874
  • 1
  • 4
  • 19
  • Using `MANAGE_EXTERNAL_STORAGE` is a bad practice. The IDE also will tell you this: "The Google Play store has a policy that limits usage of MANAGE_EXTERNAL_STORAGE". So probably the app will be rejected if I try to upload it in the Google Play Store – Melom Apr 27 '23 at 11:07
0

Your app does not need any permission on an Android 13 device to create files in all public directories.

But .. in DCIM and Picture folder you can only create image files. In Audio and Music only music files and so on.

Only in Documents and Download directory you can create all types of files.

blackapps
  • 8,011
  • 2
  • 11
  • 25
0

Finally managed to solve it thanks to a great library. The library name is flutter_file_dialog and works perfectly fine. Here a snippet of how to use it:

Future<OperationStatusCode> createLocalBackupFile() async {
    try {
    
      // ... 

      if (!await FlutterFileDialog.isPickDirectorySupported()) {
        throw Exception("Picking directory not supported");
      }

      // This will open file system manager
      final pickedDirectory = await FlutterFileDialog.pickDirectory();

      // Check if choosen directory is not null and proceed to save the file
      if (pickedDirectory != null) {
        await FlutterFileDialog.saveFileToDirectory(
          directory: pickedDirectory,
          data: YOUR_FILE_DATA,
          mimeType: "application/json",
          fileName: "backup_file_$formattedFileDate.json",
          replace: false,
        );
        return OperationStatusCode.success;
      }
      return OperationStatusCode.undefined;
    } catch (exc) {
      return OperationStatusCode.error;
    }
  }

With this library the user will be able to choose where to store his file and also he can create new folders to store that file. You don't need to set any type of permission in the Manifest.xml or Info.plist :)

Melom
  • 400
  • 1
  • 5
  • 14