Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders

Overview

saf

Saf

Saf

Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Currently supported features

  • Uses OS default native file explorer
  • Access the hidden folder and files
  • Accessing directories
  • Caching the files inside the app External files directory
  • Syncing the files of some directory with cached one
  • Different default type filtering (media, image, video, audio or any)
  • Support Android

If you have any feature that you want to see in this package, please feel free to issue a suggestion. πŸŽ‰

Usage

To use this plugin, add saf as a dependency in your pubspec.yaml file.

Initiate Saf with instance

Saf saf = Saf(directoryPath: "~/some/path")

Directory Permission request

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

if (isGranted != null) {
  // Perform some file operations
} else {
  // User canceled the native explorer
}

Get paths of all the files of granted directory

List<String>? paths = await saf.getFilesPath(FileType.media);

Cache the granted directory

List<String>? cachedFilesPath = await saf.cache();

Get the cached files' path

List<String>? cachedFilesPath = await saf.getCachedFilesPath();

Cache a single file of the granted directory

String? path = await saf.singleCache(filePath: "~/some/path/file.type");

Clear cache of the granted directory

bool? isClear = await saf.clearCache();

Sync the cached directory with the granted directory

bool? isSynced = await saf.syncWithCacheDirectory();

Release the persisted permission for current granted directory

bool? isReleased = await saf.releasePersistedPermission();

Get the list of all the granted directory paths with persisted permissions

// Static method
List<String>? paths = await Saf.getPersistedPermissionDirectories();

Release the persisted permissions for all granted the directories

// Static method
bool? isReleased = await Saf.releasePersistedPermissions();

Documentation

See the Saf Wiki for every detail on about how to install, setup and use it.

Saf Wiki

  1. Installation
  2. Setup
  3. API
  4. FAQ
  5. Troubleshooting

For full usage details refer to the Wiki above.

Example App

Android

Demo

Compatibility Chart

API Android iOS Windows linux macOS
getDirectoryPermission() βœ… ❌ ❌ ❌ ❌
getFilesPath() βœ… ❌ ❌ ❌ ❌
getCachedFilesPath() βœ… ❌ ❌ ❌ ❌
cache() βœ… ❌ ❌ ❌ ❌
singleCache() βœ… ❌ ❌ ❌ ❌
clearCache() βœ… ❌ ❌ ❌ ❌
syncWithCacheDir() βœ… ❌ ❌ ❌ ❌
getPersistedPermissionDirectories() βœ… ❌ ❌ ❌ ❌
releasePersistedPermissions() βœ… ❌ ❌ ❌ ❌

See the API section of the Saf Wiki or the official API reference on pub.dev for further details.

Getting Started

For help getting started with Flutter, view our online documentation.

For help on editing plugin code, view the documentation.

Comments
  • Not compatible with flutter permission_handler above v9.2.0.

    Not compatible with flutter permission_handler above v9.2.0.

    When I set flutter permission_handler version to ^10.1.0 I get the following error:

    Because saf 1.0.3+3 depends on permission_handler ^9.2.0 and no versions of saf match >1.0.3+3 <2.0.0, saf ^1.0.3+3 requires permission_handler ^9.2.0.
    So, because myapp depends on both permission_handler ^10.1.0 and saf ^1.0.3+3, version solving failed.
    pub get failed (1; So, because myapp depends on both permission_handler ^10.1.0 and saf ^1.0.3+3, version solving failed.)
    exit code 1
    
    opened by markhorrocks 3
  • Can't use this folder to protect your privacy choose another folder ....!!!

    Can't use this folder to protect your privacy choose another folder ....!!!

    I am unable to access .statuses folder directly. When I click on the "grant button" it does not directly open the ,statuses folder and open the root directory and the "use this folder" button is unclickable. User have to open manually this folder to get access.

    here is the directory which I want to access: saf = Saf( '/storage/emulated/0/Android/media/com.whatsapp/WhatsApp/Media/.Statuses'); WhatsApp Image 2022-11-16 at 7 56 33 PM

    opened by HussnulMaab192 1
  • Incorrect dependencies

    Incorrect dependencies

    Running "flutter pub get" in appnote...
    Because every version of saf depends on permission_handler ^9.2.0 and appnote depends on permission_handler ^10.0.0, saf is forbidden. So, because appnote depends on saf ^1.0.3+3, version solving failed. pub get failed (1; So, because appnote depends on saf ^1.0.3+3, version solving failed.)

    opened by gorkovv 1
  • Exception - Permission Denial

    Exception - Permission Denial

    This exception appear when I try to open media directory

    Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses/document/primary%3AAndroid%2Fmedia%2Fcom.whatsapp%2FWhatsApp%2FMedia%2F.Statuses/children from pid=32755, uid=10159 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs

    opened by AliAlHourash 1
  • Fix #14 & #19: upgrade permission_handler to ^10.2.0.0

    Fix #14 & #19: upgrade permission_handler to ^10.2.0.0

    Fix #14 & #19: upgrade permission_handler to ^10.2.0.0

    • update permission_handler dependencie from ^9.2.0 to ^10.2.0
    • change compileSdkVersion from 31 to 33 to be compatible with permission_handler
    opened by AMuellerAtAHS 0
  • A suggestion for simple usage

    A suggestion for simple usage

    Writing to external directory is required for certain cases and it gives too much complexities in achieving this.

    Play console does not allow apps to be published with "External manage" permissions, that is where SAF comes in.

    Now, my suggestion is simple. Why don't API allow an external root folder in the name of Application ID i.e. com.MyApp which is already unique to that App. Just like "GetApplicationsDocumentsDirectory", there can be "GetApplicationsRootDirectory" which always gives a folder based application ID with full access only to that App with the same appication ID.

    So any app from play store cannot access this folder (i.e. the security checking inside API can be made to achieve this). If possible attach the publisher's digital signature optionally to this.

    This method has only one issue. If a develper creates an App with some one else's Application ID and don't publish but some how installs manually in user's phone. This is not an issue actually because the App has not come from play store , so don't bother about security issues.

    opened by SampathNarayanan 0
  • How to sort list by date

    How to sort list by date

    Hi, I was wondering if we can sort the list of strings by their creation time or modified time. I'm making the use of cache method which returns list of string but it returns in the random order

    opened by superwebarmy 1
  • Sometimes files not getting in realme device (Android 11)

    Sometimes files not getting in realme device (Android 11)

    Saf saf = Saf("Android/media/com.whatsapp.w4b/WhatsApp Business/Media/.Statuses");
      bool? isSync = await saf.sync();
          if (isSync != null && isSync) {
            List<String>? _paths = await saf.getCachedFilesPath();
            if (_paths != null) {
              loadImage(_paths);
            }
    
     void loadImage(List<String> paths) {
        imageAssets = paths
            .map((item) => item)
            .where((item) => item.endsWith('.jpg'))
            .toList();
      }
    

    isSync getting null and _paths getting empty after 3-4 days from install app Other device working well but in realme device (Android 11) this problem happen.

    opened by prinsdha 0
  • Support for Android obb or data folder(commit from material files app)

    Support for Android obb or data folder(commit from material files app)

    Hello if possible can you add read or write access to data or obb folder. There is native File explorer that allows that here is commit for that. Thanks :D. https://github.com/zhanghai/MaterialFiles/commit/e356a9c5dc3f60d24a950e3d6f42018bf522c3e1

    opened by VirtualAstronaut 0
  • Can't the saf.sync() function copy files from the cache folder to android/data/xxx? Then how is it different from saf.cache()?

    Can't the saf.sync() function copy files from the cache folder to android/data/xxx? Then how is it different from saf.cache()?

    I want to copy the files from the cache to the directory after modifying them. But asf.sync() doesn't work. It just copies the files in directory to cache. what should I do?

    opened by jethroHuang 1
Owner
Vehement
Vehement ❀️ Open Source
Vehement
RoomJetpackCompose is an app written in Kotlin and shows a simple solution to perform CRUD operations in the Room database using Kotlin Flow in clean architecture.

RoomJetpackCompose is an app written in Kotlin and shows a simple solution to perform CRUD operations in the Room database using Kotlin Flow in clean architecture.

Alex 27 Jan 1, 2023
Muhammad Bilal 0 Jan 6, 2022
Esp touch flutter plugin - Client-side (mobile) Android Flutter implementation for ESP-Touch protocol

esp_touch_flutter_plugin Client-side (mobile) Android Flutter implementation for

huangyanxiong 0 Jan 21, 2022
Whereabouts: an android library which leverages Kotlin concurrency to streamline location fetching

Whereabouts Whereabouts is an android library which leverages Kotlin concurrency

Sumeet Rukeja 1 Jul 5, 2022
A flutter plugin to scan stripe readers and connect to the them and get the payment methods.

stripe_terminal A flutter plugin to scan stripe readers and connect to the them and get the payment methods. Installation Android No Configuration nee

Aawaz Gyawali 8 Dec 29, 2022
Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.

Themis provides strong, usable cryptography for busy people General purpose cryptographic library for storage and messaging for iOS (Swift, Obj-C), An

Cossack Labs 1.6k Jan 8, 2023
A modular object storage framework for Kotlin multiplatform projects.

ObjectStore A modular object storage framework for Kotlin multiplatform projects. Usage ObjectStore provides a simple key/value storage interface whic

Drew Carlson 4 Nov 10, 2022
[Android Library] Get easy access to device information super fast, real quick

DeviceInfo-Sample Simple, single class wrapper to get device information from an android device. This library provides an easy way to access all the d

Anitaa Murthy 193 Nov 20, 2022
πŸ› οΈ The missing drawable toolbox for Android. Create drawables programmatically and get rid of the boring and always repeated drawable.xml files.

DrawableToolbox English | δΈ­ζ–‡ The missing DrawableToolbox for Android. Create drawables programmatically and get rid of the boring and always repeated

Hong Duan 1.1k Jan 4, 2023
use kmm to write a flutter plugin

use KMM to write a flutter plugin The reference plugin_codelab example plugin that accompanies the How to write a Flutter plugin codelab. I changed pl

libill 8 Nov 9, 2022
A pure Kotlin/Multiplatform implementation of group operations on Curve25519.

curve25519-kotlin A pure Kotlin/Multiplatform implementation of group operations on Curve25519. Gradle Kotlin DSL: dependencies { implementation("

Andrey Pfau 9 Dec 22, 2022
:blowfish: An Android & JVM key-value storage powered by Protobuf and Coroutines

PufferDB PufferDB is a ⚑ key-value storage powered by Protocol Buffers (aka Protobuf) and Coroutines. The purpose of this library is to provide an eff

Adriel CafΓ© 94 Dec 7, 2022
A local storage management library for Kotlin Multiplatform Mobile iOS and android

A local storage management library for Kotlin Multiplatform Mobile iOS and android Features iOS and Android local storage in one interface Provides ge

LINE 20 Oct 30, 2022
πŸ”₯πŸ–Ό Display images stored in Cloud Storage for Firebase using Coil

firecoil firecoil allows you to load images from Cloud Storage for Firebase in your Android app (through a StorageReference) , using the image loading

RosΓ‘rio Pereira Fernandes 35 Oct 4, 2022
A simple solution to handling persistent data storage in your Minecraft server.

Modern Data Stores A simple solution to handling persistent data storage in your Minecraft server. This plugin will be used throughout the Modern Plug

Modern Plugins 2 Nov 7, 2022
A simple solution to handling persistent data storage in your Minecraft server.

Modern Data Stores A simple solution to handling persistent data storage in your Minecraft server. This plugin will be used throughout the Modern Plug

Modern Plugins 2 Nov 7, 2022
Simple MVVM app to get photos through https://unsplash.com api

MyPhotoLoaderApp Simple photo loading app powered by Unsplash.com which implements MVVM architecture using Hilt, Navigation Component, Retrofit, Pagin

Behnam Banaei 10 Oct 6, 2022
A Flutter implementation of Salesforce Marketing Cloud for iOS and Android

sfmc_flutter A Flutter implementation of Salesforce Marketing Cloud for iOS and Android. Features Setup Marketing Cloud (iOS and Android) Support for

Alex TarragΓ³ 5 Oct 19, 2022