外部存储、WRITE_EXTERNAL_STORAGE权限与maxSdkVersion属性的使用

概述

最近在项目中发现READ_EXTERNAL_STORAGE配置了maxSdkVersion 属性,于是决定对maxSdkVersion属性研究一番。研究过程中涉及好几个知识点:文件存储结构、外部存储权限、动态权限申请等。

1.存储空间概述

Android 的文件存储分为:Internal file storage 和 External file storage。

  • 内部文件存储:存储应用的私有文件,其他应用无法自然访问的数据(除非拥有 Root 访问权限)。
  • 外部文件存储:在共享外部文件系统中存储文件,此方式通常为您要与其他应用共享用户文件数据,如照片等。
内部存储
  • 内部存储存的是应用私有文件,其他应用(和用户)不能访问这些文件,除非拥有 Root 访问权限。
  • 系统会为每个应用提供私有目录,您可以在该目录中整理应用所需的任何文件。
  • 当用户卸载应用时,内部存储中的私有文件也将随之移除。
  • 如果您希望在卸载应用后仍能访问这些文件或照片,您可以改用 MediaStore 将这些类型的文件保存至合适的媒体集合中,或者存储于外部存储里的“公共共享目录”
外部存储
  • 每个 Android 设备都支持共享的“外部存储”空间,“外部存储”从名字上可能会被理解为外置的SD卡,其实并不是,有的设备没有SD卡插槽,但系统会从内部存储分配出一部分存储空间来用作外部存储
  • 所以说外部存储包括了分出来的虚拟外部存储SD卡存储
  • 当存在多个存储位置时,会有主要外部存储和其他外部存储之分。
  • 对于外部存储,用户并非始终都能访问该外部空间,用户有可能会拔出SD卡,因此,在尝试访问应用外部存储中的文件时,应检查外部存储目录及您尝试访问的文件是否可用。

如果您希望与其他应用共享文件,可以使用 FileProvider。

外部存储空间里又有两种区分:

  • 公共文件目录:如 /storage/emulated/0/Pictures
    如果你的用户数据可供其他应用访问,系统提供了一系列的标准公共文件目录,如Download、Pictures、Music、Movies等目录,位于外部存储的根目录下。
    这些数据的存储不会随着您应用的卸载而删除。
  • 私有文件目录:如 /storage/emulated/0/Android/data/应用包名/files
    由于内部存储的空间资源往往是比较紧缺的,如果想要存储更多的数据,可将文件保存至外部存储中的“应用特定目录”中。
    当用户卸载应用时,系统也会删除该目录,所以叫应用在外部存储中的私有文件目录。但这些文件仍是全局可读取文件,只不过其他应用无法共享保存该文件的位置。

外部存储空间中的文件并非始终都能访问到,因其存储于外部存储空间,有可能是从内部存储中分配出来的虚拟外部存储,有可能是SD卡存储。还有可能会移除 SD卡,因此在访问之前,您应检查外部存储目录及您尝试访问的文件是否可用。

注意:如果用户移除了外部存储设备(例如 SD 卡)或断开其连接,则存储在外部存储上的文件可能会变得不可用。如果您的应用功能非常依赖于这些文件,则应将文件写入“内部存储”。

外部存储,在多个存储位置之间的选择

市场上有些设备将内部存储分出虚拟外部存储,同时还会提供 SD 卡插槽。这意味着这些设备会有两个不同的外部存储目录,因此在将“私有”文件写入外部存储时,需要选择使用哪个目录。

从 Android 4.4 API 19 开始,可以通过调用getExternalFilesDirs()来访问这两个位置,它返回一个File数组,包含了每个存储位置的条目。数组中的第一个条目被视为主要外部存储,除非该位置已满或不可用,否则应该一律使用该位置。
如果应用支持 API 18 及更低版本,则应使用静态方法 ContextCompat.getExternalFilesDirs(),它始终会返回一个 File 数组,但如果设备搭载的是 API 18 及更低版本,数组中将仅包含主要外部存储的条目。(如果有第二个存储位置,您将无法在 Android 4.3 及更低版本上访问它。)

2.请求外部存储权限

Android 包含以下访问外部存储中的文件的权限:

READ_EXTERNAL_STORAGE
允许应用访问外部存储设备中的文件
WRITE_EXTERNAL_STORAGE
允许应用在外部存储设备中写入和修改文件。API 19 开始,拥有此权限的应用也会自动获得 READ_EXTERNAL_STORAGE 权限。

从 Android 4.4(API 19)开始,在“应用特定的目录(“私有文件目录”)”中读取或写入文件不再需要任何与存储相关的权限。

因此,如果您的应用支持 Android 4.3(API 18)及更低版本,并且您只想访问应用特定的目录(“私有文件目录”),则可以添加 maxSdkVersion 属性,声明仅在较低版本的 Android 上请求权限:(这里可能有坑,会和Android6.0权限有点小问题,慎用。)


    

具体说明:

  • 如果应用需要访问其他应用的文件或者“公共文件目录”,则需要在清单中配置存储权限,且不能添加 maxSdkVersion 属性。
  • 如果应用只需要访问应用特定的目录即私有文件目录:(这种情况实际中很少)
    - 如果应用仅支持 API 19 及之后版本,则不需要在清单中配置存储权限。
    - 如果应用还支持 API 18 及更低版本,则需要在清单中配置存储权限,且可以添加 maxSdkVersion 属性,声明仅在较低版本的 Android 上请求权限。
    - maxSdkVersion 这里可能有坑,会和Android6.0权限有点小问题,慎用。

最后关于权限的结论:
"存储权限最好还是都在清单中配置上,而且maxSdkVersion属性要慎用。"

可能有人会问,我这篇文章说了这么多,好像是都在说废话,还得出了一个废话结论,其实我是带着下面的疑问和设想来研究本文的。
以下几点是我对外部存储权限的理解,本文旨在理清其中一些隐藏细节。

1.只有在清单文件中配置了的权限,在应用的权限管理中才会出现。而且6.0动态权限开始,用户还可以手动修改权限,这种情况如果用户手动关闭了权限,则有可能导致应用无法“正常”的运行。
2.如果应用仅访问外部存储中的“私有文件目录”,那么我们是不是可以不用在清单文件中配置权限,或者使用maxSdkVersion属性限定只在低版本上配置权限?那么在应用的权限管理中就不会出现存储权限也不会有存储权限的开关,因而用户就无法关闭该权限,应用不会因为用户主动关闭权限而无法正常运行。
3.如果应用还要访问其他应用文件或者公共文件目录,那就必须乖乖在清单文件中配置权限吧。

上面是我的理解,欢迎大家指出我理解不对的地方~

参考链接:
https://developer.android.google.cn/guide/topics/data/data-storage
https://developer.android.google.cn/training/data-storage/files/external

你可能感兴趣的:(外部存储、WRITE_EXTERNAL_STORAGE权限与maxSdkVersion属性的使用)