Android 13下载文件夹文件读取EACCES权限问题求助
Android 13 读取Download目录MP3文件权限问题解决方案
核心原因
Android 13 对存储权限做了细分:原READ_EXTERNAL_STORAGE权限被拆分为媒体类型专属权限,直接通过FileInputStream访问外部存储文件需匹配对应权限;同时未通过MediaStore索引的文件可能触发权限拦截。
解决方案步骤
1. 更新权限声明
在AndroidManifest.xml中添加适配不同版本的权限:
<!-- Android 13+ 音频媒体读取权限 --> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- 兼容 Android 12 及以下版本 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
2. 动态申请权限
在读取文件前检查并申请对应权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityResultLauncher<String[]> requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> { Boolean audioGranted = result.getOrDefault(Manifest.permission.READ_MEDIA_AUDIO, false); if (audioGranted) { readMp3File(); } else { // 提示用户开启权限 } }); requestPermissionLauncher.launch(new String[]{Manifest.permission.READ_MEDIA_AUDIO}); } else { readMp3File(); } } else { // 执行 Android 12 及以下的 READ_EXTERNAL_STORAGE 权限申请逻辑 }
3. 通过ContentResolver读取文件(替代FileInputStream)
利用MediaStore查询文件Uri,通过ContentResolver打开输入流,避免直接路径访问的权限问题:
private void readMp3File() { String fileName = "file.mp3"; String relativeFolder = "Download/myFolder2/"; Uri contentUri = MediaStore.Downloads.EXTERNAL_CONTENT_URI; String[] projection = {MediaStore.Downloads._ID}; String selection = MediaStore.Downloads.RELATIVE_PATH + " = ? AND " + MediaStore.Downloads.DISPLAY_NAME + " = ?"; String[] selectionArgs = {relativeFolder, fileName}; Cursor cursor = getContentResolver().query(contentUri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { long fileId = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Downloads._ID)); Uri fileUri = ContentUris.withAppendedId(MediaStore.Downloads.EXTERNAL_CONTENT_URI, fileId); try (InputStream inputStream = getContentResolver().openInputStream(fileUri)) { if (inputStream != null) { // 执行文件读取逻辑,如转为byte数组或直接处理流 } } catch (IOException e) { e.printStackTrace(); } cursor.close(); } }
4. 优化下载逻辑(确保文件被系统索引)
下载时通过MediaStore写入文件,自动完成系统索引,避免后续读取时的识别问题:
private void downloadMp3ToDownloadFolder(String fileName) { ContentValues values = new ContentValues(); values.put(MediaStore.Downloads.DISPLAY_NAME, fileName); values.put(MediaStore.Downloads.RELATIVE_PATH, "Download/myFolder2"); values.put(MediaStore.Downloads.MIME_TYPE, "audio/mpeg"); values.put(MediaStore.Downloads.IS_PENDING, 1); Uri uri = getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); if (uri != null) { try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) { // 将下载的MP3数据写入outputStream // 写入完成后标记文件为已就绪 values.clear(); values.put(MediaStore.Downloads.IS_PENDING, 0); getContentResolver().update(uri, values, null, null); } catch (IOException e) { e.printStackTrace(); // 写入失败时删除无效记录 getContentResolver().delete(uri, null, null); } } }
内容的提问来源于stack exchange,提问作者Ozkan Tuzemen
相关产品推荐
相关产品推荐

