maui-local-notifications について
.NET MAUI でローカル通知を追加する開発者向けの実装ガイドです。サービス設計、プラットフォーム別の設定と注意点、Windows のスケジュール制限をまとめています。
主な機能
- 01クロスプラットフォーム通知サービスの設計
- 02Android の権限とチャネル設定
- 03Android 再起動後の通知再スケジュール
- 04iOS と Mac Catalyst のフォアグラウンド通知処理
- 05Windows の通知スケジュール制限
活用シーン
- 01即時ローカル通知を実装
- 02Android 再起動後も維持するリマインダーを設定
- 03通知権限やフォアグラウンド表示の問題を調査
- 04各プラットフォームの機能に沿って通知を計画
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ davidortinau/ maui-skills --skill maui-local-notificationsインストール後、Claude Code で/maui-local-notificationsを入力して読み込まれたか確認します。
同梱ファイルreferences/local-notifications-api.md
詳細
.NET MAUI ローカル通知
実装の概要
- クロスプラットフォームの
INotificationManagerServiceインターフェイスとイベント引数を定義します - Android 通知サービスを実装します(チャネル、AlarmManager、BroadcastReceiver)
- iOS/Mac Catalyst 通知サービスを実装します(UNUserNotificationCenter)
- DI を介してプラットフォームごとの実装を登録します
- プラットフォームの権限と MainActivity を設定します
実装コード全体については、references/local-notifications-api.md を参照してください。
プラットフォーム固有の注意点
Android
| 問題 | 対処方法 |
|---|---|
| API 33 以降で通知が何も表示されずに失敗する | 先に POST_NOTIFICATIONS の実行時権限をリクエストする必要があります |
Android 12 以降で PendingIntent がクラッシュする | API 31 以降では PendingIntentFlags.Immutable を含める必要があります |
| スケジュール済み通知が再起動後に失われる | AlarmManager はデバイスの再起動後に保持されません。BOOT_COMPLETED レシーバーを介して再起動時に再スケジュールしてください |
| 通知が表示されない | 通知チャネルが作成されていません。API 26 以降(Android 8.0)では必須です |
| 通知をタップしてもアプリに戻らない | MainActivity に LaunchMode = LaunchMode.SingleTop を設定する必要があります |
// ✅ Correct — API 31+ requires Immutable flag
var pendingIntentFlags = (Build.VERSION.SdkInt >= BuildVersionCodes.S)
? PendingIntentFlags.CancelCurrent | PendingIntentFlags.Immutable
: PendingIntentFlags.CancelCurrent;
// ❌ Wrong — crashes on Android 12+
var pendingIntentFlags = PendingIntentFlags.CancelCurrent;
iOS/Mac Catalyst
| 問題 | 対処方法 |
|---|---|
| 通知の許可ダイアログが表示されない | すでに許可が拒否されています。ユーザーが設定で再度有効にする必要があります |
| フォアグラウンドで通知が表示されない | UNUserNotificationCenterDelegate を実装し、Current.Delegate を設定する必要があります |
通知が Banner ではなく Alert として表示される | iOS 14 以降では UNNotificationPresentationOptions.Banner を使用します |
// ✅ iOS 14+ — use Banner
completionHandler(OperatingSystem.IsIOSVersionAtLeast(14)
? UNNotificationPresentationOptions.Banner
: UNNotificationPresentationOptions.Alert);
// ❌ Always using Alert — deprecated on iOS 14+
completionHandler(UNNotificationPresentationOptions.Alert);
Windows
⚠️ Windows App SDK はトースト通知をサポートしていますが、スケジュール済み通知はまだサポートされていません。即時通知は機能します。
DI 登録 — プラットフォーム固有のみ
// ✅ Must use #if guards — there's no cross-platform implementation
#if ANDROID
builder.Services.AddTransient<INotificationManagerService,
Platforms.Android.NotificationManagerService>();
#elif IOS
builder.Services.AddTransient<INotificationManagerService,
Platforms.iOS.NotificationManagerService>();
#elif MACCATALYST
builder.Services.AddTransient<INotificationManagerService,
Platforms.MacCatalyst.NotificationManagerService>();
#endif
よくあるアンチパターン
// ❌ Sending without checking permission — silent failure on API 33+
notificationManager.SendNotification("Title", "Body");
// ✅ Request permission first
#if ANDROID
var status = await Permissions.RequestAsync<Platforms.Android.NotificationPermission>();
if (status != PermissionStatus.Granted) return;
#endif
// ❌ Updating UI directly from notification callback — cross-thread exception
notificationManager.NotificationReceived += (s, e) =>
myLabel.Text = ((NotificationEventArgs)e).Title;
// ✅ Marshal to UI thread
notificationManager.NotificationReceived += (s, e) =>
MainThread.BeginInvokeOnMainThread(() =>
myLabel.Text = ((NotificationEventArgs)e).Title);
選択の指針
| 要件 | 方法 |
|---|---|
| 即時通知 | null の notifyTime を指定して SendNotification(title, message) を呼び出します |
| スケジュール済みリマインダー | SendNotification(title, message, DateTime.Now.AddMinutes(30)) を呼び出します |
| 再起動後も保持する(Android) | アラームを再スケジュールする BOOT_COMPLETED レシーバーを追加します |
| リッチ通知(画像、アクション) | ネイティブ API を使用してプラットフォームごとの実装を拡張します |
| サーバーからのプッシュ通知 | 別の方法(FCM/APNs)を使用します |
クイックチェックリスト
- クロスプラットフォームの
INotificationManagerServiceインターフェイスを定義した - Android:通知チャネルを作成した(API 26 以降)
- Android:マニフェストに
POST_NOTIFICATIONS権限を設定し、実行時にリクエストする(API 33 以降) - Android:
PendingIntentFlags.Immutableを使用した(API 31 以降) - Android:
MainActivityにLaunchMode.SingleTopを設定し、OnNewIntentを処理する - iOS:フォアグラウンド表示用に
UNUserNotificationCenterDelegateを設定した - iOS:iOS 14 以降では
Alertの代わりにBannerを使用した - DI 登録で
#ifによるプラットフォーム判定を使用した - 通知コールバックから UI を更新する際に
MainThread.BeginInvokeOnMainThreadを使用した
コメント
Markdown 対応