一、Android文件系统
Android文件系统分为内部存储(internal storage)和外部存储(external storage)
1.1用一个表格来直观对比一下两者
1.2应用的私有路径
应用在安装之后,系统会自动在内部存储和外部存储,分别建立应用的私有存储区域。
内部存储:data/user/0/packageName
外部存储:storage/emulated/0/android/data/packageName
当应用卸载或者清除数据后,该区域文件会被删除。
1.3内外部存储图解
二、了解分区存储
Android10版本中,Google推出分区存储(scoped storage)的功能。
背景:
分区存储功能是针对内置的外部存储来说的,很多应用喜欢在外部存储的根目录创建自己的文件夹,比如:storage/emulated/0/***
这样做的好处:
1.当不断向该目录存储时,应用自己的容量不会变化;
2.当应用卸载时,该目录下文件不会被删除,可用于保存一些可持久性的文件。
但是也有坏处:
1.对用户来说,会有很多垃圾文件存在于手机中;
2.只要获取到Read和Write权限,就可以随意访问外部存储的任何目录,信息安全存在隐患。
分区存储:
每个应用向自己的私有目录读写文件,不需要读写权限。私有文件目录具体路径:storage/emulated/0/android/data/packageName/,获取方法:Context#getExternalFilesDir()
应用即使获取了读写权限,也无法访问其他应用的私有目录。
当应用需要获取媒体文件时,通过 MediaStore API 向公共存储目录DCIM、Music或者Movie获取。同样写媒体文件也是如此。并且读写自己的文件时不需要申请权限。只有读其他应用的媒体文件时才会需要申请READ_EXTERNAL_STORAGE
权限。
(更新:Android11为目标平台时,可以使用文件直接路径去访问媒体,这是在Android10上没有的,应用的性能会略有下降,还是推荐使用MediaStore
)
当应用需要获取其他非媒体文件时,比如doc、pdf文件,需要使用 系统的文件选择器SAF 来进行访问。
所以WRITE_EXTERNAL_STORAGE
权限,在未来的Android11版本里,会被废弃。(写文件不需要权限,只能在私有目录和公共目录写文件)
三、分区存储适配
旧版存储位置迁移
除了应用的私有目录和公共目录,其他位置都称为 旧版存储位置,我们需要将旧版存储位置的数据迁移到能兼容分区存储的位置。
如果以Android 11为目标平台的应用,需要在manifest清单中标记preserveLegacyExternalStorage 为true
,这样在Android11的机器上覆盖安装时,才能访问旧版存储位置,卸载重装会失效。
如果以Android10为目标平台,需要在manifest清单中标记requestLegacyExternalStorage 为true
,这样在Android10机器上覆盖安装才能访问旧版存储位置,卸载重装会失效。在Android11的机器上两种安装方式都会失效,需要加上preserveLegacyExternalStorage = true,且覆盖安装才能访问旧版存储位置。卸载重装会失效。
如果以Android 9及以下为目标平台时,就能正常的进行文件移动。将应用在外部存储器根目录的保存的数据中,如果能接受随应用的卸载而删除的文件,迁移至**storage/emulated/0/android/data/packageName/**目录下。需要和其他应用共享的媒体文件,迁移至媒体存储位置。
正确使用读写API
只在外部存储的应用私有目录下,用直接路径读写文件
访问或者共享媒体文件,使用MediaStore
在公共目录下读写文件
访问或者共享非媒体文件,使用系统的文件选择器SAF在公共目录Download下读写文件
【精彩阅读】
Android/Linux Root分析与研究
Android APP抓不到包的解决思路
Android获取Root权限的通用方法
Android逆向之Magisk+Edxposed刷入教程(内附资源)
Gradle Plugin+Transform+ASM Hook并替换隐私方法调用(彻底解决隐私不合规问题)