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()来确定权限状态
    }
}
相关推荐
非凡ghost28 分钟前
LSPatch官方版:无Root Xposed框架,自由定制手机体验
android·智能手机·软件需求
_extraordinary_28 分钟前
MySQL 库的操作 -- 增删改查,备份和恢复,系统编码
android·mysql·oracle
西瓜本瓜@3 小时前
在Android中如何使用Protobuf上传协议
android·java·开发语言·git·学习·android-studio
似霰6 小时前
安卓adb shell串口基础指令
android·adb
fatiaozhang95278 小时前
中兴云电脑W102D_晶晨S905X2_2+16G_mt7661无线_安卓9.0_线刷固件包
android·adb·电视盒子·魔百盒刷机·魔百盒固件
CYRUS_STUDIO9 小时前
Android APP 热修复原理
android·app·hotfix
鸿蒙布道师10 小时前
鸿蒙NEXT开发通知工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
鸿蒙布道师10 小时前
鸿蒙NEXT开发网络相关工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
大耳猫10 小时前
【解决】Android Gradle Sync 报错 Could not read workspace metadata
android·gradle·android studio
ta叫我小白10 小时前
实现 Android 图片信息获取和 EXIF 坐标解析
android·exif·经纬度