Android 文件管理系列 (01) – 获取挂载点和权限

上一章已经大概了解了 Android 存储挂载点的问题,这一张来讲讲如何获取常见文件管理器中可以看到的存储位置,以及访问这些存储位置的权限。

系列

Android 文件管理系列 (00) – 存储系统概述
Android 文件管理系列 (01) – 获取挂载点和权限 [当前]
Android 文件管理系列 (02) – FileProvider
Android 文件管理系列 (03) – 监控文件变化

获取挂载点

过去有三种获取方法:

  1. getExternalStorageDirectory(), 不同厂商不同型号之间这个函数实现的并不统一,有可能是内部存储,也可能是外部存储,返回结果并不能作为依据,并且不能获得其他设备的挂载点;
  2. 通过两个环境变量,获得内部和外部存储,在较新的版本上表示外部存储的环境变量已经被移除;
  3. 分析 /proc/mount, 由于挂载方式的变化和 FUSE 的存在,这个方式复杂度和难度比较高。

现在比较好的办法是通过反射调用 StorageManager 中的 getVolumePaths 方法获得存储设备列表,不仅能获取内部存储和外部存储,还能够得到OTG等设备的挂载信息:

    private static List<String> getStorageDirectoriesList(Context context) {
        StorageManager storageManager = (StorageManager)context
                .getSystemService(context.STORAGE_SERVICE);
        Method methodGetPaths;
        List<String> directories = new ArrayList<>();
        try {
            methodGetPaths = storageManager.getClass()
                    .getMethod("getVolumePaths");
            String[] paths = (String[]) methodGetPaths.invoke(storageManager);
            for(String path : paths) {
                File file = new File(path);
                if(file.exists() && file.isDirectory() && file.canRead())
                    directories.add(path);
            }
            return directories;
        } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            return Collections.emptyList();
        }
    }

文件系统的权限

Android 的碎片化问题同样体现在文件系统的权限上:
* API 14 – 15 (Ice Cream Sandwich): 只需要在 AndroidManifest.xml 中声明 WRITE_EXTERNAL_STORAGE 权限;
* API 16 – 18 (Jelly Bean): 需要在 AndroidManifest.xml 中声明 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE;
* API 19 (KitKat): 对于 Internal Storage 需要在 AndroidManifest.xml 中声明 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE, 如果仅仅读写由 getExternalFilesDir(String)getExternalCacheDir() 获得的目录则不需要。这个版本完全禁止了写入 SD 卡,只能通过一些取巧的途径 (比如在目标目录写入空音乐或图片,将其视为媒体文件夹处理,这一部分可参考 Amaze FileManager 的实现) 来写入 SD 卡。
* API 20 (Lollipop): 对于内部存储同 API 19, 对于外部存储引入了 Storage Access Framework, 用于读写外置 SD 卡,除了需要 WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE, 还需要取得用户授权的 Uri 并通过 SAF 提供的 DocumentFile 操作文件;
* API 21 (MarshMallow): 在 Lollipop 的基础上引入了运行时权限,无论 Internal Storage 还是 External Storage, 都需要运行时申请。

另外,处于应用数据文件夹内的文件不能被其他应用直接使用,需要使用 FileProvider 将其提供给其他用户。

发表评论

电子邮件地址不会被公开。 必填项已用*标注