Android 11设备无法从下载文件夹外路径选取上传文件问题求助
Android 11(API 30)强制开启分区存储机制,你当前代码中依赖查询MediaStore的_data字段获取文件绝对路径的方案已经被官方废弃,除Download目录、公共媒体库目录外的其他路径文件都无法通过该方式拿到本地路径,所以返回null。
方案1:放弃绝对路径转换,直接通过Uri处理文件(官方推荐)
你不需要拿到文件的真实本地路径,通过系统返回的Uri就可以读取到文件内容,你可以将Uri对应的文件拷贝到应用私有缓存目录,再用缓存文件的路径进行上传,适配所有Android版本,不需要申请额外存储权限。
新增工具方法:
// 从Uri获取文件名 private static String getFileName(Context context, Uri uri) { String fileName = null; if (DocumentsContract.isDocumentUri(context, uri)) { String docId = DocumentsContract.getDocumentId(uri); String[] split = docId.split(":"); fileName = split[split.length - 1]; } else if ("content".equals(uri.getScheme())) { try (Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { int index = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME); if (index != -1) { fileName = cursor.getString(index); } } } } if (fileName == null) { fileName = uri.getLastPathSegment(); } return fileName; } // 将Uri对应文件拷贝到应用私有缓存目录,返回缓存文件路径 public static String getPathFromUri(Context context, Uri uri) throws IOException { String fileName = getFileName(context, uri); File cacheFile = new File(context.getCacheDir(), fileName); try (InputStream inputStream = context.getContentResolver().openInputStream(uri); OutputStream outputStream = new FileOutputStream(cacheFile)) { byte[] buffer = new byte[4096]; int len; while ((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } } return cacheFile.getAbsolutePath(); }
修改MainActivity的onActivityResult逻辑:
将原来的
path = AppUtils.getfilePath(getContext(), uri);
替换为
try { path = AppUtils.getPathFromUri(getContext(), uri); } catch (IOException e) { e.printStackTrace(); Toast.makeText(getContext(), "读取文件失败", Toast.LENGTH_SHORT).show(); }
原有后续上传逻辑完全不用改动,直接使用返回的缓存路径即可。
方案2:申请全量存储权限(仅适合文件管理类应用)
如果你的应用确实需要访问设备所有存储路径,可以申请全量存储权限解决问题,该权限Google Play上架需要额外审核,非必要不推荐。
- 修改AndroidManifest.xml配置:
<!-- Android 11及以上全存储权限 --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" /> <application ... android:requestLegacyExternalStorage="true">
- 代码中动态申请权限:
// 申请全量存储权限请求码,自己定义即可 private static final int REQUEST_MANAGE_STORAGE = 1001; // 权限判断逻辑 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_MANAGE_STORAGE); } }
用户授权后原有获取绝对路径的逻辑即可正常使用。
内容的提问来源于stack exchange,提问作者Ajay Ghatge
相关产品推荐
相关产品推荐

