Skip to content

Instantly share code, notes, and snippets.

@PauloLuan
Last active October 31, 2022 07:02
Show Gist options
  • Select an option

  • Save PauloLuan/4bcecc086095bce28e22 to your computer and use it in GitHub Desktop.

Select an option

Save PauloLuan/4bcecc086095bce28e22 to your computer and use it in GitHub Desktop.
how to get the external sd card path on android.
public static String getExternalSdCardPath() {
String path = null;
File sdCardFile = null;
List<String> sdCardPossiblePath = Arrays.asList("external_sd", "ext_sd", "external", "extSdCard");
for (String sdPath : sdCardPossiblePath) {
File file = new File("/mnt/", sdPath);
if (file.isDirectory() && file.canWrite()) {
path = file.getAbsolutePath();
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date());
File testWritable = new File(path, "test_" + timeStamp);
if (testWritable.mkdirs()) {
testWritable.delete();
}
else {
path = null;
}
}
}
if (path != null) {
sdCardFile = new File(path);
}
else {
sdCardFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
}
return sdCardFile.getAbsolutePath();
}
@miszmaniac

Copy link
Copy Markdown

Kotlin version:

private fun getExternalCardDirectory(): File? {
        val storageManager = getSystemService(Context.STORAGE_SERVICE)
        try {
            val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
            val getVolumeList = storageManager.javaClass.getMethod("getVolumeList")
            val getPath = storageVolumeClazz.getMethod("getPath")
            val isRemovable = storageVolumeClazz.getMethod("isRemovable")
            val result = getVolumeList.invoke(storageManager) as Array<StorageVolume>
            result.forEach {
                if (isRemovable.invoke(it) as Boolean) {
                    return File(getPath.invoke(it) as String)
                }
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return null
    }

@feelgoodincorp

Copy link
Copy Markdown

lovelyelfpop's version works great, thank you!

@djkskqyr3

Copy link
Copy Markdown

@lovelyelfpop Great, it works

@zgrujic

zgrujic commented Sep 26, 2019

Copy link
Copy Markdown

@lovelyelfpop God bless you, seems this is the only working solution on internet currently. Thanks a bunch!!

@bhanubais

Copy link
Copy Markdown

In Samsung external card location has changed as:
/storage/0000-0000/

@JoeCodeswell

Copy link
Copy Markdown

Thanks, @lovelyelfpop this worked on my Samsung SM-T320 running Android version 4.4.2.

  1. I followed get Context in non-Activity class [duplicate] to get the context into my Util class from the MainActivity.
  2. Here's some things I imported. there might have been a couple more.
import android.os.storage.StorageManager;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

Thanks again. This worked like a champ

ghost commented Nov 10, 2020

Copy link
Copy Markdown

@lovelyelfpop Thank you, very much

@Alkwin

Alkwin commented Feb 14, 2022

Copy link
Copy Markdown

Hi,

After Android Q, the method getPath cannot be called through reflection.

For me, the following code works. Tested on around 6-7 devices, ranging from Android 4.3 up to Android 12.

private fun getExternalCardDirectory(): String {
        val storageManager = context.getSystemService(Context.STORAGE_SERVICE)
        try {
            val storageVolumeClassReflection = Class.forName("android.os.storage.StorageVolume")
            val getVolumeList = storageManager.javaClass.getMethod("getVolumeList")
            val getPath = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                storageVolumeClassReflection.getMethod("getDirectory")
            } else {
                storageVolumeClassReflection.getMethod("getPath")
            }
            val isRemovable = storageVolumeClassReflection.getMethod("isRemovable")
            val result = getVolumeList.invoke(storageManager) as Array<StorageVolume>
            result.forEach {
                if (isRemovable.invoke(it) as Boolean) {
                    return when(val invokeResult = getPath.invoke(it)) {
                        is File -> invokeResult.absolutePath

                        is String -> invokeResult

                        else -> DEFAULT_VALUE.also {
                            log.debug { "Reflection unsupported type; Invoke result: $invokeResult" }
                        }
                    }
                }
            }
        } catch (e: Throwable) {
            log.debug { "Could not get SD card path; Exception: $e" }
        }
        return DEFAULT_VALUE
    }

With DEFAULT_VALUE = "N/A"
Credit @lovelyelfpop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment