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

.NET Maui Android API33下Plugin.AudioRecorder音频保存失败

解决.NET Maui Android API30+ 音频保存到Pictures自定义目录被拒绝的问题

问题根源

Android 10(API30)开始强制启用Scoped Storage,android:requestLegacyExternalStorage="true"仅在API29中生效,API30及以上版本会直接忽略该配置。此时直接通过文件路径访问公共存储(如Pictures目录)会触发权限拒绝,因为Scoped Storage限制了应用对公共存储的直接文件系统访问,必须通过系统提供的MediaStore接口操作公共媒体文件。

解决方案

1. 调整权限配置

在AndroidManifest.xml中更新权限:

  • API33及以上:添加READ_MEDIA_AUDIO权限(用于读取媒体文件,保存操作无需额外WRITE权限)
  • 保留原有录音权限,移除不再需要的WRITE_EXTERNAL_STORAGE(API30+下通过MediaStore保存无需此权限;若需兼容API29及以下,可保留该权限并添加maxSdkVersion="29")
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" android:minSdkVersion="33" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />

2. 修改音频保存逻辑

不再直接通过文件路径创建/写入文件,改用MediaStore接口将录制好的音频文件写入Pictures下的自定义目录。以下是Android平台的实现代码(可通过.NET Maui的依赖服务跨平台调用):

using Android.Content;
using Android.OS;
using Android.Provider;
using System.IO;

public void SaveAudioToCustomPicturesDir(string tempAudioFilePath, string outputFileName)
{
    // 指定Pictures下的自定义目录路径
    string relativeDir = $"{Android.OS.Environment.DirectoryPictures}/MyAudioFolder";

    // 构建媒体文件元数据
    ContentValues mediaValues = new ContentValues();
    mediaValues.Put(MediaStore.Audio.Media.Columns.DisplayName, outputFileName);
    mediaValues.Put(MediaStore.Audio.Media.Columns.MimeType, "audio/m4a"); // 根据你的音频格式调整(如audio/wav)
    mediaValues.Put(MediaStore.Audio.Media.Columns.RelativePath, relativeDir);

    // 获取ContentResolver插入媒体条目
    ContentResolver resolver = Android.App.Application.Context.ContentResolver;
    Android.Net.Uri mediaUri = resolver.Insert(MediaStore.Audio.Media.ExternalContentUri, mediaValues);

    if (mediaUri != null)
    {
        // 将临时录制文件复制到目标位置
        using (Stream outputStream = resolver.OpenOutputStream(mediaUri))
        using (Stream inputStream = new FileStream(tempAudioFilePath, FileMode.Open))
        {
            inputStream.CopyTo(outputStream);
        }
    }
}

3. 适配Plugin.AudioRecorder的临时文件

Plugin.AudioRecorder录制完成后会生成临时音频文件(通常存储在应用专属目录),你只需将该临时文件路径传入上述方法,即可完成向Pictures自定义目录的迁移。

补充说明

  • Scoped Storage下,自定义目录会在首次插入文件时由系统自动创建,无需手动调用文件系统API创建目录
  • 若需让用户在系统相册/文件管理器中立即看到新增的音频文件,可调用MediaScannerConnection.ScanFile触发媒体扫描:
MediaScannerConnection.ScanFile(Android.App.Application.Context, 
    new string[] { mediaUri.Path }, 
    new string[] { "audio/m4a" }, 
    null);

内容的提问来源于stack exchange,提问作者Steven Gazo M.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 18:52:54