Android模拟器SD卡音频无法播放问题排查(附报错与代码)
解决Android模拟器播放SD卡音乐时的SSLHandshakeException问题
嘿,我发现你遇到的问题有点蹊跷——明明是播放本地SD卡的音乐,却抛出了SSL相关的错误,这其实是文件路径的Uri格式错误导致的典型小坑!
问题根源
你直接使用了字符串"sdcard/sample_music.mp3"来构造Uri,但这个格式并没有明确告诉MediaPlayer这是本地文件。MediaPlayer会默认尝试将其当作网络资源去加载,从而触发了SSL握手流程,自然就会抛出SSLHandshakeException和证书验证失败的错误。
解决方案
1. 修正本地文件Uri的格式
本地文件的Uri必须以file://开头,这样MediaPlayer才会识别为本地资源而非网络资源。你可以直接修改路径字符串:
String media_path= "file:///sdcard/sample_music.mp3";
注意这里是三个斜杠:file://加上本地路径的根目录/sdcard/。
2. 使用系统API获取SD卡路径(更推荐)
硬编码sdcard路径在不同设备上可能存在兼容性问题,建议用Android提供的标准API获取外部存储路径:
String media_path = "file://" + Environment.getExternalStorageDirectory().getPath() + "/sample_music.mp3";
3. 确保申请了文件读写权限
如果你的App运行在Android 6.0(API 23)及以上版本,还需要动态申请读写外部存储的权限:
- 在
AndroidManifest.xml中添加静态权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
- 在代码中动态申请权限(点击播放按钮前检查权限):
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 100); return; }
修改后的完整代码
play_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 先检查权限 if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 100); return; } Log.d(TAG,"Onclick"); mediaPlayer=new MediaPlayer(); // 使用标准API构造本地文件Uri String media_path = "file://" + Environment.getExternalStorageDirectory().getPath() + "/sample_music.mp3"; mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); Uri uri= Uri.parse(media_path); Log.d(TAG,"Player initiated"); try { mediaPlayer.setDataSource(getApplicationContext(), uri); mediaPlayer.prepare(); mediaPlayer.start(); Toast.makeText(getApplicationContext(), "Playback started", Toast.LENGTH_LONG).show(); play_btn.setEnabled(false); } catch (IOException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "播放失败:" + e.getMessage(), Toast.LENGTH_LONG).show(); } mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { play_btn.setEnabled(true); mediaPlayer.release(); mediaPlayer = null; Toast.makeText(getApplicationContext(), "Playback finished", Toast.LENGTH_LONG).show(); } }); } });
额外注意事项
- 测试前确保
sample_music.mp3确实存在于模拟器的SD卡根目录下,可以通过Android Studio的Device File Explorer查看 - MediaPlayer使用完毕后一定要调用
release()释放资源,避免内存泄漏 - 如果是Android 10及以上版本,还需要注意Scoped Storage的限制,可能需要使用MediaStore来访问媒体文件
内容的提问来源于stack exchange,提问作者user9396014




