requestLegacyExternalStorage is not working in Android 11 - API 30
But now when I targetSdkVersion 30, this no longer seems to work
That is correct. Android 11 (API 30+) requestLegacyExternalStorage=true
does nothing and you can no longer "opt-out". It was available in Android 10 to give developers a transition/grace period to be able to migrate to the scoped storage model.
Option 1: Migrate data in your app whilst still targeting API 29, then once you're migrated data is compatible with scoped storage you should be able to release an update targetting API 30 - https://developer.android.com/training/data-storage/use-cases
This can come with its own problems if users skip this version and updates directly from a previous version to the latest and you're stuck with un-migrated data you can't access.
Option 2: It seems that Google sees this obvious caveat and has included a preserveLegacyExternalStorage=true
option when targetting API 30 to allow you to migrate data. https://developer.android.com/reference/android/R.attr#preserveLegacyExternalStorage
Going forward you can reference this table for deciding what storage "framework" to use based on the use-case: https://developer.android.com/training/data-storage
There is a potential that some apps simply won't be able to successfully migrate, based on how they interacted with the File
API as Google's solution will not encompass all current use-cases and there might not be a migration path.
For instance, I released an app a couple of years ago that allowed users to update album artwork using MediaStore
and ContentResolver
to update the data for the album artwork image - this was stored in shared storage. Having looked at the Android 10+ AOSP MediaProvider
source code it seems that apps that used to use MediaStore
to update album artwork to point to a data file no longer works, simply because the MediaProvider
internally creates its own artwork in a hidden .thumbnails
folder looking directly at the mp3's and using a MediaExtractor
, and never references the ContentValues
that were inserted to reference the artwork. So even though you can update the artwork yourself, query the MediaStore
for it and see it, other apps have to use ContentResolver#loadThumbnail
in API 29+ that does not reference your updated values and either creates an artwork lazily, or picks the already generated file in the .thumbnails
folder. Obviously, none of this is documented, and I got a massive backlash to my app with negative reviews, yet these changes were breaking changes and completely out of my control and took me looking through AOSP source code to find that Android had fundamentally changed behaviour.
(This wasn't a rant, but an example of how these changes offered no migration path because of fundamental undocumented behaviour to AOSP).
WRITE_EXTERNAL_STORAGE when targeting Android 10
A workaround is to actually ignore the warning, as it is just informational and therefore harmless. By setting maxSdkVersion to 28 no need to worry anymore.
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"
tools:ignore="ScopedStorage" />
Note that using the android:requestLegacyExternalStorage flag as stated in other answers is not a solution, is just a temporary patch which will no longer work at all in Android 11 (API 30), and future versions
UPDATE, to clarify the doubts and confusions shown by some developers in the comments:
If using the requestLegacyExternalStorage flag in Android 10 (API 29) then request the WRITE_EXTERNAL_STORAGE permission as usual.
The flag requestLegacyExternalStorage does nothing in Android 11 (API 30), it is completely ignored, and there is not workaround for it.
WRITE_EXTERNAL_STORAGE does not give any privileges in Android 11 (API 30), it does nothing at all, therefore in API 11 you need to set the maxSdkVersion to 29.
If in Android 10 (API 29) you are also not using requestLegacyExternalStorage then set maxSdkVersion to 28 instead of 29.
Starting in Android 11 (API 30), the older File API can again be used but "only" when accessing the public "shared storage" folders (DCIM, Music, etc.), or your app "private" directory. For other locations the DocumentFile API is required.
Consider that the File API is now much slower in Android 11 (API 30), because has been refactored becoming essentially a wrapper. This is to enforce its usage just to the allowed locations. So, is no longer a fast system file API, is just a wrapper that internally delegates the work to the MediaStore. When using the File API in Android 11 or above you should consider the performance penalty hit, as according to the Android team it will be 2 to 3 times slower than if accessing directly the MediaStore.
Related Topics
Asynctask.Executeonexecutor() Before API Level 11
Android: Dex Cannot Parse Version 52 Byte Code
Reading a JSON Array in Android
String.Equals() with Multiple Conditions (And One Action on Result)
Android Timer Updating a Textview (Ui)
Best Way to Implement View.Onclicklistener in Android
How to Save Bitmap to Android Gallery
Java Doesn't Work with Regex \S, Says: Invalid Escape Sequence
Android: Email Client Receiver Email Id Empty in Android-Parse
Sort Data to Recyclerview Based on Latest Date from Firebase
Stream Live Android Audio to Server
Decompile an APK, Modify It and Then Recompile It
How to Add Programmatically a Custom Account in Android
How to Pass a Uri to an Intent
Is It Possibile to Set Hint Spinner in Android
How to Hide a View Programmatically
Bitmapfactory.Decodestream Returning Null When Options Are Set