简介:Android 10推出的Scoped Storage机制通过隔离应用私有目录与共享存储空间,重构了应用存储权限模型。本文从技术原理、权限体系、应用适配及典型场景四个维度深入解析该机制,并提供代码示例与最佳实践建议。
Android 10(API 29)引入的Scoped Storage机制是Google针对应用存储权限管理的一次革命性重构。在Android 9及更早版本中,应用可通过REQUEST_EXTERNAL_STORAGE权限自由访问设备上的所有共享存储位置(如DCIM、Downloads等目录),这导致用户隐私数据泄露风险激增,且不同应用间的文件管理容易产生冲突。
Scoped Storage的核心目标在于:隔离应用私有数据与共享数据、最小化权限暴露范围、提升文件系统可维护性。其技术实现通过两个维度展开:
/data/data/<package_name>)和外部专属目录(/Android/data/<package_name>/files),无需权限即可自由读写。Android 10废弃了传统的READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限的泛用性,转而采用更细粒度的控制:
/Android/data/<package_name>/下的文件。READ_EXTERNAL_STORAGE权限(但仅限当前应用创建的媒体文件)。Downloads API或SAF访问Downloads/目录,需用户显式授权。Documents/、Pictures/等目录需通过SAF选择文件,或申请MANAGE_EXTERNAL_STORAGE权限(需用户手动授权且需通过Google Play政策审核)。
// 查询当前应用创建的图片ContentResolver resolver = getContentResolver();String[] projection = {MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME};String selection = MediaStore.Images.Media.RELATIVE_PATH + " LIKE ?";String[] selectionArgs = {"Pictures/%"}; // 仅查询当前应用目录Cursor cursor = resolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,projection,selection,selectionArgs,null);// 插入图片到应用专属目录ContentValues values = new ContentValues();values.put(MediaStore.Images.Media.DISPLAY_NAME, "test.jpg");values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/" + getPackageName());Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
/sdcard/DCIM/等路径的逻辑需重构为MediaStore API调用。Context.getExternalFilesDir()或getCacheDir()下。AndroidManifest.xml中设置android:requestLegacyExternalStorage="true"(仅限Android 10过渡期使用),并通过Build.VERSION.SDK_INT判断API级别动态调整逻辑。Intent.ACTION_OPEN_DOCUMENT或ACTION_CREATE_DOCUMENT启动系统文件选择器。
// 请求存储权限(Android 10以下)if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_CODE);}}// Android 10+:保存到应用专属目录File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "data.zip");try (FileOutputStream fos = new FileOutputStream(file)) {fos.write(data); // 写入数据} catch (IOException e) {e.printStackTrace();}
// 通过SAF共享文件Intent intent = new Intent(Intent.ACTION_SEND);intent.setType("*/*");intent.putExtra(Intent.EXTRA_STREAM, uri); // uri为ContentUri或FileProvider生成的Uriintent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);startActivity(Intent.createChooser(intent, "Share via"));// 配置FileProvider(AndroidManifest.xml)<providerandroid:name="androidx.core.content.FileProvider"android:authorities="${applicationId}.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /></provider>
Scoped Storage的推行标志着Android生态向隐私优先和标准化存储的转型。其影响体现在:
未来,随着Google Play对MANAGE_EXTERNAL_STORAGE权限的严格审核,开发者需更依赖MediaStore和SAF实现文件操作。建议开发者尽早完成适配,并关注Android 14对存储权限的进一步优化。