.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.
相关产品推荐
相关产品推荐

