You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 15:27:21