33

We have an app that uses external storage to store some temporary files: images, binary data. The code for that has been working for a few years without big changes until recently. On Android Q it doesn't work:

File f = new File(Environment.getExternalStorageDirectory().toString() + File.separator + MainActivity.APP_DIR)
f.mkdirs();
// do sth with f

The mkdirs now returns just false.

Required permission is provided in the manifest:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

The code works fine on previous versions of Android. Is there some system level change to this type of access? If so, what is the workaround?

khusrav
  • 5,267
  • 5
  • 27
  • 38

3 Answers3

63

There was huge privacy change in android Q by introducing Scoped Storage.

Since Q beta 4 it's possible to opt-out of that feature by:

  • targeting API 28 (or lower)
  • using requestLegacyExternalStorage manifest attribute (while targetting API 29):

<manifest ... >
  <!-- This attribute is "false" by default on apps targeting Android Q. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>

edit: as mentioned in other answer this does not work if app is targeting API 30 - Android 11 devices will ignore legacy storage flag.

edit 2: heads up for anyone planning to publish on play store - soon usage of this flag will be restricted (new and updated apps won't be accepted) unless its required for core functionality (e.g. file manager)

Pawel
  • 15,548
  • 3
  • 36
  • 36
  • Isn't he asking for Android Pie? But, I think you're addressing Android Q related problems. – exploitr Jun 30 '19 at 11:10
  • @Toaster you're right, it was late at night when I replied. For some bizzare reason I thought 9 is Q already. – Pawel Jun 30 '19 at 11:34
  • Haha, that's fine. Just update the answer in your free-time. – exploitr Jun 30 '19 at 11:37
  • @Pawel Looks like not only you were sleepy, I didn't pay attention - the image I used to check was indeed of Q (9+ emulator). Checked on 9 - all on fine, so re-phrase the question and accept – khusrav Jun 30 '19 at 19:37
  • @khusrav that's what was on my mind, didn't see a reason why that code wouldn't work on P but knew there'd be an issue on Q. – Pawel Jun 30 '19 at 19:40
  • @khusrav Well, that was a disaster. :-D – exploitr Jul 03 '19 at 18:20
  • I've updated my sdk version to 29 and added that attribute but I'm still facing the same issue. Is there anything else that i'm missing? my android version is '10QP1A' – Zeynab Rostami Mar 07 '20 at 10:55
  • Yes it works for me i have just added `android:requestLegacyExternalStorage="true"` in API 29 or higher – Prototype Sep 20 '20 at 09:27
11

UPDATE: Since Android 11 scoped storage is enforced. 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.


In API level 29 direct access to shared/external storage devices is deprecated. When an app targets Build.VERSION_CODES.Q, the path returned from getExternalStorageDirectory() method is no longer directly accessible to apps. Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.

It's a best practice to use scoped storage unless your app needs access to a file that doesn't reside in the app-specific directory.

Those who face the issue with managing files in Android-Q may read through this article to know further.

Anoop M Maddasseri
  • 10,213
  • 3
  • 52
  • 73
3

In the new Android update API 30 you can only write in your app-specific files

 File directory = new File(context.getFilesDir(), "YOUR_DIR");
 directory.mkdirs();

or in the external storage of your app Android/data

File directory = new File(myContext.getExternalFilesDir("FolderName"),"YOUR_DIR");

UPDATE

this answer provided another solution https://stackoverflow.com/a/65744517/8195076

UPDATE

another way is to grant this permission in manifest

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

like this answer https://stackoverflow.com/a/66968986/8195076

Wowo Ot
  • 1,362
  • 13
  • 21