-
Notifications
You must be signed in to change notification settings - Fork 711
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(OS Error: Permission denied, errno = 13) on Android Q #169
Comments
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 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 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. Thank you. |
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 https://github.com/OkunaOrg/okuna-app/blob/release/0.0.55/lib/services/media.dart#L64 this library is used on the I'll try copying the file somewhere else before even trying to read it (?) |
@lifenautjoe that's probably because that Like I said, 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 ☕️ 😄 Thank you! |
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
With the code final tempPath = await _getTempPath();
final String processedImageUuid = _uuid.v4();
String imageExtension = basename(pickedImage.path);
// The image picker gives us the real image, lets copy it into a temp path
pickedImage =
pickedImage.copySync('$tempPath/$processedImageUuid$imageExtension'); I've found this issue on the image picker package which might be related 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. |
Hi, thank you @lifenautjoe 🙌 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. Thank you! |
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. https://commonsware.com/blog/2019/06/07/death-external-storage-end-saga.html And instead, there's scoped external storage with its respective methods : getExternalFilesDir(), getExternalCacheDir(), getExternalMediaDirs(), getExternalCacheDirs(), and getExternalFilesDirs() for storing files instead of the There's a new release of the |
@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
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 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 app I'm working on has 2 use cases that require refactoring for scoped storage compatibility:
I would recommend the following to make file_picker compliant with scoped storage:
|
@ovidiu-anghelina thank you for the huge feedback. I agree with both of your suggestions and I may added those in a near future, just need to have the time. 🙂 |
Is it maybe worth reopening this issue in order to improve its visibility and make it easier to keep track of it? |
Sure. I’m already wiring up some solution for this @ovidiu-anghelina. |
Can confirm. Had the exact same issue and the suggested (temporary) solution worked perfectly. It was really surprising to see that I could pick a file, query about it's existence but exception (Error 13) )was thrown as soon as I tried to actually read the contents of the file. (Android 10. OnePlus 7Pro). BTW: Miguel, thx for great plugin! It rocks! |
One additional comment from my observations: Within your plugin you use the method "Environment.getExternalStorageDirectory()". According to the docs, the method is depcreacted and the path returned by this method is not accessible by apps. In case an image from the Camera folder is selected via file_picker, the internally resolved URI is 'content://media/external/images/media' (via MediaStore.Images.Media.EXTERNAL_CONTENT_URI) and the actually returned path is '/storage/emulated/0/DCIM/Camera/<image_name>.jpg (via context.getContentResolver())'. Using 'File(path).existsSync()' in Flutter for the returned path yields false. From my point of view, this is also related to the scoped storage changes. Apparently the actual file path (even from an externally visible file) is no longer accessible. It is really a big pain now to use files access in Flutter in combination with the scoped storage changes. I hope, you'll be able to update your plugin to help cover these issues. Thanks in advance. |
Does this still happen with V2 embedded support? (file_picker: 1.5.0+2) Thank you. |
@miguelpruivo It still happen on my Android10 device (pixel3) |
@dokinkon ok, might have forgot something that should fix your issue. Please, add the following
to your It should look like this:
And let me know if it worked for you. If so, this should be added onto the Wiki. This happens because Android 10 (Q) or above, require new scoped file system and won't work with legacy unless this flag is added. Anyway, don't forget to Expecting to hear a feedback from you soon. Thanks! |
@miguelpruivo Sorry but how does adding the legacy flag help with closing this issue? As mentioned before, the legacy flag is only a temporary workaround, which will stop working as soon as Android 11 is released, regardless of the target SDK version. Any solution relying on the legacy flag is just a temporary solution. |
@ovideozn no one knows if it will be deprecated on Android 11 or not, sometimes deprecated API's work until later versions. However, a problem at a time. Flutter needs absolute paths to handle Files, there's no way a Dart I've been drafting a solution for it by wrapping it in a custom class that could manage both absolute paths and URI's, but iOS will always behave differently and that's one more thing for the dev to handle a less abstraction. For now, having the flag will solve this issue as it offers a concrete solution or temporary workaround, if you prefer. I'll soon open a new issue regarding this with the motivation for scoped storage handling. |
@miguelpruivo Fair enough. Would the solution I mentioned above not work though?
and
I still think this is better than creating a custom class that wraps everything, as it would either have to extend |
@ovideozn first one will work, however, I'm not sure if some devs will starting open issues because the paths are not real but copies instead — which already happened when URI can't be resolved to a path and a temporary copy has to be made. Second one, will match my purposed solution and that's probably the way to go. But I can agree that having files through a URI only and an optional method, such as Thanks for the input! |
Closing in favor of #234. |
FAILURE: Build failed with an exception.
|
@braysonjohn148 you are using Either change your target to it or remove the flag from your manifest file. |
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
Error Log
Flutter Version details
The text was updated successfully, but these errors were encountered: