Android 分区存储

1 手机存储

手机存储:

  • Android 4.4 之前的版本:设备的机身存储就是内部存储(internal storage),为了弥补内部存储空间的不足而插入外置的 SD 卡,被称为外部存储(external storage);
  • Android 4.4 及以上版本:很多中高端机器将自身的机身扩展到了 8G 以上,将机身存储分为内部存储和外部存储两部分。当然,依然可以插入 SD 卡来扩充外部存储空间;

2 私有存储和共享存储

对于 Android 应用而言,将应用的存储分为私有存储和共享存储。私有存储是每个应用专属的存储空间,而共享存储包含用户手动创建或共享给其他应用的文件,如相册、下载等:

  • 私有存储/目录:
    • 每个应用都有自己的私有目录,应用间无法访问;
    • 私有存储空间的数据,在应用卸载后删除;
  • 共享存储/目录:
    • 除了私有存储空间外,其他的都被认定为共享存储,比如 Downloads、Documents、Pictures、DCIM、Movies、Music 等;
    • 共享存储空间的数据管理混乱,应用能够随意的访问共享空间的数据,会导致隐私数据泄漏;
    • 共享存储空间中的文件不会随着 APP 的卸载而被删除;

在 Android 10 之前,只要应用程序获得了READ_EXTERNAL_STORAGE 和WRITE_EXTERNAL_STORAGE 的权限,就可以随意的访问和修改共享存储中的文件。从 Android 10 开始,对共享存储的读写权限变得更加严格,开发者可以选择是否使用分区存储,Android 11 中强制使用了分区存储。

分区存储/沙盒存储机制是一种安全机制,它用于限制应用对存储空间的访问权限,确保每个应用程序只能访问其被授权的资源和数据。这种机制通过为每个应用分配独立的存储区域(沙盒)来实现,每个应用都有自己的私有目录(例如 /data/data/<package_name>/)和自己创建的图片、视频、音频文件等,其他应用无法直接访问或修改其文件。

如果需要访问其他应用创建的媒体文件,则需要通过特性的 API(如 MediaStore API 或者 Storage Access Framework) 来访获取访问权限。

3 文件的读写操作

3.1 权限声明

首先在 AndroidManifest.xml 中声明必要的权限:

xml 复制代码
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<!-- 如果你的应用需要访问所有文件,你还可以声明MANAGE_EXTERNAL_STORAGE权限,
     但这通常需要用户手动在应用的设置页面开启,并且只有特定的应用类型(如文件管理器)才能请求此权限 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
                 android:maxSdkVersion="30"
                 tools:ignore="ScopedStorage" />

Android 11(API 30)及更高的版本中,对文件读写权限的处理发生了一些变化,主要是为了增强用户隐私和数据保护。如果我们的应用仍然需要访问共享存储空间(如 SD 卡)或需要旧版的存储访问权限,我们仍然可以在 Android 11 及更高版本上使用 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE。

MANAGE_EXTERNAL_STORAGE 是 Android 10/API 29 引入的一个特殊的权限,它允许应用访问所有的文件,但是通常只适用于特定的应用类型(如文件管理器),并且需要用户手动在应用设置页开启。对于大多数的应用,不建议使用此权限。

在 Android 11(API 30)及更高的版本中,如果申请了 MANAGE_EXTERNAL_STORAGE 权限,通常不需要再显示申请 WRITE_EXTERNAL_STORAGE 和 READ_EXTERNAL_STORAGE 权限,因为 MANAGE_EXTERNAL_STORAGE 权限已经允许应用全面的访问共享存储空间(包括读写权限)。

3.2 requestLegacyExternalStorage="true"

Android 10(API 29)及 Android 11(API 30)中,为了帮助开发者过渡到分区存储模型,Google 引入了一个临时解决方案,即 requestLegacyExternalStorage="true"。

xml 复制代码
<application
    android:requestLegacyExternalStorage="true"
    ... >
    ...
</application>

当 requestLegacyExternalStorage 属性为 true 的时候,表示应用可以继续使用之前版本的文件访问形式,即可以自由的读写共享存储中的文件。 然而,这个属性仅在 Android 10 和 Android 11 中有效,在未来的版本中可能被弃用。

在设置了 android:requestLegacyExternalStorage="true" 后,应用仍然需要申请 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限。

3.3 运行时请求权限
java 复制代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
  	// 对于Android 11(API 级别 30)及以上版本
    // 使用MediaStore API访问媒体文件或者使用分区存储的API 
  	if (Environment.isExternalStorageManager()) {
        // 应用已获得管理外部存储的权限
        // ...
    } else {
        // 应用未获得管理外部存储的权限
        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivityForResult(intent, REQUEST_CODE_MANAGE_EXTERNAL_STORAGE);
    }
} else {
    // 对于Android 10(API 级别 29),可以使用以下代码请求访问外部存储的权限
    boolean hasPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
    if (!hasPermission) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_MANAGE_EXTERNAL_STORAGE) {
        // 处理权限申请结果
        // 注意:这里无法直接获取到用户是否授予了权限,因为系统设置没有返回结果
        // 你可能需要再次检查Environment.isExternalStorageManager()来确定权限状态
    }
}
相关推荐
帅得不敢出门8 小时前
安卓设备adb执行AT指令控制电话卡
android·adb·sim卡·at指令·电话卡
我又来搬代码了10 小时前
【Android】使用productFlavors构建多个变体
android
德育处主任11 小时前
Mac和安卓手机互传文件(ADB)
android·macos
芦半山11 小时前
Android“引用们”的底层原理
android·java
迃-幵12 小时前
力扣:225 用队列实现栈
android·javascript·leetcode
大风起兮云飞扬丶12 小时前
Android——从相机/相册获取图片
android
Rverdoser12 小时前
Android Studio 多工程公用module引用
android·ide·android studio
aaajj13 小时前
[Android]从FLAG_SECURE禁止截屏看surface
android
@OuYang13 小时前
android10 蓝牙(二)配对源码解析
android
Liknana13 小时前
Android 网易游戏面经
android·面试