Android 11(JAVA)代码实现外部存储视频播放及播放异常解决
Android 11下通过Uri/文件/Base64播放视频解决方案
问题根源
你当前的核心问题是:通过ACTION_GET_CONTENT获取的是内容Uri,而非真实文件路径,直接调用uri.getPath()转File在Android 11及以上会失效——因为系统限制了直接访问外部存储的文件路径,且内容Uri的getPath()字段并非真实文件路径。
一、直接通过Uri播放(推荐,最简洁合规)
无需转文件或Base64,直接使用获取到的内容Uri,关键是给第三方播放器授予临时读取权限:
修改播放代码
@Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && data != null) { Uri videoUri = data.getData(); // 直接用内容Uri播放 Intent playIntent = new Intent(Intent.ACTION_VIEW); playIntent.setDataAndType(videoUri, "video/*"); // 授予临时读取权限,否则第三方播放器无法访问Uri playIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); playIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(playIntent); } }
二、通过File对象播放(不推荐,权限限制多)
如果必须转成File,需要将内容Uri对应的文件复制到应用私有目录(Android 11允许访问),再通过FileProvider生成可共享的Uri:
1. 复制文件到私有目录
@Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && data != null) { Uri videoUri = data.getData(); try { // 创建应用私有目录下的临时文件 File tempFile = new File(getFilesDir(), "temp_video.mp4"); // 从内容Uri读取数据并写入临时文件 InputStream inputStream = getContentResolver().openInputStream(videoUri); FileOutputStream outputStream = new FileOutputStream(tempFile); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length); } inputStream.close(); outputStream.close(); // 播放临时文件 playLocalFile(tempFile); } catch (IOException e) { e.printStackTrace(); } } }
2. 配置FileProvider
在AndroidManifest.xml中添加Provider声明:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
在res/xml目录下创建file_paths.xml:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="private_files" path="." /> </paths>
3. 播放本地文件的方法
private void playLocalFile(File file) { Uri fileUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", file); Intent playIntent = new Intent(Intent.ACTION_VIEW); playIntent.setDataAndType(fileUri, "video/*"); playIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(playIntent); }
三、通过Base64播放视频
将Base64字符串转为字节数组后,可选择写入临时文件播放(兼容性更好),或直接用MediaPlayer加载:
方法1:转临时文件播放
// 假设base64Str是已获取的Base64视频字符串 byte[] videoBytes = Base64.decode(base64Str, Base64.DEFAULT); try { File tempFile = new File(getFilesDir(), "base64_video.mp4"); FileOutputStream fos = new FileOutputStream(tempFile); fos.write(videoBytes); fos.close(); // 复用上面的playLocalFile方法播放 playLocalFile(tempFile); } catch (IOException e) { e.printStackTrace(); }
方法2:用MediaPlayer直接加载字节数组(自定义播放器场景)
byte[] videoBytes = Base64.decode(base64Str, Base64.DEFAULT); MediaPlayer mediaPlayer = new MediaPlayer(); try { mediaPlayer.setDataSource(new ByteArrayInputStream(videoBytes)); mediaPlayer.prepare(); mediaPlayer.start(); // 记得在合适的时机释放MediaPlayer mediaPlayer.setOnCompletionListener(mp -> mp.release()); } catch (IOException e) { e.printStackTrace(); }
内容的提问来源于stack exchange,提问作者Faizan Ahmad
相关产品推荐
相关产品推荐

