📅  最后修改于: 2023-12-03 14:58:44.371000             🧑  作者: Mango
自从 Android 10 开始,WRITE_EXTERNAL_STORAGE 不再提供直接访问外部存储的方式。应用程序需要适配新的存储访问架构来保持兼容性。
在 Android 10 及更高版本中,应用程序只能使用以下方式来访问外部存储:
使用 MediaStore API:应用程序可以使用 MediaStore API 查看、修改或删除用户媒体文件,如图像、音频或视频。使用 MediaStore API 还需要请求 READ_EXTERNAL_STORAGE 权限。
使用 Storage Access Framework(SAF)API:应用程序可以使用 SAF API 来访问用户选择的根目录。To let users select a whole directory subtree, use ACTION_OPEN_DOCUMENT_TREE。使用 SAF API 还需要请求 READ_EXTERNAL_STORAGE 权限。
如果应用程序需要访问应用程序特定目录下的文件,在 Android 10 上,应该创建一个 app-specific 目录,并在其下创建子目录和文件。这些目录和文件可以使用 Context.getExternalFilesDir() 和 Context.getExternalCacheDir() 方法。
对于最常见的媒体文件管理,使用 MediaStore API。
以下是在 Android 10 及更高版本中使用迁移 MediaStore API 的示例代码:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && Environment.isExternalStorageLegacy()) {
// Only use legacy storage API for Android 10 devices or above
// when external storage is already mounted
final String DCIMCameraDir = "/DCIM/Camera/";
final String DIRECTORY_PICTURES = "/Pictures/";
final String IMAGE_MIME_TYPE = "image/jpeg";
final String VIDEO_MIME_TYPE = "video/mp4";
// Get the Image and Video MediaStore collections
final Uri images = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
final Uri videos = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
// Find all JPEGs and save them to the camera folder
final Cursor imageCursor = getContentResolver().query(
images,
new String[] { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA },
MediaStore.Images.Media.MIME_TYPE + "=? OR " + MediaStore.Images.Media.MIME_TYPE + "=?",
new String[] { IMAGE_MIME_TYPE, "image/png"},
null);
while (imageCursor.moveToNext()) {
final long id = imageCursor.getLong(0);
final String path = imageCursor.getString(1);
final File file = new File(path);
final String newImagePath = DCIMCameraDir + file.getName();
final ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, newImagePath);
values.put(MediaStore.Images.Media.IS_PENDING, 1);
getContentResolver().update(images, values, MediaStore.Images.Media._ID + "=?", new String[]{Long.toString(id)});
file.renameTo(new File(newImagePath));
values.clear();
values.put(MediaStore.Images.Media.IS_PENDING, 0);
getContentResolver().update(images, values, MediaStore.Images.Media._ID + "=?", new String[]{Long.toString(id)});
}
// Find all videos and save them to the camera folder
final Cursor videoCursor = getContentResolver().query(
videos,
new String[] { MediaStore.Video.Media._ID, MediaStore.Video.Media.DATA },
null,
null,
null);
while (videoCursor.moveToNext()) {
final long id = videoCursor.getLong(0);
final String path = videoCursor.getString(1);
final File file = new File(path);
final String newVideoPath = DCIMCameraDir + file.getName();
final ContentValues values = new ContentValues();
values.put(MediaStore.Video.Media.DATA, newVideoPath);
values.put(MediaStore.Video.Media.IS_PENDING, 1);
getContentResolver().update(videos, values, MediaStore.Video.Media._ID + "=?", new String[]{Long.toString(id)});
file.renameTo(new File(newVideoPath));
values.clear();
values.put(MediaStore.Video.Media.IS_PENDING, 0);
getContentResolver().update(videos, values, MediaStore.Video.Media._ID + "=?", new String[]{Long.toString(id)});
}
imageCursor.close();
videoCursor.close();
} else {
// For devices running Android 9 and lower, or when external storage is not mounted
// keep using getExternalStoragePublicDirectory()
// See code samples for managing files on older devices and volumes
}
对于其他类型的文件操作,使用 SAF API。
以下是使用 Storage Access Framework(SAF)API 的示例代码:
// Use the ACTION_OPEN_DOCUMENT tree intent to request access to the attached storage device.
private static final int EXTERNAL_STORAGE_REQUEST_CODE = 100;
private void requestStoragePermissionForSAF() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, EXTERNAL_STORAGE_REQUEST_CODE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (requestCode == EXTERNAL_STORAGE_REQUEST_CODE && resultCode == RESULT_OK) {
if (resultData != null) {
// Use the provided uri to access the attached storage device.
Uri treeUri = resultData.getData();
getContentResolver().takePersistableUriPermission(
treeUri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
// the application can access files from device
}
}
}
以上就是适配 Android 10 存储访问架构的示例代码和操作说明。
在 Android 10 及更高版本中,应用程序需要适配新的存储访问架构来保持兼容性。使用 MEDIASTORE API 和 SAF API 可以满足访问不同类型文件的需求。注意:在 Android 10 中,请求 WRITE_EXTERNAL_STORAGE 权限已不再提供,应用程序不应再使用此权限来访问外部存储。