Search code examples
androidflutterdartstorage-access-frameworksaf

How to do file operations (create/write/update/delete files) using the Flutter "saf" Package


How to do file operations (create/write/update/delete files) using the Flutter "saf" Package.

link:- pub.dev/packages/saf

I didn't find any solutions on Google. I want to use Android "Storage Access Framework" and let users select a folder on External Storage. In this folder, I want to save my app files that users can access.

Previously I was using app-specific storage (Android/data/com.myapp). But from Android 11 users can't access this folder due to Security Update from Google.

Any solutions will be appreciated. Thanks in advance.

bool? isGranted = await saf.getDirectoryPermission(isDynamic: false);

if (isGranted != null && isGranted) {
  // Perform some file operations
  // **But How?**
} else {
  // failed to get the permission
}

Solution

  • If you get the folder access by using Storage Access Framework then you can not perform file handling operations on this folder by using the dart: 'dart: io' package. Check URL: SAF root gives your application access to the corresponding storage, but only through the SAF API, not directly via the filesystem. Also, from Android 11 and above, without MANAGE_EXTERNAL_STORAGE permission, accessing data from external storage using java.io.File is almost completely deprecated.

    I found two Packages that support Storage Access Framework in the flutter.

    shared_storage: ^0.2.0

    saf: ^1.0.3+3

    shared_storage 0.2.0 provide us

    Uri uri = await openDocumentTree(); 
    List<UriPermission> persistedUris = await persistedUriPermissions();
    

    and

    /// Create a new file using the `SAF` API
    final newDocumentFile = await createDocumentFile(
      mimeType: 'text/plain',
      content: 'My Plain Text Comment Created by shared_storage plugin',
      displayName: 'CreatedBySharedStorageFlutterPlugin',
      directory: anySelectedUriByTheOpenDocumentTreeAPI,
    );
    
    print(newDocumentFile);
    

    By above method can create file by using writeAsString() instead of writeAsBytes(). But for creating an Image file we required writeAsBytes().

    saf 1.0.3+3 having a method createFileAsBytes() in document_file.dart but not available for usage in current version.

    But in the future, both packages will provide these APIs.

    Solution: For now, I have solved this issue by using both packages simultaneously.

    Add packages in your pubspec.yaml:

    shared_storage: ^0.2.0

    saf: ^1.0.3+3

    And use the following code

    void createFileBySAF(String fileName, Uint8List uint8list) {
    
      /*From: shared_storage: ^0.2.0*/
      Uri uri = await openDocumentTree(); 
      
      /*From: saf: ^1.0.3+3*/
      Map<String, dynamic> result = await MethodChannel('com.ivehement.plugins/saf/documentfile').invokeMapMethod<String, dynamic>('createFile', <String, dynamic>{
        'mimeType': 'any',
        'content': uint8list,
        'displayName': fileName,
        'directoryUri': '$uri',
      });
      print(result);
    }
    

    For the Update and Delete operations find the usage in https://github.com/ivehement/saf/blob/master/lib/src/storage_access_framework/document_file.dart