How to grant read/write access to external SD card on different api

Published on Author Code Father

In my application I need to store lots of images on device storage. Such images tend to fulfill the device storage and I want to allow users to be able to choose external SD card as destination folder.

I read everywhere that Android doesn’t allow users to write to external SD card, by SD card I mean the external and mountable SD card and not the external storage, but file manager applications manage to write to External SD on all Android versions.

What is the better way to grant read/write access to external SD card on different api levels (Pre-KitKat, KitKat, Lollipop+)?

There are two methods to achieve this:

METHOD 1:

I have been using this method for years on many device version with no issue. Credit is due to the original source, as it was not me who wrote it.

It will return all mounted media (including Real SD Cards) in a list of strings directory locations. With the list you can then ask the user where to save, etc.

You can call it with the following:

 HashSet<String> extDirs = getStorageDirectories();

Method:

/**
 * Returns all the possible SDCard directories
 */
public static HashSet<String> getStorageDirectories() {
    final HashSet<String> out = new HashSet<String>();
    String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
    String s = "";
    try {
        final Process process = new ProcessBuilder().command("mount")
                .redirectErrorStream(true).start();
        process.waitFor();
        final InputStream is = process.getInputStream();
        final byte[] buffer = new byte[1024];
        while (is.read(buffer) != -1) {
            s = s + new String(buffer);
        }
        is.close();
    } catch (final Exception e) {
        e.printStackTrace();
    }

    // parse output
    final String[] lines = s.split("\n");
    for (String line : lines) {
        if (!line.toLowerCase().contains("asec")) {
            if (line.matches(reg)) {
                String[] parts = line.split(" ");
                for (String part : parts) {
                    if (part.startsWith("/"))
                        if (!part.toLowerCase().contains("vold"))
                            out.add(part);
                }
            }
        }
    }
    return out;
}

METHOD 2:

Use the v4 support library

import android.support.v4.content.ContextCompat;

Just call the following to get a list of File locations of storage.

 File[] list = ContextCompat.getExternalFilesDirs(myContext, null);

The locations differ in usage however though.

Returns absolute paths to application-specific directories on all external storage devices where the application can place persistent files it owns. These files are internal to the application, and not typically visible to the user as media.

External storage devices returned here are considered a permanent part of the device, including both emulated external storage and physical media slots, such as SD cards in a battery compartment. The returned paths do not include transient devices, such as USB flash drives.

An application may store data on any or all of the returned devices. For example, an app may choose to store large files on the device with the most available space

More Info on ContextCompat

They are like app specific files. Hidden from other apps.

Comments

comments