Android SD Card Write Permission using SAF (Storage Access Framework)
Letting the user choose the "SD card" or even the "Internal storage" SAF root give your application access to the corresponding storage, but only through the SAF API, not directly via the filesystem. For example you code could be translated into something like :
public void writeFile(DocumentFile pickedDir) {
try {
DocumentFile file = pickedDir.createFile("image/jpeg", "try2.jpg");
OutputStream out = getContentResolver().openOutputStream(file.getUri());
try {
// write the image content
} finally {
out.close();
}
} catch (IOException e) {
throw new RuntimeException("Something went wrong : " + e.getMessage(), e);
}
}
In recent version of Android, accessing data outside your application using java.io.File
is almost completely deprecated.
Does SAF(Storage Access Framework) solve the SD card WRITE issue in Android 4.4 (KitKat)?
When implementing a DocumentsProvider
, you can only extend access to files on disk that you already have access to. Adding a DocumentsProvider
doesn't give you any new access, so you probably don't need to implement one.
You can gain write access anywhere on an SD card by using the ACTION_OPEN_DOCUMENT
or ACTION_CREATE_DOCUMENT
intents that you mentioned. There is an ExternalStorageProvider
built into the system that has access to all SD cards, and it will gladly delegate write access to you once confirmed by the user through those intents.
Users may need to enable "Settings > Display advanced devices" to show the SD cards offered by ExternalStorageProvider
. Also, if you want to limit the user to interacting with local storage, you can set EXTRA_LOCAL_ONLY
.
As for (2), you can create new files outside your package-specific directory with ACTION_CREATE_DOCUMENT
, and you can select existing files with either intent. User-selected files can be deleted with DocumentsContract.deleteDocument()
.
And for (3), MediaDocumentsProvider
built into the platform currently does not extend FLAG_SUPPORTS_WRITE
for Photos, Videos, and Music.
Hope this helps. :)
Does Anyone knows Where this permission come from and how to grant this programmatically in Android?
I found it after too many searching in Stack Overflow , So there is a flag that call that dialog and get the uri of the storage ,but this way only works with android 7 to 10.
here is answer of my question :
question answer
How to do file operations (create/write/update/delete files) using the Flutter saf Package
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
Related Topics
Android Google Maps API V2 Zoom to Current Location
How to Have a Viewpager Inside of a Scrollview
How to Handle the Firebase Notification When App Is in Foreground
Httpentity Is Deprecated on Android Now, What's the Alternative
Difference Between Content_Main.Xml and Activity_Main.Xml
Android.Os.Networkonmainthreadexception with Android 4.2
Why Shouldn't I Use System.Out.Println() in Android
Google Play Security Alert - Your App Is Using an Unsafe Implementation of the Hostnameverifier
Allow Multi-Line in Edittext View in Android
How to Access Localhost from a Genymotion Android Emulator
How to Change Package Name in Android Studio
How to Execute a Method by Clicking a Notification
Android Gradle Build Error:(9, 0) Gradle Dsl Method Not Found: 'Compile()'
How to Correctly Pass Unique Extras to a Pending Intent
How to Use a Timertask to Run a Thread
How to Add Crosswalk Webview in My Own Android Library Module