Android使用Multipart Retrofit上传文件时遭遇权限拒绝问题
问题解决:Android图库文件上传报EACCES权限拒绝
问题原因
从Android 10(API 29)开始引入的Scoped Storage(分区存储)机制,限制了应用直接访问外部存储的真实文件路径。即使你通过URI转换得到了文件路径,直接用File(path)打开文件也会被系统拒绝权限,抛出android.system.ErrnoException: open failed: EACCES (Permission denied)异常。此外,Android 13(API 33)之后,原有的READ_EXTERNAL_STORAGE权限被拆分为媒体类型专属权限,权限申请不匹配也会导致访问失败。
解决方案
1. 改用ContentResolver获取文件流,避免直接访问真实路径
放弃通过真实路径创建File对象,直接利用ContentResolver从URI获取文件输入流来构建MultipartBody.Part,这是Scoped Storage下的标准做法:
private fun getMultiPartFromUri(context: Context, uri: Uri, partName: String): MultipartBody.Part { val contentResolver = context.contentResolver // 获取文件MIME类型,默认用*/* val mimeType = contentResolver.getType(uri) ?: "*/*" val requestFile = object : RequestBody() { override fun contentType(): MediaType? { return mimeType.toMediaTypeOrNull() } override fun writeTo(sink: BufferedSink) { contentResolver.openInputStream(uri)?.use { inputStream -> sink.writeAll(inputStream.source()) } ?: throw IOException("无法打开文件输入流") } } // 从URI获取文件名(可选,根据后端需求调整) val fileName = getFileNameFromUri(context, uri) return MultipartBody.Part.createFormData(partName, fileName, requestFile) } // 辅助方法:从媒体URI获取文件名 private fun getFileNameFromUri(context: Context, uri: Uri): String { var fileName = "unknown_file" val cursor = context.contentResolver.query(uri, null, null, null, null) cursor?.use { if (it.moveToFirst()) { val nameColumnIndex = it.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME) if (nameColumnIndex != -1) { fileName = it.getString(nameColumnIndex) } } } return fileName }
2. 确保权限申请正确
根据目标Android版本申请对应权限:
- Android 13+(API 33):根据文件类型申请
READ_MEDIA_IMAGES、READ_MEDIA_VIDEO或READ_MEDIA_AUDIO权限,在AndroidManifest.xml中声明:<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- 根据需要添加其他媒体权限 --> - Android 10-12(API 29-32):申请
READ_EXTERNAL_STORAGE权限:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> - 所有版本都需要动态申请权限,确保用户授予权限后再进行文件操作。
3. 取消真实路径转换流程
直接保留从图库选择得到的Uri,不再转换为真实路径,全程用Uri处理文件上传,避免因路径转换带来的权限问题。
内容的提问来源于stack exchange,提问作者Shashank Singh Bisht
相关产品推荐
相关产品推荐

