Android 开发SD卡存储目录的使用

Android 开发SD卡存储目录的使用

最近两天产品收到用户反馈:“下载目录是否可以选择外置SD卡”,用户就是上帝啊,需要什么我们就要实现什么。但是,在真正的开发过程中遇到了不少问题,记下来做个前车之鉴。

你还在为开发中频繁切换环境打包而烦恼吗?快来试试 Environment Switcher 吧!使用它可以在app运行时一键切换环境,而且还支持其他贴心小功能,有了它妈妈再也不用担心频繁环境切换了。https://github.com/CodeXiaoMai/EnvironmentSwitcher

解决思路

先说一下思路吧,既然是可以选择外置SD卡,那么很显然SD卡是可有可无的,那么就需要去扫描当前是否存在外置SD卡。只有存在SD卡,用户才有选择的余地。下面是扫描存储设备的代码。如果返回的sparseArray.size() > 1,说明存在外置SD卡,且sparseArray.get(1) 得到的就是外置SD卡的路径,否则不存在。

public static SparseArray scanStorage() {
    SparseArray sparseArray = new SparseArray<>();
    final StorageManager storageManager = (StorageManager) HSApplication.getContext().getSystemService(
            Context.STORAGE_SERVICE);
    try {
        String[] paths = (String[]) storageManager.getClass().getMethod("getVolumePaths")
                .invoke(storageManager);
        for (int i = 0; i < paths.length; i++) {
            String status = (String) storageManager.getClass()
                    .getMethod("getVolumeState", String.class).invoke(storageManager, paths[i]);
            if (Environment.MEDIA_MOUNTED.equals(status)) {
                sparseArray.append(i, paths[i]);
            }
        }
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    return sparseArray;
}

Android 4.4 带来的问题

接下来设置下载目录为外置SD卡,我的设备的外置SD卡路径为“/storage/sdcard1” (PS:不同设备的SD卡路径可能是不一样的,跟手机的Rom有关系,因此千万不能写死。)然后我把下载路径设置为“/storage/sdcard1/com.xiaomai.myproject/download”,然后开始下载,问题出现了。

open failed: EACCES (Permission denied)

哦!大概意思就是:文件打开失败,原因也说的很清楚,权限拒绝!该死,忘了加权限。去manifest.xml中声明权限!



可是我发现已经声明存储设备的读写权限了啊,再试一次,还是不行。这是怎么回事,难道我用来假的权限????于是开始Google,经过一番搜索终于找到问题的原因了。

https://source.android.com/devices/storage/index.html

下面是Android官方文档中一段话

Access to external storage is protected by various Android permissions. Starting in Android 1.0, write access is protected with the WRITE_EXTERNAL_STORAGE permission. Starting in Android 4.1, read access is protected with the READ_EXTERNAL_STORAGE permission.

Starting in Android 4.4, the owner, group and modes of files on external storage devices are now synthesized based on directory structure. This enables apps to manage their package-specific directories on external storage without requiring they hold the broad WRITE_EXTERNAL_STORAGE permission. For example, the app with package name com.example.foo can now freely access Android/data/com.example.foo/ on external storage devices with no permissions. These synthesized permissions are accomplished by wrapping raw storage devices in a FUSE daemon.

意思是:

访问外部存储器受到各种Android权限的保护。从Android 1.0开始,写权限受到权限的 WRITE_EXTERNAL_STORAGE保护。从Android 4.1开始,读取权限受到权限READ_EXTERNAL_STORAGE 保护。

从Android 4.4开始,外部存储设备上的文件所有者,组和模式现在基于目录结构进行合成。这使应用程序能够在外部存储上管理其特定于包的目录,而无需拥有广泛 WRITE_EXTERNAL_STORAGE权限。例如,具有包名称“com.example.foo”的应用程序现在可以在没有权限的外部存储设备上对“Android/data/com.example.foo/”进行自由访问 。这些合成的权限是通过在FUSE守护进程中包装原始存储设备来实现的。

这么一大段,说人话就是从Android4.4,应用对外置SD卡的访问只限于“Android/data/[包名]/”,而对于外置SD卡的其他路径,没有权限访问。(内置存储不受影响,可以访问任何目录)

问题原因找到了,那就把下载路径老老实实的改成“Android/data/com.xiaomai.myproject/”吧,我再自己的包名下读写文件总行了吧。可是。。。没错,还是不行,问题还是权限拒绝。原来,Android4.4以后应用程序本身是没有权限在外置SD卡中创建目录的,包括自己的包名。必须用下面的方法

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        getExternalFilesDirs(null);
}

再次运行,这次终于可以了。

你可能感兴趣的:(Android)