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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 21:58:29