Issue
I’m trying to display an image from my phone in my Flutter app and getting following error:
Another exception was thrown: FileSystemException: Cannot open file, path = '/storage/emulated/0/Android/data/com.android.providers.media/albumthumbs/1570277797774' (OS Error: Permission denied, errno = 13)
I don’t understand the Permission denied
part, because I added…
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
…to my android/app/src/mainAndroidManifest.xml
file, and when running the app it shows that it really does have the permissions to read files:
Also the file I’m trying to open exists and seems fine — I can open it with other apps as well:
Here’s my Code:
import 'dart:io';
import 'package:flutter/material.dart';
void main() => runApp(FileOps());
class FileOps extends StatefulWidget {
_FileOpsState createState() => _FileOpsState();
}
class _FileOpsState extends State<FileOps> {
File localFile;
String widgetTitle = 'Show Image';
@override
void initState() {
super.initState();
localfile.then((File _localFile) {
setState(() {
localFile = _localFile;
});
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: widgetTitle,
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text(widgetTitle),
),
body: Column(
children: <Widget>[
Image.file(localFile),
],
),
),
);
}
Future<File> get localfile async {
String imgPath =
'/storage/emulated/0/Android/data/com.android.providers.media/albumthumbs/1570277797774';
return File(imgPath);
}
}
My pubspec.yaml:
name: template_app
description: A template Flutter app for testing and minimal examples
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons:
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
Answers to questions in comments:
- «com.android.providers.media» is not the name of my app, idk what it is — but the image I want to open is there
- My Android Version is 8.0.0, my phone is also running EMUI 8.0.0 (idk what it is exactly, some Huawei stuff)
- I can open the file with the standard app that came with the phone called «Gallery»
Solution
Attention: My answer is a bit old now, I heard that a newer version of
permission_handler
works a bit differently now — so just google how it works nowadays, I guess.
I got it — <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
seemed to only define what permissions were needed, but not actually requesting them
So I manually requested the permissions and then everything worked:
I followed this tutorial.
- I added
permission_handler:
topubspec.yaml
- Changed my
get localfile
get method to:
Future<File> get localfile async {
final PermissionHandler _permissionHandler = PermissionHandler();
var result = await _permissionHandler.requestPermissions([PermissionGroup.storage]);
if (result[PermissionGroup.storage] == PermissionStatus.granted) {
// permission was granted
String imgPath = '/storage/emulated/0/Android/data/com.android.providers.media/albumthumbs/1570277797774';
return File(imgPath);
}
}
Answered By — Cold_Class
OS Error: Permission denied, errno = 13 when reading a File from internal storage #19504
Comments
Hi, I’m trying to read an image file which I uploaded to internal storage through Device File Explorer (on Android emulator) and I ran into a permission error. However, I do not have any problem reading/writing the (image) file I downloaded from the web/localhost.
Note: I am new to mobile development and not sure whether this problem falls under the scope of flutter project, or any other. I suspect that I may be missing a configuration or two on AVD. If this is the case, any pointer to a documentation is really appreciated. Also, if it is more appropriate to post this to SO, I will close this issue and will repost there.
Steps to Reproduce
- Access the file using path_provider API as suggested in the cookbook :
Ensure that the file exist and has read permission on Device File Explorer.
filename: ‘/data/user/0/
/app_flutter/1.jpeg’
permission: -rw-rw-rw-
I also modified the user/group to be similar with other files and granted full permissions.
This is unrelated, but I also tried adding external storage permissions in AndroidManifest.xml.
/app_flutter/1.jpeg’ (OS Error: Permission denied, errno = 13) I/flutter ( 6196): When the exception was thrown, this was the stack: I/flutter ( 6196): #0 _File.open. (dart:io/file_impl.dart:368:9) I/flutter ( 6196): (elided 8 frames from package dart:async) I/flutter ( 6196): I/flutter ( 6196): Path: /data/user/0/
The text was updated successfully, but these errors were encountered:
Источник
(OS Error: Permission denied, errno = 13) on Android Q #169
Comments
Describe the bug
We’ve received and seen several crashes related to permission denied trying to open a file that was picked on Android Q devices.
Looking for solutions, came across this flutter/flutter#31122 (comment)
where it’s claimed that
and might the cause for issues.
Perhaps something to update in regards to how permissions are asked to the user on Android devices?
The strange thing is that users CAN pick the file with the modal, it’s after we programatically try to access it’s contents, we get the exception.
Issue details
- Platform Android
- Q
- IMAGE
- Try to pick an image from your SD card.
Error Log
Flutter Version details
The text was updated successfully, but these errors were encountered:
Hi @lifenautjoe, this is a no-issue and actually what is happening is that the picker is working as it should by allowing users to pick files from wherever they are allowed to (and that’s why it works). What you can’t do tho, is writing files from directories that you don’t have permissions, such as that one ‘/storage/emulated/0/WhatsApp/Media/WhatsApp which is from WhatsApp app.
Even though you are free to pick the files you want and use it to display some data, for example, as a developer, if you are going to write some file, you need to make sure that you write/move the files to your app’s content folder or some cache directory.
Regarding the WRITE_EXTERNAL_STORAGE being deprecated on Q, the plugin doesn’t have it at all. It’s on the wiki because older SDK Android versions may actually need that, but it won’t hurt if you have it as well. 🙂
I’m closing this as it doesn’t represents an issue, but feel free to keep the discussion here if you still have any question.
Hmm we’re not trying to write to the file nor the directory it’s in, we’re actually just trying to read it with pickedImage.readAsBytesSync() as seen here
this library is used on the showImagePicker just before this. It shows a bottom sheet asking to select source, and returns the picked file
I’ll try copying the file somewhere else before even trying to read it (?)
@lifenautjoe that’s probably because that ImageConverter is writing on the same directory from which is picked and it can’t. It’s up to the developer to decide where to write the files and since you are creating a copy (converted), you should place it in a temp directory or your own app content directory.
Like I said, FilePicker gives you the file as it is, this is, from its original directory (whenever possible) but that doesn’t mean that you can actually write on it and you shouldn’t assume that because there are a lot of folders on Android that can be accessible to read but not write.
In iOS you won’t have this issue because the native picker delegate already forces a cache copy to the app’s content.
hah, didn’t think about that one, will give it a try 🙂
You should get a buymeacoffee page Miguel, we’d be happy to send some coffees for your time and help!
No need to thank me @lifenautjoe, always glad to help! 🙂 Just because of you, I’ve created one here ☕️ 😄
Cool! I’ve sent some coffee’s your way ☕️ .
In regards to the issue we’re having, we’ve changed the code to intermediately copy the file to a directory we have permissions with getApplicationDocumentsDirectory() , still seeing the same issues.
I’ve found this issue on the image picker package which might be related
flutter/flutter#41459
People suggest removing some legacy flag as seen here flutter/flutter#41459 (comment) or downgrading to target sdk 28 instead of the latest 29 as a workaround.
If it’s really a bug, perhaps an interesting thread to follow for the fix on this library too.
This is really weird, there must be something missing there, if this was really an issue with the plugin, it should have affected a lot of other users already. 🤔
Could you provide the full steps and details to replicate? I’ll try to make it happen on my machine. Also, does it happens in the emulator or only in some real devices? If you could make it happen on any emulator, please, give me the details/steps of it as well.
Hi Miguel, it’ll happen if you’re on Android Q | 10.
And it will be solved by adding the following on the manifest file.
Reading a bit more, looks like read external storage and write external storage permissions are being deprecated.
And instead, there’s scoped external storage with its respective methods : getExternalFilesDir(), getExternalCacheDir(), getExternalMediaDirs(), getExternalCacheDirs(), and getExternalFilesDirs() for storing files instead of the getTemporaryDirectory and getApplicationDocumentsDir
There’s a new release of the path_provider plugin which chooses between the old and new directories but for some reason its breaking people’s apps as well.
@lifenautjoe yes, I’m familiar with it being deprecated because they want us to always handle files using URI instead of real paths, and in a way, that’s safer and much more easier that just covering all file path possibilities between SDK [16, 29]. However, for Flutter users, that’s not very convenient as they need a lot of times real paths to display content on Flutter’s side, that’s why I’ve been keeping it.
If this is a thing, I don’t bother add that flag to the File Picker package as well by leaving the developer with another thing to not miss. However, I’d like to replicate it here first. Could you make it happen on an emulator and provide me with the full steps?
Thank you once more.
@lifenautjoe ok, after digging a bit more around this, it seems that the issue is indeed with the path_provider package and not this one. So, I’ll break it down for you for better understanding:
- You are picking the files with file_picker which gives you the file path without any issue, right? So, file_picker gets its job done.
- Now, you are trying to make a copy of the original file to a temporary directory, and, because of that, you are using path_provider or any other path utility plugin.
- An exception is thrown due to no writing permissions (remember that with the file_picker we are not writing anything here, right?)
- You added the android:requestLegacyExternalStorage=»true» , which is required to use the SDK scope, and it works because it’s picking the old path (without the social.openbook.app ). That flag is only affecting the path_provider , thus, making it work.
TL;DR: Sometimes is hard to delegate the issue to the right plugin, specially when you are using multiple plugins for one operation. However, like I said, if this was really an issue with file_picker I would have probably found it already when testing on Android Q or other users reported it, because it’s a very common use case.
Again, after further investigation, I’m closing this, but it’s always good to keep on track of this issues. If there’s still anything that you didn’t get, just let me know.
Thank you, I guess I’ll get some coffee now before they cool down! 👀 ☕️
Thank you for the nice breakdown of the issue and help as usual Miguel!
Good rest of the weekend! ☕️ ☀️
Guys, I’m not convinced that you have found any long-term solution to the real problem here.
After doing a lot of reading on what Android 10’s new scoped storage implies, I came to the following conclusions:
- The legacy flag is just a temporary solution. As per this link, «Google states that Scoped Storage will only be required in next year’s major platform release for all apps independent of target SDK». So, in 1 year’s time, that flag will not help, and using a target SDK version lower than 29 will not help either.
- On Android, the paths of files and folders that are not scoped to the app are useless. You cannot read and cannot write to them. Instead, you need to use classes such as the DocumentsContract, which allow you to perform various actions on files by referencing their Uri instead of their path.
- There is nothing wrong with path_provider, as long as you try to comply with Android 10’s scoped storage. It no longer provides paths to folders that are not scoped to the app, because you wouldn’t be able to do anything with them as per the point above. I’ve just tried picking a file using file_picker and displaying it straight away, only to get the permission error mentioned by this issue — path_provider was not used for this, and the app has the storage permission that is still required for accessing files that are not scoped to the app.
- file_picker still works correctly for remote Uris, because it calls getUriFromRemote which copies the file to the scoped cache folder by using the remote file’s Uri, before returning the path of the file within the scoped cache folder, which can safely be used!
The app I’m working on has 2 use cases that require refactoring for scoped storage compatibility:
- Select an external folder to save one or more files to. I previously had the possibility to query Android for all external folders and build my own custom UI for displaying them and allowing the user to select one. This is no longer allowed with scoped storage, and there are only 2 solutions, both involving the Storage Access Framework — using Intent.ACTION_CREATE_DOCUMENT which displays an OS-controlled UI for selecting a folder belonging to a ContentProvider (eg. the Downloads folder, Google Drive, etc.) as well as a file name, which creates a blank file and returns its Uri so that you can write to it, or Intent.ACTION_OPEN_DOCUMENT_TREE which displays an OS-controlled UI for selecting a folder, and returns its Uri that you can use to create child files and folders, etc. I couldn’t find any Flutter plugin that does any of this, so I had to write my own platform channels, and they are working as intended.
- Select one or more files from external storage which are then copied to internal storage before doing other things with them — so far I’ve been using file_picker to select them and path_provider to get the paths of the internal folders to copy those files to. This is currently not possible while using scoped storage, because file_picker always returns file paths.
I would recommend the following to make file_picker compliant with scoped storage:
Источник
(OS Error: Permission denied, errno = 13) on Android Q #169
Comments
Describe the bug
We’ve received and seen several crashes related to permission denied trying to open a file that was picked on Android Q devices.
Looking for solutions, came across this flutter/flutter#31122 (comment)
where it’s claimed that
and might the cause for issues.
Perhaps something to update in regards to how permissions are asked to the user on Android devices?
The strange thing is that users CAN pick the file with the modal, it’s after we programatically try to access it’s contents, we get the exception.
Issue details
- Platform Android
- Q
- IMAGE
- Try to pick an image from your SD card.
Error Log
Flutter Version details
The text was updated successfully, but these errors were encountered:
Hi @lifenautjoe, this is a no-issue and actually what is happening is that the picker is working as it should by allowing users to pick files from wherever they are allowed to (and that’s why it works). What you can’t do tho, is writing files from directories that you don’t have permissions, such as that one ‘/storage/emulated/0/WhatsApp/Media/WhatsApp which is from WhatsApp app.
Even though you are free to pick the files you want and use it to display some data, for example, as a developer, if you are going to write some file, you need to make sure that you write/move the files to your app’s content folder or some cache directory.
Regarding the WRITE_EXTERNAL_STORAGE being deprecated on Q, the plugin doesn’t have it at all. It’s on the wiki because older SDK Android versions may actually need that, but it won’t hurt if you have it as well. 🙂
I’m closing this as it doesn’t represents an issue, but feel free to keep the discussion here if you still have any question.
Hmm we’re not trying to write to the file nor the directory it’s in, we’re actually just trying to read it with pickedImage.readAsBytesSync() as seen here
this library is used on the showImagePicker just before this. It shows a bottom sheet asking to select source, and returns the picked file
I’ll try copying the file somewhere else before even trying to read it (?)
@lifenautjoe that’s probably because that ImageConverter is writing on the same directory from which is picked and it can’t. It’s up to the developer to decide where to write the files and since you are creating a copy (converted), you should place it in a temp directory or your own app content directory.
Like I said, FilePicker gives you the file as it is, this is, from its original directory (whenever possible) but that doesn’t mean that you can actually write on it and you shouldn’t assume that because there are a lot of folders on Android that can be accessible to read but not write.
In iOS you won’t have this issue because the native picker delegate already forces a cache copy to the app’s content.
hah, didn’t think about that one, will give it a try 🙂
You should get a buymeacoffee page Miguel, we’d be happy to send some coffees for your time and help!
No need to thank me @lifenautjoe, always glad to help! 🙂 Just because of you, I’ve created one here ☕️ 😄
Cool! I’ve sent some coffee’s your way ☕️ .
In regards to the issue we’re having, we’ve changed the code to intermediately copy the file to a directory we have permissions with getApplicationDocumentsDirectory() , still seeing the same issues.
I’ve found this issue on the image picker package which might be related
flutter/flutter#41459
People suggest removing some legacy flag as seen here flutter/flutter#41459 (comment) or downgrading to target sdk 28 instead of the latest 29 as a workaround.
If it’s really a bug, perhaps an interesting thread to follow for the fix on this library too.
This is really weird, there must be something missing there, if this was really an issue with the plugin, it should have affected a lot of other users already. 🤔
Could you provide the full steps and details to replicate? I’ll try to make it happen on my machine. Also, does it happens in the emulator or only in some real devices? If you could make it happen on any emulator, please, give me the details/steps of it as well.
Hi Miguel, it’ll happen if you’re on Android Q | 10.
And it will be solved by adding the following on the manifest file.
Reading a bit more, looks like read external storage and write external storage permissions are being deprecated.
And instead, there’s scoped external storage with its respective methods : getExternalFilesDir(), getExternalCacheDir(), getExternalMediaDirs(), getExternalCacheDirs(), and getExternalFilesDirs() for storing files instead of the getTemporaryDirectory and getApplicationDocumentsDir
There’s a new release of the path_provider plugin which chooses between the old and new directories but for some reason its breaking people’s apps as well.
@lifenautjoe yes, I’m familiar with it being deprecated because they want us to always handle files using URI instead of real paths, and in a way, that’s safer and much more easier that just covering all file path possibilities between SDK [16, 29]. However, for Flutter users, that’s not very convenient as they need a lot of times real paths to display content on Flutter’s side, that’s why I’ve been keeping it.
If this is a thing, I don’t bother add that flag to the File Picker package as well by leaving the developer with another thing to not miss. However, I’d like to replicate it here first. Could you make it happen on an emulator and provide me with the full steps?
Thank you once more.
@lifenautjoe ok, after digging a bit more around this, it seems that the issue is indeed with the path_provider package and not this one. So, I’ll break it down for you for better understanding:
- You are picking the files with file_picker which gives you the file path without any issue, right? So, file_picker gets its job done.
- Now, you are trying to make a copy of the original file to a temporary directory, and, because of that, you are using path_provider or any other path utility plugin.
- An exception is thrown due to no writing permissions (remember that with the file_picker we are not writing anything here, right?)
- You added the android:requestLegacyExternalStorage=»true» , which is required to use the SDK scope, and it works because it’s picking the old path (without the social.openbook.app ). That flag is only affecting the path_provider , thus, making it work.
TL;DR: Sometimes is hard to delegate the issue to the right plugin, specially when you are using multiple plugins for one operation. However, like I said, if this was really an issue with file_picker I would have probably found it already when testing on Android Q or other users reported it, because it’s a very common use case.
Again, after further investigation, I’m closing this, but it’s always good to keep on track of this issues. If there’s still anything that you didn’t get, just let me know.
Thank you, I guess I’ll get some coffee now before they cool down! 👀 ☕️
Thank you for the nice breakdown of the issue and help as usual Miguel!
Good rest of the weekend! ☕️ ☀️
Guys, I’m not convinced that you have found any long-term solution to the real problem here.
After doing a lot of reading on what Android 10’s new scoped storage implies, I came to the following conclusions:
- The legacy flag is just a temporary solution. As per this link, «Google states that Scoped Storage will only be required in next year’s major platform release for all apps independent of target SDK». So, in 1 year’s time, that flag will not help, and using a target SDK version lower than 29 will not help either.
- On Android, the paths of files and folders that are not scoped to the app are useless. You cannot read and cannot write to them. Instead, you need to use classes such as the DocumentsContract, which allow you to perform various actions on files by referencing their Uri instead of their path.
- There is nothing wrong with path_provider, as long as you try to comply with Android 10’s scoped storage. It no longer provides paths to folders that are not scoped to the app, because you wouldn’t be able to do anything with them as per the point above. I’ve just tried picking a file using file_picker and displaying it straight away, only to get the permission error mentioned by this issue — path_provider was not used for this, and the app has the storage permission that is still required for accessing files that are not scoped to the app.
- file_picker still works correctly for remote Uris, because it calls getUriFromRemote which copies the file to the scoped cache folder by using the remote file’s Uri, before returning the path of the file within the scoped cache folder, which can safely be used!
The app I’m working on has 2 use cases that require refactoring for scoped storage compatibility:
- Select an external folder to save one or more files to. I previously had the possibility to query Android for all external folders and build my own custom UI for displaying them and allowing the user to select one. This is no longer allowed with scoped storage, and there are only 2 solutions, both involving the Storage Access Framework — using Intent.ACTION_CREATE_DOCUMENT which displays an OS-controlled UI for selecting a folder belonging to a ContentProvider (eg. the Downloads folder, Google Drive, etc.) as well as a file name, which creates a blank file and returns its Uri so that you can write to it, or Intent.ACTION_OPEN_DOCUMENT_TREE which displays an OS-controlled UI for selecting a folder, and returns its Uri that you can use to create child files and folders, etc. I couldn’t find any Flutter plugin that does any of this, so I had to write my own platform channels, and they are working as intended.
- Select one or more files from external storage which are then copied to internal storage before doing other things with them — so far I’ve been using file_picker to select them and path_provider to get the paths of the internal folders to copy those files to. This is currently not possible while using scoped storage, because file_picker always returns file paths.
I would recommend the following to make file_picker compliant with scoped storage:
Источник
How to solve: FileSystemException: Creation failed, path = ‘Directory: » (OS Error: Read-only file system, errno = 30)
Question
Asked by tr1via on June 11, 2022 (source).
I am receiving an error as Unhandled Exception: FileSystemException: Creation failed, path = 'Directory: '' (OS Error: Read-only file system, errno = 30)
when I am trying to save a xlsx file.
Code:
class ExportPasswords {
static exportUserEntries(List entries) async {
final _psd = PasswordDecrypter();
final _secureStorage = FlutterSecureStorage();
//creating the xlsx
var excel = Excel.createExcel();
var fileBytes = excel.save();
Sheet sheetObject = excel['pssswd_export'];
CellStyle cellStyle = CellStyle(
backgroundColorHex: "#1AFF1A",
fontFamily: getFontFamily(FontFamily.Calibri));
cellStyle.underline = Underline.Single;
for (var entry in entries) {
final _username = entry['data']['username'];
final _name = entry['data']['name'];
final _url = entry['data']['url'];
final _hashedPassword = entry['data']['password'];
final _randForKeyToStore = entry['data']['randForKeyToStore'];
final _randForIV = entry['data']['randForIV'];
final _masterPassword = await _secureStorage.read(key: 'masterPassword');
final _decryptedEntryPassword = await _psd.getDecryptedPassword(
_hashedPassword, _randForKeyToStore, _randForIV, _masterPassword);
sheetObject.appendRow([_name, _username, _decryptedEntryPassword, _url]);
}
PermissionStatus permissionResult =
await SimplePermissions.requestPermission(
Permission.WriteExternalStorage);
if (permissionResult == PermissionStatus.authorized) {
Directory directory = await getApplicationDocumentsDirectory();
// print(directory);
new Directory(directory.path + '/').create(recursive: true).then((dir) {
print(dir);
File(join('$dir/pssswd_export'))
..createSync(recursive: true)
..writeAsBytesSync(fileBytes!);
});
}
}
}
I have given the permission of WRITE_EXTERNAL_STORAGE.
I/SimplePermission( 7685): Requesting permission : android.permission.WRITE_EXTERNAL_STORAGE
I/SimplePermission( 7685): Requesting permission status : 3
In the error it is displayed as Directory : ''
, but when I am printing the directory value it is showing the path
I/flutter ( 7685): Directory: '/data/user/0/com.palsoham.pssswd.pssswd/app_flutter/'
Answer
Question answered by Shahzad U (source).
Please try changing your path in File
function from '$dir/pssswd_export'
to dir.path + /pssswd_export'
.
- Source: Stackoverflow.com