This blog explains how to tackle EACCES error in Android Q and above.
Developing for Android is an amazing experience for every mobile developer because of the ultra-active developer community improving it day by day and bringing new features. Almost every year we see a new android version released by Google through their event Google I/O. The most recently released stable version of android is the Android 10(Q) or API Level 29 as many devs call it.
While switching code to make it suited for the Android 10 running devices, one common error developers come across is Permission denied (EACCES). This most commonly happens when the user needs permission to do some task (For example: Storage Access, Media/Image Access) which wasn’t the case in previous Android versions.
When it happened
It happened with me when I was contributing to a project in Android which could be able to determine if a plant has any disease or not, known as CropAI. An Image upload was required and I stumbled on this issue. I tried to tackle it as a bug fix in the pull request.
According to the Official Android Documentation:
On earlier versions of Android, apps needed to declare these permissions to access any file outside the app-specific directories on external storage. More recent versions of Android rely more on a file’s purpose than its location for determining an app’s ability to access that file. This purpose-based storage model improves user privacy because apps are given access only to the areas of the device’s file system that they actually use.
Taking my use-case of uploading an image from the media gallery, we shall figure out how to solve the above problem. There are two ways to figure out a solution:
Switch the flag requestLegacyExternalStorage to true in the manifest file of your android project.
Here’s a word from the Official Documentation:
To give developers additional time for testing, apps that target Android 10 (API level 29) can still request the requestLegacyExternalStorage attribute. This flag allows apps to temporarily opt out of the changes associated with scoped storage, such as granting access to different directories and different types of media files. After you update your app to target Android 11, the system ignores the requestLegacyExternalStorage flag.
<?xml ver ...>
<manifest xmlns:andro ...>
android:requestLegacyExternalStorage = "true">
The idea behind this way is to make a copy of the file that the user picks in the media gallery and add it to your application cache directory, and then further use/process it as we would have in normal scenario.
- So, the first step is to open the file using a ParcelFileDescriptor object and create an InputStream from the choosen original file.
- Now, give a name to your copied file and create an empty copy of the original file.
- Create an OutputStream for the newly created file and then finally transfer the data from the original file to the newly created empty file.
- Don’t forget to close the input and output streams. Get the file accessible in the form of a Uri.
To get the path of the copied file, simply use the getPath method of the Uri class:
image_path = copyImage.getPath();
That’s it, we are done! Hope you liked it.
Peace out! 🙌