基于位置的触发器
每个平台都需要自己的本机代码实现来发送和接收本地通知。 但是,每个平台实现都可以在跨平台层进行抽象化,以便在 .NET 多平台应用 UI (.NET MAUI) 应用中发送和接收本地通知有一致的 API。
.NET MAUI 应用应发送和接收本地通知,而无需担心基础平台实现。 以下
INotificationManagerService
接口用于定义可用于与本地通知交互的跨平台 API:
public interface INotificationManagerService
event EventHandler NotificationReceived;
void SendNotification(string title, string message, DateTime? notifyTime = null);
void ReceiveNotification(string title, string message);
此接口定义以下操作:
NotificationReceived
事件允许应用处理传入通知。
SendNotification
方法会在可选 DateTime
发送通知。
ReceiveNotification
方法会在基础平台收到通知时,对其进行处理。
应在想要支持本地通知的每个平台上实现该接口。
在 Android 上实现本地通知
在 Android 上的本地通知是在应用的 UI 外部显示的消息,用于提供应用中的提醒或其他信息。 用户可以点击该通知以打开应用,也可以选择直接从通知执行操作。 有关 Android 上的本地通知的信息,请参阅 developer.android.com 上的通知概述。
若要使 .NET MAUI 应用在 Android 上发送和接收通知,应用必须提供 INotificationManagerService
接口的实现。
发送和接收本地通知
在 Android 上,NotificationManagerService
类会实现 INotificationManagerService
接口,并包含用于发送和接收本地通知的逻辑:
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using AndroidX.Core.App;
namespace LocalNotificationsDemo.Platforms.Android;
public class NotificationManagerService : INotificationManagerService
const string channelId = "default";
const string channelName = "Default";
const string channelDescription = "The default channel for notifications.";
public const string TitleKey = "title";
public const string MessageKey = "message";
bool channelInitialized = false;
int messageId = 0;
int pendingIntentId = 0;
NotificationManagerCompat compatManager;
public event EventHandler NotificationReceived;
public static NotificationManagerService Instance { get; private set; }
public NotificationManagerService()
if (Instance == null)
CreateNotificationChannel();
compatManager = NotificationManagerCompat.From(Platform.AppContext);
Instance = this;
public void SendNotification(string title, string message, DateTime? notifyTime = null)
if (!channelInitialized)
CreateNotificationChannel();
if (notifyTime != null)
Intent intent = new Intent(Platform.AppContext, typeof(AlarmHandler));
intent.PutExtra(TitleKey, title);
intent.PutExtra(MessageKey, message);
intent.SetFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTop);
var pendingIntentFlags = (Build.VERSION.SdkInt >= BuildVersionCodes.S)
? PendingIntentFlags.CancelCurrent | PendingIntentFlags.Immutable
: PendingIntentFlags.CancelCurrent;
PendingIntent pendingIntent = PendingIntent.GetBroadcast(Platform.AppContext, pendingIntentId++, intent, pendingIntentFlags);
long triggerTime = GetNotifyTime(notifyTime.Value);
AlarmManager alarmManager = Platform.AppContext.GetSystemService(Context.AlarmService) as AlarmManager;
alarmManager.Set(AlarmType.RtcWakeup, triggerTime, pendingIntent);
Show(title, message);
public void ReceiveNotification(string title, string message)
var args = new NotificationEventArgs()
Title = title,
Message = message,
NotificationReceived?.Invoke(null, args);
public void Show(string title, string message)
Intent intent = new Intent(Platform.AppContext, typeof(MainActivity));
intent.PutExtra(TitleKey, title);
intent.PutExtra(MessageKey, message);
intent.SetFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTop);
var pendingIntentFlags = (Build.VERSION.SdkInt >= BuildVersionCodes.S)
? PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable
: PendingIntentFlags.UpdateCurrent;
PendingIntent pendingIntent = PendingIntent.GetActivity(Platform.AppContext, pendingIntentId++, intent, pendingIntentFlags);
NotificationCompat.Builder builder = new NotificationCompat.Builder(Platform.AppContext, channelId)
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetLargeIcon(BitmapFactory.DecodeResource(Platform.AppContext.Resources, Resource.Drawable.dotnet_logo))
.SetSmallIcon(Resource.Drawable.message_small);
Notification notification = builder.Build();
compatManager.Notify(messageId++, notification);
void CreateNotificationChannel()
// Create the notification channel, but only on API 26+.
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
var channelNameJava = new Java.Lang.String(channelName);
var channel = new NotificationChannel(channelId, channelNameJava, NotificationImportance.Default)
Description = channelDescription
// Register the channel
NotificationManager manager = (NotificationManager)Platform.AppContext.GetSystemService(Context.NotificationService);
manager.CreateNotificationChannel(channel);
channelInitialized = true;
long GetNotifyTime(DateTime notifyTime)
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(notifyTime);
double epochDiff = (new DateTime(1970, 1, 1) - DateTime.MinValue).TotalSeconds;
long utcAlarmTime = utcTime.AddSeconds(-epochDiff).Ticks / 10000;
return utcAlarmTime; // milliseconds
NotificationManagerService
类应放置在应用的“平台 > Android”文件夹中。 或者,可以根据自己的文件名和文件夹条件执行多目标,而不是使用“平台 > Android”文件夹。 有关详细信息,请参阅配置多目标。
Android 允许应用为通知定义多个通道。 NotificationManagerService
构造函数会创建用于发送通知的基本通道。 SendNotification
方法定义创建和发送通知所需的特定于平台的逻辑。 当收到消息并调用 NotificationReceived
事件处理程序时,Android OS 将调用 ReceiveNotification
方法。 有关详细信息,请参阅 developer.android.com 上的创建通知。
SendNotification
方法立即或在准确的 DateTime
创建一个本地通知。 可以使用 AlarmManager
类为准确的 DateTime
安排一个通知,且该通知将由从 BroadcastReceiver
类派生的对象接收:
[BroadcastReceiver(Enabled = true, Label = "Local Notifications Broadcast Receiver")]
public class AlarmHandler : BroadcastReceiver
public override void OnReceive(Context context, Intent intent)
if (intent?.Extras != null)
string title = intent.GetStringExtra(NotificationManagerService.TitleKey);
string message = intent.GetStringExtra(NotificationManagerService.MessageKey);
NotificationManagerService manager = NotificationManagerService.Instance ?? new NotificationManagerService();
manager.Show(title, message);
默认情况下,使用 AlarmManager
类计划的通知在设备重启后不会得到保留。 但是,可以将应用设计为在重启设备时自动重新计划通知。 有关详细信息,请参阅 developer.android.com 上的安排重复警报中的当设备重新启动时启动警报。 有关 Android 上后台处理的信息,请参阅 developer.android.com 上的后台处理指南。
处理传入通知
Android 应用必须检测传入通知并通知 NotificationManagerService
实例。 实现此目标的一种方法是修改 MainActivity
类。
MainActivity
类上的 Activity
属性应指定 LaunchMode.SingleTop
的 LaunchMode
值:
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, //... )]
public class MainActivity : MauiAppCompatActivity
SingleTop
模式可防止在应用处于前台时启动 Activity
的多个实例。 此 LaunchMode
可能不适合在更复杂的通知方案中启动了多个活动的应用。 有关 LaunchMode
枚举值的详细信息,请参阅 developer.android.com 上的 Android Activity LaunchMode。
还需要修改 MainActivity
类才能接收传入通知:
public class MainActivity : MauiAppCompatActivity
protected override void OnCreate(Bundle? savedInstanceState)
base.OnCreate(savedInstanceState);
CreateNotificationFromIntent(Intent);
protected override void OnNewIntent(Intent? intent)
base.OnNewIntent(intent);
CreateNotificationFromIntent(intent);
static void CreateNotificationFromIntent(Intent intent)
if (intent?.Extras != null)
string title = intent.GetStringExtra(LocalNotificationsDemo.Platforms.Android.NotificationManagerService.TitleKey);
string message = intent.GetStringExtra(LocalNotificationsDemo.Platforms.Android.NotificationManagerService.MessageKey);
var service = IPlatformApplication.Current.Services.GetService<INotificationManagerService>();
service.ReceiveNotification(title, message);
CreateNotificationFromIntent
方法会从 intent
参数中提取通知数据,并将其传递给 NotificationManagerService
类中的 ReceiveNotification
方法。 CreateNotificationFromIntent
方法是从 OnCreate
方法和 OnNewIntent
方法中调用的:
当应用通过通知数据启动时,会向 OnCreate
方法传递 Intent
数据。
如果应用已在前台,则 Intent
数据将传递给 OnNewIntent
方法。
Android 13 (API 33) 及更高版本需要 POST_NOTIFICATIONS
权限才能从应用发送通知。 应在 AndroidManifest.xml 文件中声明此权限:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
有关 POST_NOTIFICATIONS
权限的详细信息,请参阅 developer.android.com 上的通知运行时权限。
应实现在运行时检查权限声明的权限类:
using Android;
namespace LocalNotificationsDemo.Platforms.Android;
public class NotificationPermission : Permissions.BasePlatformPermission
public override (string androidPermission, bool isRuntime)[] RequiredPermissions
var result = new List<(string androidPermission, bool isRuntime)>();
if (OperatingSystem.IsAndroidVersionAtLeast(33))
result.Add((Manifest.Permission.PostNotifications, true));
return result.ToArray();
应用启动后,应在尝试发送本地通知之前请求用户授予此权限:
PermissionStatus status = await Permissions.RequestAsync<NotificationPermission>();
有关 .NET MAUI 权限的详细信息,请参阅“权限”。
在 iOS 和 Mac Catalyst 上实现本地通知
在 Apple 平台上,本地通知是向用户传达重要信息的消息。 系统会根据指定的时间或位置处理通知的传递。 有关 Apple 平台上的本地通知的信息,请参阅 developer.apple.com 上的从应用进行本地通知计划。
若要使 .NET MAUI 应用在 Apple 平台上发送和接收通知,应用必须提供 INotificationManagerService
接口的实现。
发送和接收本地通知
在 Apple 平台上,NotificationManagerService
类会实现 INotificationManagerService
接口,并包含用于发送和接收本地通知的逻辑:
using Foundation;
using UserNotifications;
namespace LocalNotificationsDemo.Platforms.iOS;
public class NotificationManagerService : INotificationManagerService
int messageId = 0;
bool hasNotificationsPermission;
public event EventHandler? NotificationReceived;
public NotificationManagerService()
// Create a UNUserNotificationCenterDelegate to handle incoming messages.
UNUserNotificationCenter.Current.Delegate = new NotificationReceiver();
// Request permission to use local notifications.
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err) =>
hasNotificationsPermission = approved;
public void SendNotification(string title, string message, DateTime? notifyTime = null)
// App doesn't have permissions.
if (!hasNotificationsPermission)
return;
messageId++;
var content = new UNMutableNotificationContent()
Title = title,
Subtitle = "",
Body = message,
Badge = 1
UNNotificationTrigger trigger;
if (notifyTime != null)
// Create a calendar-based trigger.
trigger = UNCalendarNotificationTrigger.CreateTrigger(GetNSDateComponents(notifyTime.Value), false);
// Create a time-based trigger, interval is in seconds and must be greater than 0.
trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(0.25, false);
var request = UNNotificationRequest.FromIdentifier(messageId.ToString(), content, trigger);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
if (err != null)
throw new Exception($"Failed to schedule notification: {err}");
public void ReceiveNotification(string title, string message)
var args = new NotificationEventArgs()
Title = title,
Message = message
NotificationReceived?.Invoke(null, args);
NSDateComponents GetNSDateComponents(DateTime dateTime)
return new NSDateComponents
Month = dateTime.Month,
Day = dateTime.Day,
Year = dateTime.Year,
Hour = dateTime.Hour,
Minute = dateTime.Minute,
Second = dateTime.Second
NotificationManagerService
类应放置在应用的“平台 > iOS”或“平台 > Mac Catalyst”文件夹中。 或者,可以根据自己的文件名和文件夹条件执行多目标,而不是使用“平台”文件夹。 有关详细信息,请参阅配置多目标。
在 Apple 平台上,在尝试计划通知之前,必须先请求使用通知的权限。 这发生在 NotificationManagerService
构造函数中。 有关本地通知权限的详细信息,请参阅 developer.apple.com 上的“请求使用通知的权限”。
SendNotification
方法定义了创建和发送通知所需的逻辑,并使用 UNTimeIntervalNotificationTrigger
对象或使用 UNCalendarNotificationTrigger
对象的确切 DateTime
来创建即时本地通知。 当收到消息并调用 NotificationReceived
事件处理程序时,iOS 将调用 ReceiveNotification
方法。
处理传入通知
在 Apple 平台上,若要处理传入的消息,就必须创建子类化了 UNUserNotificationCenterDelegate
的委托:
using UserNotifications;
namespace LocalNotificationsDemo.Platforms.iOS;
public class NotificationReceiver : UNUserNotificationCenterDelegate
// Called if app is in the foreground.
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
ProcessNotification(notification);
var presentationOptions = (OperatingSystem.IsIOSVersionAtLeast(14))
? UNNotificationPresentationOptions.Banner
: UNNotificationPresentationOptions.Alert;
completionHandler(presentationOptions);
// Called if app is in the background, or killed state.
public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
if (response.IsDefaultAction)
ProcessNotification(response.Notification);
completionHandler();
void ProcessNotification(UNNotification notification)
string title = notification.Request.Content.Title;
string message = notification.Request.Content.Body;
var service = IPlatformApplication.Current?.Services.GetService<INotificationManagerService>();
service?.ReceiveNotification(title, message);
NotificationReceiver
类在 NotificationManagerService
构造函数中注册为 UNUserNotificationCenter
委托,并向 NotificationManagerService
类中的 ReceiveNotification
方法提供传入通知数据。
在 Windows 上实现本地通知
Windows 应用 SDK 中的本地通知是指当用户当前不在你的应用程序中时,你的应用程序可以向其发送的消息。 通知内容显示在屏幕右下角和通知中心的临时窗口中。 本地通知可用于通知用户应用的状态,或提示用户采取措施。
有关 Windows 上的本地通知的信息,包括打包和解压缩应用的实现详细信息,请参阅“应用通知概述”。
应针对 INotificationManagerService
接口注册每个 NotificationManagerService
实现,以便可以从跨平台代码调用接口公开的操作。 为此,可以在 MauiProgram
类的 CreateMauiApp
方法中向 MauiAppBuilder 对象的 Services 属性注册类型:
#if ANDROID
builder.Services.AddTransient<INotificationManagerService, LocalNotificationsDemo.Platforms.Android.NotificationManagerService>();
#elif IOS
builder.Services.AddTransient<INotificationManagerService, LocalNotificationsDemo.Platforms.iOS.NotificationManagerService>();
#elif MACCATALYST
builder.Services.AddTransient<INotificationManagerService, LocalNotificationsDemo.Platforms.MacCatalyst.NotificationManagerService>();
#elif WINDOWS
builder.Services.AddTransient<INotificationManagerService, LocalNotificationsDemo.Platforms.Windows.NotificationManagerService>();
#endif
有关 .NET MAUI 中依赖项注入的详细信息,请参阅依赖项注入。
发送和接收本地通知
可以通过自动依赖项解析或显式依赖项解析来解析 INotificationManagerService
实现。 以下示例演示如何使用显式依赖项解析来解析 INotificationManagerService
实现:
// Assume the app uses a single window.
INotificationManagerService notificationManager =
Application.Current?.Windows[0].Page?.Handler?.MauiContext?.Services.GetService<INotificationManagerService>();
有关解析已注册类型的详细信息,请参阅“解析”。
解析 INotificationManagerService
实现后,即可调用其操作:
// Send
notificationManager.SendNotification();
// Scheduled send
notificationManager.SendNotification("Notification title goes here", "Notification messages goes here.", DateTime.Now.AddSeconds(10));
// Receive
notificationManager.NotificationReceived += (sender, eventArgs) =>
var eventData = (NotificationEventArgs)eventArgs;
MainThread.BeginInvokeOnMainThread(() =>
// Take required action in the app once the notification has been received.
NotificationReceived
事件处理程序会将其事件参数强制转换为 NotificationEventArgs
,该参数定义了 Title
和 Message
属性:
public class NotificationEventArgs : EventArgs
public string Title { get; set; }
public string Message { get; set; }
在 Android 上,当发送通知时,它会显示为状态栏中的图标:
在状态栏上向下轻扫时,通知抽屉将打开:
点击通知会启动应用。 通知在抽屉中仍会可见,直到应用或用户将其消除。
在 iOS 上,传入通知会由应用自动接收,无需要求用户输入: