MAUI(.NET 8)音频播放器如何访问Android设备的公共Music存储目录?
在.NET 8 MAUI中访问Android公共Music目录的解决方案
问题根源
你用Environment.GetFolderPath(Environment.SpecialFolder.MyMusic)拿到的是应用私有存储目录,这是MAUI跨平台API的设计特性,它指向应用沙箱内的Music文件夹,而非系统公共的Internal storage/Music目录。同时,Android 13+的权限模型已变更,原有的READ_EXTERNAL_STORAGE权限不再适用于媒体文件访问。
解决方案步骤
1. 更新权限配置
在AndroidManifest.xml中添加对应权限,适配不同Android版本:
- Android 13(API 33)及以上,需
READ_MEDIA_AUDIO权限访问音频文件 - Android 12及以下,保留
READ_EXTERNAL_STORAGE做兼容
修改后的权限节点:
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" android:maxSdkVersion="33" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
2. 获取公共Music目录的正确方式
方式一:直接获取公共目录路径(Android原生API)
通过MAUI的平台条件编译调用Android原生API,获取系统公共Music目录:
#if ANDROID using Android.OS; #endif public string GetPublicMusicPath() { #if ANDROID var publicMusicDir = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryMusic); return publicMusicDir?.AbsolutePath ?? string.Empty; #else // 其他平台沿用跨平台API逻辑 return Environment.GetFolderPath(Environment.SpecialFolder.MyMusic); #endif }
注意:Android 10(API 29)及以上启用了Scoped Storage,直接读写该目录文件可能受限,更推荐用MediaStore查询音频文件。
方式二:通过MediaStore查询音频文件(官方推荐)
Scoped Storage时代,访问媒体文件的合规方式是通过MediaStore,以下是查询公共Music目录下.mp3文件的示例:
#if ANDROID using Android.Content; using Android.Database; using Android.Provider; #endif public async Task<List<string>> GetAllMusicFilesAsync() { List<string> musicFiles = new List<string>(); #if ANDROID var uri = MediaStore.Audio.Media.ExternalContentUri; string[] projection = { MediaStore.Audio.Media.Data }; using (ICursor cursor = Android.App.Application.Context.ContentResolver.Query(uri, projection, null, null, null)) { if (cursor != null && cursor.MoveToFirst()) { int dataColumnIndex = cursor.GetColumnIndex(MediaStore.Audio.Media.Data); do { string filePath = cursor.GetString(dataColumnIndex); if (filePath.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)) { musicFiles.Add(filePath); } } while (cursor.MoveToNext()); } } #endif return musicFiles; }
3. 权限请求适配
更新权限请求逻辑,区分Android版本处理不同权限:
protected override async void OnAppearing() { base.OnAppearing(); PermissionStatus status; #if ANDROID if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Tiramisu) { status = await Permissions.CheckStatusAsync<Permissions.MediaAudio>(); if (status != PermissionStatus.Granted) { status = await Permissions.RequestAsync<Permissions.MediaAudio>(); } } else { status = await Permissions.CheckStatusAsync<Permissions.StorageRead>(); if (status != PermissionStatus.Granted) { status = await Permissions.RequestAsync<Permissions.StorageRead>(); } } #else status = await Permissions.CheckStatusAsync<Permissions.StorageRead>(); if (status != PermissionStatus.Granted) { status = await Permissions.RequestAsync<Permissions.StorageRead>(); } #endif if (status == PermissionStatus.Granted) { var publicMusicPath = GetPublicMusicPath(); var musicFiles = await GetAllMusicFilesAsync(); // 处理获取到的路径或文件列表 } else { // 权限未授予的提示或逻辑处理 } }
关键说明
- Scoped Storage限制:Android 10及以上,直接操作公共目录文件可能触发权限异常,使用MediaStore是官方推荐的合规方案。
- 版本适配:不同Android版本的权限模型差异较大,必须针对API级别做区分处理。
内容的提问来源于stack exchange,提问作者Saba
相关产品推荐
相关产品推荐

