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

播放WAV文件时遇权限问题及MediaPlayer报错求助

问题分析与解决方案

核心问题

  1. 权限适配错误:你的targetSdk是33(Android 13),该版本开始READ_EXTERNAL_STORAGE权限被废弃,针对音频文件需使用READ_MEDIA_AUDIO权限,旧权限申请逻辑在API33+环境下会直接返回拒绝,不会弹出授权弹窗。
  2. MediaPlayer数据源潜在问题:Uri.fromFile()在Android 7.0+可能触发FileUriExposedException,同时权限问题也会导致数据源设置失败。

分步解决

1. 修正Manifest权限声明

替换原有存储权限,适配API33+的媒体权限:

<!-- 适配Android 13+(API33)的音频读取权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<!-- 兼容Android 12及以下(API32)的存储读取权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

2. 适配动态权限申请逻辑

根据系统版本判断要申请的权限,确保API33+环境下请求正确的媒体权限:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 动态权限申请逻辑
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        // Android 13+ 申请音频媒体权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_MEDIA_AUDIO}, 1);
        }
    } else {
        // Android 12及以下 申请外部存储读取权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
        }
    }
}

3. 修复MediaPlayer数据源问题

方案A:直接使用文件路径设置数据源(简单高效)

避免Uri相关的权限和暴露问题,直接传入文件路径:

if (audioFile != null && audioFile.exists()) {
    mediaPlayer = new MediaPlayer();
    try {
        // 直接用文件路径替代Uri
        mediaPlayer.setDataSource(audioFile.getAbsolutePath());
        mediaPlayer.prepare();
        mediaPlayer.start();
    } catch (IOException e) {
        Log.e("MediaPlayer Error", "Error while setting data source: " + e.getMessage());
    } catch (IllegalArgumentException e) {
        Log.e("MediaPlayer Error", "Error while preparing MediaPlayer: " + e.getMessage());
    } catch (IllegalStateException e) {
        Log.e("MediaPlayer Error", "Error while starting MediaPlayer: " + e.getMessage());
    }
} else {
    Toast.makeText(MainActivity.this, "No audio file to play", Toast.LENGTH_SHORT).show();
}

方案B:使用FileProvider获取安全Uri(适合共享文件场景)

如果需要用Uri传递文件,配置FileProvider避免文件暴露:

  • 在AndroidManifest.xml的<application>标签内添加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>
    <!-- 允许访问外部存储根目录 -->
    <external-path name="external_files" path="." />
</paths>
  • 修改MediaPlayer的Uri获取逻辑:
Uri audioUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".fileprovider", audioFile);
mediaPlayer.setDataSource(getApplicationContext(), audioUri);

4. 优化权限回调逻辑

处理用户勾选"不再询问"的场景,引导用户去系统设置开启权限:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 1) {
        boolean isGranted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
        if (isGranted) {
            Toast.makeText(MainActivity.this, "Ja", Toast.LENGTH_SHORT).show();
            // 权限获取成功后,可在此触发音频播放
        } else {
            // 判断用户是否勾选了"不再询问"
            if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0])) {
                // 引导用户去应用设置页开启权限
                Intent settingIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                Uri uri = Uri.fromParts("package", getPackageName(), null);
                settingIntent.setData(uri);
                startActivity(settingIntent);
            } else {
                Toast.makeText(MainActivity.this, "Nein", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Neo-S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:20:33