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

如何通过Xamarin Forms便携类库结合依赖注入列出存储媒体文件?

在Xamarin.Forms便携类库中列出所有媒体文件的实现方案

嘿,我来帮你梳理下怎么搞定这个需求~你当前的代码是直接遍历Android根目录,但这里有几个明显的问题:一是根目录里几乎找不到你要的媒体文件(照片、视频这些都存在专门的媒体目录),二是Android 10及以上的Scoped Storage机制会限制你直接访问外部存储目录,三是既然用了便携类库,就得考虑跨平台的兼容性。结合你已经在用的依赖注入,我们可以这么来实现:


第一步:在便携类库中定义共享接口

首先要在PCL/共享项目里定义一个统一的接口,让各个平台去实现,这样上层代码不用关心具体平台的细节:

public interface IMediaFileService
{
    // 获取所有类型的媒体文件
    List<string> GetAllMediaFiles();
    // 按类型筛选(图片/视频/音频)
    List<string> GetMediaFilesByType(MediaType mediaType);
}

// 枚举媒体类型,方便筛选
public enum MediaType
{
    Image,
    Video,
    Audio
}

第二步:Android平台的具体实现

因为你当前的代码是Android的,重点说这个平台。我们不用直接遍历目录,而是通过ContentResolver查询系统的媒体库——这是Android推荐的方式,既能避开Scoped Storage的限制,又能高效获取所有媒体文件。

先配置权限

在Android项目的AndroidManifest.xml里添加必要的权限(Android 13+可以用更细分的媒体权限):

<!-- Android 10及以下用这个 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Android 13+ 用更细分的权限,用户体验更好 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

实现接口

创建Android平台的服务类,标记依赖注入:

[assembly: Dependency(typeof(AndroidMediaFileService))]
namespace YourAppName.Droid
{
    public class AndroidMediaFileService : IMediaFileService
    {
        public List<string> GetAllMediaFiles()
        {
            var mediaFiles = new List<string>();
            // 合并图片、视频、音频的结果
            mediaFiles.AddRange(GetMediaFilesByType(MediaType.Image));
            mediaFiles.AddRange(GetMediaFilesByType(MediaType.Video));
            mediaFiles.AddRange(GetMediaFilesByType(MediaType.Audio));
            return mediaFiles;
        }

        public List<string> GetMediaFilesByType(MediaType mediaType)
        {
            var files = new List<string>();
            var contentResolver = Android.App.Application.Context.ContentResolver;
            // 定义要查询的字段:文件路径、文件名
            string[] projection;
            Android.Net.Uri mediaUri;
            string sortOrder = $"{MediaStore.Images.Media.DateAdded} DESC"; // 按添加时间倒序

            switch (mediaType)
            {
                case MediaType.Image:
                    mediaUri = MediaStore.Images.Media.ExternalContentUri;
                    projection = new[] { MediaStore.Images.Media.Data, MediaStore.Images.Media.DisplayName };
                    break;
                case MediaType.Video:
                    mediaUri = MediaStore.Video.Media.ExternalContentUri;
                    projection = new[] { MediaStore.Video.Media.Data, MediaStore.Video.Media.DisplayName };
                    break;
                case MediaType.Audio:
                    mediaUri = MediaStore.Audio.Media.ExternalContentUri;
                    projection = new[] { MediaStore.Audio.Media.Data, MediaStore.Audio.Media.DisplayName };
                    break;
                default:
                    return files;
            }

            // 查询媒体库
            using (var cursor = contentResolver.Query(mediaUri, projection, null, null, sortOrder))
            {
                if (cursor != null && cursor.MoveToFirst())
                {
                    do
                    {
                        // 这里可以获取文件名或者文件路径,按需选择
                        var fileName = cursor.GetString(cursor.GetColumnIndex(projection[1]));
                        // var filePath = cursor.GetString(cursor.GetColumnIndex(projection[0]));
                        files.Add(fileName);
                    } while (cursor.MoveToNext());
                }
            }

            return files;
        }
    }
}

第三步:iOS平台的适配(可选,跨平台需要)

如果你的应用要支持iOS,同样实现接口,iOS用Photos框架来获取媒体文件:

[assembly: Dependency(typeof(IosMediaFileService))]
namespace YourAppName.iOS
{
    public class IosMediaFileService : IMediaFileService
    {
        public List<string> GetAllMediaFiles()
        {
            var mediaFiles = new List<string>();
            mediaFiles.AddRange(GetMediaFilesByType(MediaType.Image));
            mediaFiles.AddRange(GetMediaFilesByType(MediaType.Video));
            mediaFiles.AddRange(GetMediaFilesByType(MediaType.Audio));
            return mediaFiles;
        }

        public List<string> GetMediaFilesByType(MediaType mediaType)
        {
            var files = new List<string>();
            var fetchOptions = new PHFetchOptions();
            PHFetchResult fetchResult = null;

            switch (mediaType)
            {
                case MediaType.Image:
                    fetchResult = PHAsset.FetchAssets(PHAssetMediaType.Image, fetchOptions);
                    break;
                case MediaType.Video:
                    fetchResult = PHAsset.FetchAssets(PHAssetMediaType.Video, fetchOptions);
                    break;
                case MediaType.Audio:
                    fetchResult = PHAsset.FetchAssets(PHAssetMediaType.Audio, fetchOptions);
                    break;
            }

            if (fetchResult != null)
            {
                foreach (PHAsset asset in fetchResult)
                {
                    // 这里可以获取本地标识,或者进一步获取文件路径/文件名
                    files.Add(asset.LocalIdentifier);
                }
            }

            return files;
        }
    }
}

记得在iOS项目的Info.plist里添加权限描述:

<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问您的照片库来获取媒体文件</string>

第四步:在便携类库中调用服务

现在回到你的PCL/共享项目,通过依赖注入获取服务并调用:

// 获取媒体服务实例
var mediaService = DependencyService.Get<IMediaFileService>();
// 获取所有媒体文件
var allMediaFiles = mediaService.GetAllMediaFiles();
// 只获取图片
var imageFiles = mediaService.GetMediaFilesByType(MediaType.Image);

几个重要的注意点

  • 权限检查:在调用获取媒体的方法前,一定要先检查权限是否已授权。Android可以用Xamarin.Essentials的Permissions.CheckStatusAsync<Permissions.StorageRead>(),iOS则检查PHPhotoLibrary.AuthorizationStatus。
  • 性能优化:如果设备上媒体文件很多,别在主线程执行查询操作,放到后台线程(比如用Task.Run),避免UI卡顿。
  • Android Scoped Storage:直接遍历目录的方式在Android 10+会失效,用MediaStore是官方推荐的合规方案。

内容的提问来源于stack exchange,提问作者Srusti Thakkar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:25:36