Android 11 - Creating app-specific directory on external storage

Viewed 1604

Recently, I'm trying to migrate my application from SDK-29 to SDK-30. And one thing I concerned the most is scoped storage.

I saw on official document that says "On Android 11 (API level 30) and higher, apps cannot create their own app-specific directory on external storage."

So I tried it out to create my own directory inside external storage and write a new file to it. The code looks like this :

// creating new directory under external storage
val appDir = File(applicationContext.getExternalFilesDir(null), "play")
appDir.mkdir()

// writing new file under my own directory
val newFile = File(appDir.absolutePath, "test.jpg")
val outputStream = FileOutputStream(newFile)
val inputStream = resources.openRawResource(R.drawable.ic_launcher_foreground)
val data = byteArrayOf()
inputStream.read(data)
outputStream.write(data)
inputStream.close()
outputStream.close()

I expected this code will crash but it works. I find the file at the given path. So, I'm a little confused the meaning of that note.

What do Google means with "cannot create their own app-specific directory on external storage"?

2 Answers

They are referring to creating arbitrary directories off of the external storage root (e.g., Environment.getExternalStorageDirectory().

getExternalFilesDir() and similar methods on Context are fine solutions to use instead!

To create app-specific directory on external storage but off root.

private fun createDir(directoryName: String): File? {
        val file = File(applicationContext.getExternalFilesDir("/"),directoryName)
        if (!file?.mkdirs())
            print("Volume : " + "Directory not created")

        return file
    }

Note: For that does not required any storage permission.

To create app-specific directory on external storage in root.

Note: This is only work for Android 11.

Request for All files access from the user:

  1. Declare the MANAGE_EXTERNAL_STORAGE permission in the manifest.
  2. Use the ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent action to direct users to a system settings page where they can enable the following option for your app: Allow access to manage all files.
  3. To determine whether your app has been granted the MANAGE_EXTERNAL_STORAGE permission, call Environment.isExternalStorageManager().

Write code on OnCreate Method:

if (!isExternalStorageReadable()) return

if (!Environment.isExternalStorageManager()) {
            val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
            intent.addCategory("android.intent.category.DEFAULT")
            intent.data = Uri.parse(String.format("package:%s", applicationContext.packageName))
            startActivityForResult(intent, 20)
        } else {
            createDir("ddddd")
        }

Declare two functions outside from OnCreate:

private fun isExternalStorageReadable(): Boolean {
        return Environment.getExternalStorageState() in
                setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
    }

private fun createDir(directoryName: String): File? {
        val file = File(Environment.getExternalStoragePublicDirectory("/"),directoryName)
        if (!file?.mkdirs())
            print("Volume : " + "Directory not created")

        return file
    }
Related