maui-media-picker

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

.NET MAUI Media Picker Skill

.NET MAUI Media Picker 使用指南

Core API

核心API

Use
MediaPicker.Default
to pick or capture photos and videos. All methods must run on the UI thread.
使用
MediaPicker.Default
来选择或拍摄照片和视频。所有方法必须在UI线程上运行。

Single-select methods (all .NET versions)

单选方法(所有.NET版本)

MethodPurpose
MediaPicker.Default.PickPhotoAsync()
Pick one photo from gallery
MediaPicker.Default.PickVideoAsync()
Pick one video from gallery
MediaPicker.Default.CapturePhotoAsync()
Capture a photo with the camera
MediaPicker.Default.CaptureVideoAsync()
Capture a video with the camera
All return
Task<FileResult?>
. A null result means the user cancelled.
方法用途
MediaPicker.Default.PickPhotoAsync()
从相册选择一张照片
MediaPicker.Default.PickVideoAsync()
从相册选择一段视频
MediaPicker.Default.CapturePhotoAsync()
使用相机拍摄一张照片
MediaPicker.Default.CaptureVideoAsync()
使用相机拍摄一段视频
所有方法返回
Task<FileResult?>
。返回null表示用户已取消操作。

Multi-select methods (.NET 10+)

多选方法(.NET 10及以上版本)

MethodPurpose
MediaPicker.Default.PickPhotosAsync()
Pick multiple photos
MediaPicker.Default.PickVideosAsync()
Pick multiple videos
These return
Task<IEnumerable<FileResult>>
. An empty list means the user cancelled.
方法用途
MediaPicker.Default.PickPhotosAsync()
选择多张照片
MediaPicker.Default.PickVideosAsync()
选择多段视频
这些方法返回
Task<IEnumerable<FileResult>>
。返回空列表表示用户已取消操作。

MediaPickerOptions (.NET 10+)

MediaPickerOptions(.NET 10及以上版本)

Pass
MediaPickerOptions
to any pick/capture method to control behavior:
csharp
var options = new MediaPickerOptions
{
    Title = "Select photos",        // Picker dialog title
    SelectionLimit = 5,             // Max items (0 = unlimited; multi-select only)
    MaximumWidth = 1024,            // Resize max width in pixels
    MaximumHeight = 1024,           // Resize max height in pixels
    CompressionQuality = 80,       // JPEG quality 0–100
    RotateImage = true,             // Auto-rotate per EXIF
    PreserveMetaData = true         // Keep EXIF/metadata
};

var photos = await MediaPicker.Default.PickPhotosAsync(options);
Platform note: Android and Windows may not enforce
SelectionLimit
. Always validate the count in your code.
MediaPickerOptions
传递给任何选择/拍摄方法以控制行为:
csharp
var options = new MediaPickerOptions
{
    Title = "Select photos",        // Picker dialog title
    SelectionLimit = 5,             // Max items (0 = unlimited; multi-select only)
    MaximumWidth = 1024,            // Resize max width in pixels
    MaximumHeight = 1024,           // Resize max height in pixels
    CompressionQuality = 80,       // JPEG quality 0–100
    RotateImage = true,             // Auto-rotate per EXIF
    PreserveMetaData = true         // Keep EXIF/metadata
};

var photos = await MediaPicker.Default.PickPhotosAsync(options);
平台说明: Android和Windows可能不强制执行
SelectionLimit
。请始终在代码中验证返回数量。

FileResult usage

FileResult 使用

csharp
var photo = await MediaPicker.Default.PickPhotoAsync();
if (photo is null)
    return; // user cancelled

// Read the stream
using var stream = await photo.OpenReadAsync();

// Useful properties
string fullPath    = photo.FullPath;
string fileName    = photo.FileName;
string contentType = photo.ContentType;
csharp
var photo = await MediaPicker.Default.PickPhotoAsync();
if (photo is null)
    return; // user cancelled

// Read the stream
using var stream = await photo.OpenReadAsync();

// Useful properties
string fullPath    = photo.FullPath;
string fileName    = photo.FileName;
string contentType = photo.ContentType;

Save to app storage

保存到应用存储

csharp
async Task<string> SaveToAppDataAsync(FileResult fileResult)
{
    var targetPath = Path.Combine(FileSystem.AppDataDirectory, fileResult.FileName);
    using var sourceStream = await fileResult.OpenReadAsync();
    using var targetStream = File.OpenWrite(targetPath);
    await sourceStream.CopyToAsync(targetStream);
    return targetPath;
}
csharp
async Task<string> SaveToAppDataAsync(FileResult fileResult)
{
    var targetPath = Path.Combine(FileSystem.AppDataDirectory, fileResult.FileName);
    using var sourceStream = await fileResult.OpenReadAsync();
    using var targetStream = File.OpenWrite(targetPath);
    await sourceStream.CopyToAsync(targetStream);
    return targetPath;
}

Platform permissions

平台权限

Android

Android

Add to
Platforms/Android/AndroidManifest.xml
:
xml
<!-- Camera capture -->
<uses-permission android:name="android.permission.CAMERA" />

<!-- Storage: API ≤ 32 (Android 12 and below) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
                 android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                 android:maxSdkVersion="32" />

<!-- Storage: API ≥ 33 (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" />
Also add inside
<application>
:
xml
<queries>
    <intent>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
    </intent>
</queries>
添加以下内容到
Platforms/Android/AndroidManifest.xml
xml
<!-- Camera capture -->
<uses-permission android:name="android.permission.CAMERA" />

<!-- Storage: API ≤ 32 (Android 12 and below) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
                 android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                 android:maxSdkVersion="32" />

<!-- Storage: API ≥ 33 (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" />
同时在
<application>
标签内添加:
xml
<queries>
    <intent>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
    </intent>
</queries>

iOS / Mac Catalyst

iOS / Mac Catalyst

Add to
Platforms/iOS/Info.plist
(and
Platforms/MacCatalyst/Info.plist
):
xml
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to take photos</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access to record video</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to pick media</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs permission to save photos</string>
添加以下内容到
Platforms/iOS/Info.plist
(以及
Platforms/MacCatalyst/Info.plist
):
xml
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to take photos</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access to record video</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to pick media</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs permission to save photos</string>

Windows

Windows

No additional permissions required.
无需额外权限。

Check availability before capture

拍摄前检查可用性

csharp
if (MediaPicker.Default.IsCaptureSupported)
{
    var photo = await MediaPicker.Default.CapturePhotoAsync();
    // ...
}
csharp
if (MediaPicker.Default.IsCaptureSupported)
{
    var photo = await MediaPicker.Default.CapturePhotoAsync();
    // ...
}

Multi-select example (.NET 10+)

多选示例(.NET 10及以上版本)

csharp
var options = new MediaPickerOptions { SelectionLimit = 10 };
var results = await MediaPicker.Default.PickPhotosAsync(options);

if (!results.Any())
    return; // user cancelled

foreach (var file in results)
{
    using var stream = await file.OpenReadAsync();
    // process each selected photo
}
csharp
var options = new MediaPickerOptions { SelectionLimit = 10 };
var results = await MediaPicker.Default.PickPhotosAsync(options);

if (!results.Any())
    return; // user cancelled

foreach (var file in results)
{
    using var stream = await file.OpenReadAsync();
    // process each selected photo
}

Key rules

关键规则

  • Always call media picker methods on the main/UI thread.
  • Single-select cancellation returns null; multi-select returns an empty list.
  • Use
    IsCaptureSupported
    before calling capture methods.
  • Android/Windows may ignore
    SelectionLimit
    — validate result count yourself.
  • OpenReadAsync()
    gives a stream; dispose it when done.
  • Save files to
    FileSystem.AppDataDirectory
    for persistent app-local storage.
  • 始终在主线程/UI线程上调用媒体选择器方法。
  • 单选操作取消返回null;多选操作取消返回空列表
  • 调用拍摄方法前请使用
    IsCaptureSupported
    检查可用性。
  • Android/Windows可能会忽略
    SelectionLimit
    ——请自行验证结果数量。
  • OpenReadAsync()
    返回一个流;使用完毕后请释放它。
  • 将文件保存到
    FileSystem.AppDataDirectory
    以获得持久的应用本地存储。