diff --git a/src/Essentials/samples/Samples/Platforms/Android/AndroidManifest.xml b/src/Essentials/samples/Samples/Platforms/Android/AndroidManifest.xml
index 75eb405387d7..78eaefb7827c 100644
--- a/src/Essentials/samples/Samples/Platforms/Android/AndroidManifest.xml
+++ b/src/Essentials/samples/Samples/Platforms/Android/AndroidManifest.xml
@@ -11,6 +11,7 @@
+
diff --git a/src/Essentials/samples/Samples/Platforms/iOS/Info.plist b/src/Essentials/samples/Samples/Platforms/iOS/Info.plist
index 83bae2a68f1f..8baa6df9ac79 100644
--- a/src/Essentials/samples/Samples/Platforms/iOS/Info.plist
+++ b/src/Essentials/samples/Samples/Platforms/iOS/Info.plist
@@ -64,5 +64,9 @@
Just writing events to the Calendar, nothing to see here.
NSRemindersFullAccessUsageDescription
Just so you will remember
+ UIBackgroundModes
+
+ remote-notification
+
diff --git a/src/Essentials/src/Permissions/Permissions.ios.cs b/src/Essentials/src/Permissions/Permissions.ios.cs
index 2617b98a5263..09ea3dbe42ad 100644
--- a/src/Essentials/src/Permissions/Permissions.ios.cs
+++ b/src/Essentials/src/Permissions/Permissions.ios.cs
@@ -7,6 +7,7 @@
using CoreBluetooth;
using MediaPlayer;
using Speech;
+using UserNotifications;
namespace Microsoft.Maui.ApplicationModel
{
@@ -293,6 +294,51 @@ public override Task RequestAsync()
}
}
+ public partial class PostNotifications : BasePlatformPermission
+ {
+ ///
+ public override Task CheckStatusAsync()
+ {
+ var tcs = new TaskCompletionSource();
+
+ UNUserNotificationCenter.Current.GetNotificationSettings(settings =>
+ {
+ switch (settings.AuthorizationStatus)
+ {
+ case UNAuthorizationStatus.Authorized:
+ case UNAuthorizationStatus.Provisional:
+ case UNAuthorizationStatus.Ephemeral:
+ tcs.TrySetResult(PermissionStatus.Granted);
+ break;
+ case UNAuthorizationStatus.Denied:
+ tcs.TrySetResult(PermissionStatus.Denied);
+ break;
+ default:
+ tcs.TrySetResult(PermissionStatus.Unknown);
+ break;
+ }
+ });
+
+ return tcs.Task;
+ }
+
+ ///
+ public override async Task RequestAsync()
+ {
+ var status = await CheckStatusAsync();
+ if (status == PermissionStatus.Granted)
+ return status;
+
+ var (granted, error) = await UNUserNotificationCenter.Current.RequestAuthorizationAsync(
+ UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound);
+
+ if (error is not null)
+ return PermissionStatus.Unknown;
+
+ return granted ? PermissionStatus.Granted : PermissionStatus.Denied;
+ }
+ }
+
public partial class Speech : BasePlatformPermission
{
///
diff --git a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index a6ea2f543be2..d694af4cdb7a 100644
--- a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -5,3 +5,5 @@ override Microsoft.Maui.Devices.Sensors.LocationTypeConverter.CanConvertFrom(Sys
override Microsoft.Maui.Devices.Sensors.LocationTypeConverter.CanConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Type? destinationType) -> bool
override Microsoft.Maui.Devices.Sensors.LocationTypeConverter.ConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object! value) -> object?
override Microsoft.Maui.Devices.Sensors.LocationTypeConverter.ConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object? value, System.Type! destinationType) -> object?
+~override Microsoft.Maui.ApplicationModel.Permissions.PostNotifications.CheckStatusAsync() -> System.Threading.Tasks.Task
+~override Microsoft.Maui.ApplicationModel.Permissions.PostNotifications.RequestAsync() -> System.Threading.Tasks.Task
diff --git a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index a6ea2f543be2..d694af4cdb7a 100644
--- a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -5,3 +5,5 @@ override Microsoft.Maui.Devices.Sensors.LocationTypeConverter.CanConvertFrom(Sys
override Microsoft.Maui.Devices.Sensors.LocationTypeConverter.CanConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Type? destinationType) -> bool
override Microsoft.Maui.Devices.Sensors.LocationTypeConverter.ConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object! value) -> object?
override Microsoft.Maui.Devices.Sensors.LocationTypeConverter.ConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object? value, System.Type! destinationType) -> object?
+~override Microsoft.Maui.ApplicationModel.Permissions.PostNotifications.CheckStatusAsync() -> System.Threading.Tasks.Task
+~override Microsoft.Maui.ApplicationModel.Permissions.PostNotifications.RequestAsync() -> System.Threading.Tasks.Task
diff --git a/src/Essentials/test/DeviceTests/Tests/Permissions_Tests.cs b/src/Essentials/test/DeviceTests/Tests/Permissions_Tests.cs
index da41c2eb4367..e01ab462722a 100644
--- a/src/Essentials/test/DeviceTests/Tests/Permissions_Tests.cs
+++ b/src/Essentials/test/DeviceTests/Tests/Permissions_Tests.cs
@@ -103,5 +103,16 @@ public async Task StorageAndroid13AlwaysGranted()
Assert.Equal(PermissionStatus.Denied, status);
}
}
+
+ [Fact]
+ public async Task PostNotifications_CheckStatus_ReturnsValidStatus()
+ {
+ var status = await Permissions.CheckStatusAsync();
+ Assert.True(
+ status == PermissionStatus.Unknown ||
+ status == PermissionStatus.Granted ||
+ status == PermissionStatus.Denied,
+ $"Unexpected PostNotifications status: {status}");
+ }
}
}