mcpField
M
maui-media-picker

maui-media-picker

github.com/davidortinau開発17647 回インストール16 週間前に更新
リポジトリ

maui-media-picker について

.NET MAUI アプリにメディア選択や撮影を実装する開発者向けの Media Picker ガイドです。キャンセル、スレッド、ストリーム、プラットフォーム固有の注意点を扱います。

主な機能

  1. 01キャンセルと空の結果への対応
  2. 02UI スレッドでのピッカー呼び出し
  3. 03カメラ撮影対応の確認
  4. 04読み込みストリームの破棄
  5. 05プラットフォーム権限と選択数制限への対応

活用シーン

  1. 01単一または複数写真の選択機能の追加
  2. 02カメラ対応を確認した上での写真撮影
  3. 03Android と iOS のメディア権限設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/davidortinau/maui-skills --skill maui-media-picker

インストール後、Claude Code で/maui-media-pickerを入力して読み込まれたか確認します。

同梱ファイルreferences/media-picker-api.md

詳細

.NET MAUI メディアピッカー — 注意点とベストプラクティス

よくある間違い

1. キャンセルされたかどうかを確認しない

単一選択では null、複数選択では空のリストが返されます。確認しないと NullReferenceException が発生します。

// ❌ Crashes when user cancels
var photo = await MediaPicker.Default.PickPhotoAsync();
using var stream = await photo.OpenReadAsync();

// ✅ Always check for null / empty
var photo = await MediaPicker.Default.PickPhotoAsync();
if (photo is null) return;
using var stream = await photo.OpenReadAsync();
2. バックグラウンドスレッドから呼び出す

すべての MediaPicker メソッドは UI スレッドで実行する必要があります。そうしないと例外が発生します。

// ❌ Will throw on some platforms
await Task.Run(async () => await MediaPicker.Default.PickPhotoAsync());

// ✅ Call directly from a command or event handler on the UI thread
var photo = await MediaPicker.Default.PickPhotoAsync();
3. IsCaptureSupported を確認しない

カメラのないデバイス(エミュレーターや一部のタブレット)で撮影メソッドを呼び出すと、例外が発生します。

// ❌ Crashes on devices without a camera
var photo = await MediaPicker.Default.CapturePhotoAsync();

// ✅ Guard with capability check
if (MediaPicker.Default.IsCaptureSupported)
{
    var photo = await MediaPicker.Default.CapturePhotoAsync();
}
4. ストリームを破棄しない

OpenReadAsync() は、破棄する必要があるストリームを返します。

// ❌ Leaks the stream
var stream = await photo.OpenReadAsync();
var bytes = ReadAllBytes(stream);

// ✅ Dispose with using
using var stream = await photo.OpenReadAsync();

プラットフォーム固有の注意点

⚠️ Android/Windows では SelectionLimit が適用されません

MediaPickerOptions.SelectionLimit は参考値です。必ず自分で件数を検証してください。

var options = new MediaPickerOptions { SelectionLimit = 5 };
var results = await MediaPicker.Default.PickPhotosAsync(options);
if (results.Count() > 5)
{
    // Warn user or take only the first 5
    results = results.Take(5);
}
⚠️ Android のストレージ権限は API 33 で分かれます
  • API ≤ 32:READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE が必要です
  • API ≥ 33:READ_MEDIA_IMAGES/READ_MEDIA_VIDEO が必要です(広範なストレージ権限は無視されます)
  • Play ストアの警告を避けるため、古い権限には android:maxSdkVersion="32" を指定してください
⚠️ iOS で完全な機能を使うには plist キーが4つすべて必要です

NSCameraUsageDescription、NSMicrophoneUsageDescription、 NSPhotoLibraryUsageDescription、NSPhotoLibraryAddUsageDescription のいずれかが欠けていると、 その機能にアクセスした際に実行時クラッシュが発生します。

⚠️ Android ではカメラのインテントに <queries> が必要です

AndroidManifest.xml に IMAGE_CAPTURE のクエリがないと、パッケージの可視性制限により、Android 11 以降で CapturePhotoAsync が何も表示せずに失敗する場合があります。

判断基準

シナリオメソッド
ユーザーが写真を1枚選択するPickPhotoAsync()
ユーザーが複数の写真を選択する(.NET 10 以降)SelectionLimit を指定して PickPhotosAsync()
アプリでカメラ撮影が必要IsCaptureSupported を確認 → CapturePhotoAsync()
選択したファイルを永続的に保存するストリームを FileSystem.AppDataDirectory にコピーする
写真のメタデータが必要MediaPickerOptions で PreserveMetaData = true を設定する

チェックリスト

  • すべてのピッカー呼び出しを UI スレッドで実行する
  • 選択/撮影の呼び出し後に毎回 null/空の値を確認する
  • 撮影メソッドの前に IsCaptureSupported でガードする
  • ストリームを using で破棄する
  • Android マニフェストに maxSdkVersion を指定した新旧両方のストレージ権限がある
  • Android マニフェストにカメラインテント用の <queries> ブロックがある
  • iOS の Info.plist に使用目的を説明するキーが4つすべてある
  • プラットフォームの値をそのまま信頼せず、コード内で SelectionLimit を検証する

コメント