Android 13下如何通过代码删除DCIM子文件夹中的照片?
问题:Android 13下无法删除DCIM子文件夹中的照片(结合FileProvider与相机Intent)
场景与问题
- 运行环境:Android 13,仅使用内部存储,Manifest已配置读写权限,运行时仅申请了相机和读取图片权限
- 目标路径:
/storage/emulated/0/DCIM/NewCam/NewCamPhoto.jpg - 问题:使用FileProvider配合相机Intent保存照片时,仅当目标文件/文件夹不存在时才能正常保存;手动删除现有照片后相机可正常拍摄保存,但通过代码删除该位置的照片/文件夹无效,照片仍存在
现有代码
1. 删除文件夹的尝试代码
public static void deleteFolder(String folderPath) { Log.d("yoyo","**** SCANNER **** DELETING "+folderPath); File folder = new File(folderPath); if (folder.exists()) { String[] children = folder.list(); for (int i = 0; i < children.length; i++) { boolean success = deleteRecursive(new File(folder, children[i])); if (!success) { return; } } // The folder is now empty so delete it folder.delete(); } } private static boolean deleteRecursive(File file) { if (file.isDirectory()) { String[] children = file.list(); for (int i = 0; i < children.length; i++) { boolean success = deleteRecursive(new File(file, children[i])); if (!success) { return false; } } } else { return file.delete(); } return true; }
2. 相机Intent相关代码
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File photo = new File(path, Name); if (photo.exists()) photo.delete(); PhotoPath = photo.getAbsolutePath(); i.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(RunnerActivity.CurrentActivity, RunnerActivity.CurrentActivity.getPackageName() + ".NewCam",photo)); RunnerActivity.CurrentActivity.startActivityForResult(i, REQUEST_CODE_CAMERA);
3. Manifest中的FileProvider配置
<provider android:name="androidx.core.content.FileProvider" android:authorities="com.cam.newcam.scannerprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider>
4. provider_paths.xml内容
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="." /> <!-- Access to a specific subdirectory within DCIM --> <external-path name="external_dcim" path="DCIM/NewCam" /> </paths>
解决方案
1. 修正FileProvider Authorities匹配问题
代码中FileProvider.getUriForFile的第二个参数(authorities)必须与Manifest中配置的android:authorities完全一致。
将相机Intent代码中的authorities修改为Manifest中配置的值:
// 替换原来的authorities参数为Manifest中配置的"com.cam.newcam.scannerprovider" i.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(RunnerActivity.CurrentActivity, "com.cam.newcam.scannerprovider", photo));
2. 改用MediaStore API删除媒体文件
Android 13对DCIM等媒体目录的文件访问有严格限制,直接使用File.delete()可能因媒体库索引或权限问题无法生效,需通过MediaStore API删除:
private boolean deletePhotoFromMediaStore(Context context, String photoPath) { // 先尝试从MediaStore中查找并删除 String[] projection = {MediaStore.Images.Media._ID}; String selection = MediaStore.Images.Media.DATA + "=?"; String[] selectionArgs = {photoPath}; Cursor cursor = context.getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null); if (cursor != null) { if (cursor.moveToFirst()) { long mediaId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)); Uri mediaUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mediaId); int deletedRows = context.getContentResolver().delete(mediaUri, null, null); cursor.close(); return deletedRows > 0; } cursor.close(); } // 如果MediaStore中未找到,尝试直接删除文件 File photoFile = new File(photoPath); return photoFile.delete(); }
3. 调整权限申请(Android 13)
Android 13删除媒体文件需要READ_MEDIA_IMAGES权限,需在Manifest中声明并运行时申请:
Manifest声明:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
运行时申请代码:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(RunnerActivity.CurrentActivity, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { // 使用ActivityResultAPI申请权限 ActivityResultLauncher<String> requestPermissionLauncher = RunnerActivity.CurrentActivity.registerForActivityResult( new ActivityResultContracts.RequestPermission(), isGranted -> { if (isGranted) { // 权限授予后执行删除和相机逻辑 launchCameraIntent(); } else { // 提示用户需要权限才能删除照片 } }); requestPermissionLauncher.launch(Manifest.permission.READ_MEDIA_IMAGES); return; } } // 权限已授予,直接执行 launchCameraIntent();
4. 启动相机Intent前调用删除方法
修改相机启动逻辑,先调用删除方法:
private void launchCameraIntent() { Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File photo = new File(path, Name); // 删除目标照片 deletePhotoFromMediaStore(RunnerActivity.CurrentActivity, photo.getAbsolutePath()); PhotoPath = photo.getAbsolutePath(); // 使用正确的authorities获取FileProvider Uri i.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(RunnerActivity.CurrentActivity, "com.cam.newcam.scannerprovider", photo)); RunnerActivity.CurrentActivity.startActivityForResult(i, REQUEST_CODE_CAMERA); }
补充说明
- 如果需要删除整个
DCIM/NewCam文件夹,需遍历文件夹内所有文件,逐个用MediaStoreAPI删除,最后再调用folder.delete()删除空文件夹 - Android 13中,APP删除自身创建的媒体文件也需通过
MediaStoreAPI,确保媒体库索引同步,避免出现文件已删除但系统相册仍显示的情况
内容的提问来源于stack exchange,提问作者rafhelp
相关产品推荐
相关产品推荐

