diff --git a/Source/Plugin.LocalNotification/Apple/ApplePlatform.cs b/Source/Plugin.LocalNotification/Apple/ApplePlatform.cs new file mode 100644 index 0000000..7a3dcd2 --- /dev/null +++ b/Source/Plugin.LocalNotification/Apple/ApplePlatform.cs @@ -0,0 +1,57 @@ +#if IOS || MACCATALYST +using System.Runtime.Versioning; + +namespace Plugin.LocalNotification; + +internal static class ApplePlatform +{ + internal static bool IsCurrent() => +#if IOS + OperatingSystem.IsIOS(); +#else + OperatingSystem.IsMacCatalyst(); +#endif + +#if IOS + [SupportedOSPlatformGuard("ios11.0")] +#else + [SupportedOSPlatformGuard("maccatalyst11.0")] +#endif + internal static bool IsVersion11OrLater() => IsVersionAtLeast(11); + +#if IOS + [SupportedOSPlatformGuard("ios12.0")] +#else + [SupportedOSPlatformGuard("maccatalyst12.0")] +#endif + internal static bool IsVersion12OrLater() => IsVersionAtLeast(12); + +#if IOS + [SupportedOSPlatformGuard("ios14.0")] +#else + [SupportedOSPlatformGuard("maccatalyst14.0")] +#endif + internal static bool IsVersion14OrLater() => IsVersionAtLeast(14); + +#if IOS + [SupportedOSPlatformGuard("ios15.0")] +#else + [SupportedOSPlatformGuard("maccatalyst15.0")] +#endif + internal static bool IsVersion15OrLater() => IsVersionAtLeast(15); + +#if IOS + [SupportedOSPlatformGuard("ios16.0")] +#else + [SupportedOSPlatformGuard("maccatalyst16.0")] +#endif + internal static bool IsVersion16OrLater() => IsVersionAtLeast(16); + + private static bool IsVersionAtLeast(int majorVersion) => +#if IOS + OperatingSystem.IsIOSVersionAtLeast(majorVersion); +#else + OperatingSystem.IsMacCatalystVersionAtLeast(majorVersion); +#endif +} +#endif diff --git a/Source/Plugin.LocalNotification/Platforms/MacCatalyst/LocalNotificationCenter.cs b/Source/Plugin.LocalNotification/Apple/LocalNotificationCenter.cs similarity index 96% rename from Source/Plugin.LocalNotification/Platforms/MacCatalyst/LocalNotificationCenter.cs rename to Source/Plugin.LocalNotification/Apple/LocalNotificationCenter.cs index 5d97c40..b4d4dc4 100644 --- a/Source/Plugin.LocalNotification/Platforms/MacCatalyst/LocalNotificationCenter.cs +++ b/Source/Plugin.LocalNotification/Apple/LocalNotificationCenter.cs @@ -1,4 +1,5 @@ -using Foundation; +#if IOS || MACCATALYST +using Foundation; using Plugin.LocalNotification.Core; using Plugin.LocalNotification.Core.Models; using Plugin.LocalNotification.Platforms; @@ -72,7 +73,7 @@ public static void ResetApplicationIconBadgeNumber(UIApplication uiApplication) uiApplication.InvokeOnMainThread(() => { - if (OperatingSystem.IsMacCatalystVersionAtLeast(16)) + if (ApplePlatform.IsVersion16OrLater()) { UNUserNotificationCenter.Current.SetBadgeCount(0, (error) => { @@ -115,7 +116,7 @@ public static async Task ResetApplicationIconBadgeNumberAsync(UIApplication uiAp uiApplication.InvokeOnMainThread(async () => { - if (OperatingSystem.IsMacCatalystVersionAtLeast(16)) + if (ApplePlatform.IsVersion16OrLater()) { await UNUserNotificationCenter.Current.SetBadgeCountAsync(0); } @@ -132,4 +133,5 @@ public static async Task ResetApplicationIconBadgeNumberAsync(UIApplication uiAp throw; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Source/Plugin.LocalNotification/Platforms/iOS/NotificationServiceImpl.cs b/Source/Plugin.LocalNotification/Apple/NotificationServiceImpl.cs similarity index 96% rename from Source/Plugin.LocalNotification/Platforms/iOS/NotificationServiceImpl.cs rename to Source/Plugin.LocalNotification/Apple/NotificationServiceImpl.cs index 12064e5..3f7f01b 100644 --- a/Source/Plugin.LocalNotification/Platforms/iOS/NotificationServiceImpl.cs +++ b/Source/Plugin.LocalNotification/Apple/NotificationServiceImpl.cs @@ -1,9 +1,14 @@ -using CoreGraphics; +#if IOS || MACCATALYST +using CoreGraphics; using Foundation; using Plugin.LocalNotification.Core; using Plugin.LocalNotification.Core.Models; using Plugin.LocalNotification.Core.Models.AppleOption; +#if IOS using Plugin.LocalNotification.Core.Platforms.iOS; +#else +using Plugin.LocalNotification.Core.Platforms.MacCatalyst; +#endif using Plugin.LocalNotification.EventArgs; using System.Globalization; using UIKit; @@ -18,7 +23,7 @@ internal class NotificationServiceImpl : INotificationService public Func>? NotificationReceiving { get; set; } /// - public bool IsSupported => OperatingSystem.IsIOS(); + public bool IsSupported => ApplePlatform.IsCurrent(); /// public event NotificationReceivedEventHandler? NotificationReceived; @@ -41,7 +46,7 @@ internal class NotificationServiceImpl : INotificationService /// public bool Cancel(params int[] notificationIdList) { - if (!OperatingSystem.IsIOSVersionAtLeast(11)) + if (!ApplePlatform.IsVersion11OrLater()) { return false; } @@ -87,7 +92,7 @@ public async Task Show(NotificationRequest request) UNNotificationTrigger? trigger = null; try { - if (!OperatingSystem.IsIOS()) + if (!ApplePlatform.IsCurrent()) { return false; } @@ -166,7 +171,7 @@ await UNUserNotificationCenter.Current.AddNotificationRequestAsync(nativeRequest /// public async Task GetNotificationContent(NotificationRequest request) { - if (!OperatingSystem.IsIOS()) + if (!ApplePlatform.IsCurrent()) { return new UNMutableNotificationContent(); } @@ -184,7 +189,7 @@ public async Task GetNotificationContent(Notificat UserInfo = userInfoDictionary }; - if (OperatingSystem.IsIOSVersionAtLeast(15)) + if (ApplePlatform.IsVersion15OrLater()) { content.InterruptionLevel = request.Apple.Priority.ToNative(); content.RelevanceScore = request.Apple.RelevanceScore; @@ -212,9 +217,9 @@ public async Task GetNotificationContent(Notificat if (string.IsNullOrWhiteSpace(request.Apple.SummaryArgument) == false) { - if (OperatingSystem.IsIOS() && - OperatingSystem.IsIOSVersionAtLeast(12) && - !OperatingSystem.IsIOSVersionAtLeast(15)) + if (ApplePlatform.IsCurrent() && + ApplePlatform.IsVersion12OrLater() && + !ApplePlatform.IsVersion15OrLater()) { content.SummaryArgument = request.Apple.SummaryArgument; content.SummaryArgumentCount = (nuint)request.Apple.SummaryArgumentCount; @@ -294,7 +299,7 @@ public async Task GetNotificationContent(Notificat private static UNNotificationSound BuildNotificationSound(string? soundName, float? criticalVolume) { - if (criticalVolume is not null && OperatingSystem.IsIOSVersionAtLeast(12)) + if (criticalVolume is not null && ApplePlatform.IsVersion12OrLater()) { var volume = (float)Math.Clamp(criticalVolume.Value, 0.0, 1.0); return string.IsNullOrWhiteSpace(soundName) @@ -418,7 +423,7 @@ public void RegisterCategoryList(HashSet categoryList) var options = notificationAction.Apple.Action.ToNative(); var hasTextInput = !string.IsNullOrEmpty(notificationAction.Apple.TextInputButtonTitle); - if (OperatingSystem.IsIOSVersionAtLeast(15)) + if (ApplePlatform.IsVersion15OrLater()) { var icon = notificationAction.Apple.Icon.Type switch { @@ -584,4 +589,5 @@ public async Task RequestNotificationPermission(NotificationPermission? pe return false; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Source/Plugin.LocalNotification/Platforms/iOS/UserNotificationCenterDelegate.cs b/Source/Plugin.LocalNotification/Apple/UserNotificationCenterDelegate.cs similarity index 98% rename from Source/Plugin.LocalNotification/Platforms/iOS/UserNotificationCenterDelegate.cs rename to Source/Plugin.LocalNotification/Apple/UserNotificationCenterDelegate.cs index 46e1b2a..5dbb27c 100644 --- a/Source/Plugin.LocalNotification/Platforms/iOS/UserNotificationCenterDelegate.cs +++ b/Source/Plugin.LocalNotification/Apple/UserNotificationCenterDelegate.cs @@ -1,4 +1,5 @@ -using Plugin.LocalNotification.Core; +#if IOS || MACCATALYST +using Plugin.LocalNotification.Core; using Plugin.LocalNotification.EventArgs; using System.Globalization; using UIKit; @@ -196,7 +197,7 @@ public override void WillPresentNotification(UNUserNotificationCenter center, UN if (requestHandled == false) { - if (OperatingSystem.IsIOSVersionAtLeast(14)) + if (ApplePlatform.IsVersion14OrLater()) { if (notificationRequest.Apple.PresentAsBanner) { @@ -249,4 +250,5 @@ public override void WillPresentNotification(UNUserNotificationCenter center, UN internal static NotificationServiceImpl TryGetDefaultIOsNotificationService() => LocalNotificationCenter.Current is NotificationServiceImpl notificationService ? notificationService : new NotificationServiceImpl(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Source/Plugin.LocalNotification/Platforms/MacCatalyst/NotificationServiceImpl.cs b/Source/Plugin.LocalNotification/Platforms/MacCatalyst/NotificationServiceImpl.cs deleted file mode 100644 index e14eb22..0000000 --- a/Source/Plugin.LocalNotification/Platforms/MacCatalyst/NotificationServiceImpl.cs +++ /dev/null @@ -1,587 +0,0 @@ -using CoreGraphics; -using Foundation; -using Plugin.LocalNotification.Core; -using Plugin.LocalNotification.Core.Models; -using Plugin.LocalNotification.Core.Models.AppleOption; -using Plugin.LocalNotification.Core.Platforms.MacCatalyst; -using Plugin.LocalNotification.EventArgs; -using System.Globalization; -using UIKit; -using UserNotifications; - -namespace Plugin.LocalNotification.Platforms; - -/// -internal class NotificationServiceImpl : INotificationService -{ - /// - public Func>? NotificationReceiving { get; set; } - - /// - public bool IsSupported => OperatingSystem.IsIOS(); - - /// - public event NotificationReceivedEventHandler? NotificationReceived; - - /// - public event NotificationActionTappedEventHandler? NotificationActionTapped; - - /// - public event NotificationDisabledEventHandler? NotificationsDisabled; - - /// - public void OnNotificationReceived(NotificationEventArgs e) => NotificationReceived?.Invoke(e); - - /// - public void OnNotificationActionTapped(NotificationActionEventArgs e) => NotificationActionTapped?.Invoke(e); - - /// - public void OnNotificationsDisabled() => NotificationsDisabled?.Invoke(); - - /// - public bool Cancel(params int[] notificationIdList) - { - if (!OperatingSystem.IsIOSVersionAtLeast(11)) - { - return false; - } - - var itemList = notificationIdList.Select((item) => item.ToString()).ToArray(); - - UNUserNotificationCenter.Current.RemovePendingNotificationRequests(itemList); - UNUserNotificationCenter.Current.RemoveDeliveredNotifications(itemList); - - return true; - } - - /// - public bool Cancel(int notificationId, string? tag) => Cancel(notificationId); - - /// - public bool CancelAll() - { - UNUserNotificationCenter.Current.RemoveAllPendingNotificationRequests(); - UNUserNotificationCenter.Current.RemoveAllDeliveredNotifications(); - return true; - } - - /// - public bool Clear(params int[] notificationIdList) - { - var itemList = notificationIdList.Select((item) => item.ToString()).ToArray(); - - UNUserNotificationCenter.Current.RemoveDeliveredNotifications(itemList); - return true; - } - - /// - public bool ClearAll() - { - UNUserNotificationCenter.Current.RemoveAllDeliveredNotifications(); - return true; - } - - /// - public async Task Show(NotificationRequest request) - { - UNNotificationTrigger? trigger = null; - try - { - if (!OperatingSystem.IsIOS()) - { - return false; - } - - if (request is null) - { - return false; - } - - var allowed = await AreNotificationsEnabled().ConfigureAwait(false); - if (allowed == false) - { - LocalNotificationLogger.Log("User denied permission"); - OnNotificationsDisabled(); - return false; - } - - using var content = await GetNotificationContent(request); - - var notificationId = - request.NotificationId.ToString(CultureInfo.CurrentCulture); - - if (request.Geofence.IsGeofence) - { - if (GeofenceHandlerRegistry.Handler is null) - { - LocalNotificationLogger.Log(Properties.Resources.GeofencePackageMissing); - } - else - { - trigger = GeofenceHandlerRegistry.Handler.GetGeofenceTrigger(request); - } - - if (trigger is null) - { - return false; - } - } - else - { - var repeats = request.Schedule.RepeatType != NotificationRepeat.No; - - if (repeats && request.Schedule.RepeatType == NotificationRepeat.TimeInterval && - request.Schedule.NotifyRepeatInterval.HasValue) - { - var interval = request.Schedule.NotifyRepeatInterval.Value; - - // Cannot delay and repeat in when TimeInterval - trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(interval.TotalSeconds, true); - } - else - { - using var notifyTime = GetNsDateComponentsFromDateTime(request); - trigger = UNCalendarNotificationTrigger.CreateTrigger(notifyTime, repeats); - } - } - - var nativeRequest = UNNotificationRequest.FromIdentifier(notificationId, content, trigger); - - await UNUserNotificationCenter.Current.AddNotificationRequestAsync(nativeRequest) - .ConfigureAwait(false); - - return true; - } - finally - { - trigger?.Dispose(); - } - } - - - /// - /// - /// - /// - /// - public async Task GetNotificationContent(NotificationRequest request) - { - if (!OperatingSystem.IsIOS()) - { - return new UNMutableNotificationContent(); - } - - var userInfoDictionary = new NSMutableDictionary(); - var serializedRequest = LocalNotificationCenter.GetRequestSerialize(request); - userInfoDictionary.SetValueForKey(new NSString(serializedRequest), new NSString(RequestConstants.ReturnRequest)); - - var content = new UNMutableNotificationContent - { - Title = request.Title, - Subtitle = request.Subtitle, - Body = request.Description, - Badge = request.BadgeNumber, - UserInfo = userInfoDictionary - }; - - if (OperatingSystem.IsIOSVersionAtLeast(15)) - { - content.InterruptionLevel = request.Apple.Priority.ToNative(); - content.RelevanceScore = request.Apple.RelevanceScore; - } - - // Image Attachment - if (request.Image != null) - { - var nativeImage = await GetNativeImage(request.Image, request.Apple); - if (nativeImage != null) - { - content.Attachments = [nativeImage]; - } - } - - if (request.CategoryType != NotificationCategoryType.None) - { - content.CategoryIdentifier = request.CategoryType.ToNative(); - } - - if (string.IsNullOrWhiteSpace(request.Group) == false) - { - content.ThreadIdentifier = request.Group; - } - - if (string.IsNullOrWhiteSpace(request.Apple.SummaryArgument) == false) - { - if (OperatingSystem.IsIOS() && - OperatingSystem.IsIOSVersionAtLeast(12) && - !OperatingSystem.IsIOSVersionAtLeast(15)) - { - content.SummaryArgument = request.Apple.SummaryArgument; - content.SummaryArgumentCount = (nuint)request.Apple.SummaryArgumentCount; - } - } - - content.Sound = request.Silent - ? null - : BuildNotificationSound(request.Sound, request.Apple.CriticalSoundVolume); - - return content; - } - - /// - /// - /// - /// - /// - /// - protected virtual async Task GetNativeImage(NotificationImage? notificationImage, AppleOptions? appleOptions = null) - { - if (notificationImage is null || notificationImage.HasValue == false) - { - return null; - } - - NSUrl? imageAttachment = null; - if (string.IsNullOrWhiteSpace(notificationImage.ResourceName) == false) - { - imageAttachment = NSBundle.MainBundle.GetUrlForResource( - Path.GetFileNameWithoutExtension(notificationImage.ResourceName), - Path.GetExtension(notificationImage.ResourceName)); - } - - if (string.IsNullOrWhiteSpace(notificationImage.FilePath) == false) - { - if (File.Exists(notificationImage.FilePath)) - { - imageAttachment = NSUrl.CreateFileUrl(notificationImage.FilePath, false, null); - } - } - - if (notificationImage.Binary is { Length: > 0 }) - { - var cache = NSSearchPath.GetDirectories(NSSearchPathDirectory.CachesDirectory, - NSSearchPathDomain.User); - var cachesFolder = cache[0]; - var cacheFile = $"{cachesFolder}{NSProcessInfo.ProcessInfo.GloballyUniqueString}"; - - if (File.Exists(cacheFile)) - { - File.Delete(cacheFile); - } - - await File.WriteAllBytesAsync(cacheFile, notificationImage.Binary); - - imageAttachment = NSUrl.CreateFileUrl(cacheFile, false, null); - } - - if (imageAttachment is null) - { - return null; - } - - var attachOptions = new UNNotificationAttachmentOptions(); - if (appleOptions?.HideThumbnail == true) - { - attachOptions.ThumbnailHidden = true; - } - if (appleOptions?.ThumbnailClippingRect is { } clipRect) - { - attachOptions.ThumbnailClippingRect = new CGRect(clipRect.X, clipRect.Y, clipRect.Width, clipRect.Height); - } - - return UNNotificationAttachment.FromIdentifier("image", imageAttachment, attachOptions, out _); - } - - private static UNNotificationSound BuildNotificationSound(string? soundName, float? criticalVolume) - { - if (criticalVolume is not null && OperatingSystem.IsIOSVersionAtLeast(12)) - { - var volume = (float)Math.Clamp(criticalVolume.Value, 0.0, 1.0); - return string.IsNullOrWhiteSpace(soundName) - ? UNNotificationSound.GetDefaultCriticalSound(volume) - : UNNotificationSound.GetCriticalSound(soundName, volume); - } - return string.IsNullOrWhiteSpace(soundName) - ? UNNotificationSound.Default - : UNNotificationSound.GetSound(soundName); - } - - /// - /// - /// - /// - /// - protected static NSDateComponents GetNsDateComponentsFromDateTime(NotificationRequest notificationRequest) - { - var dateTime = notificationRequest.Schedule.NotifyTime ?? DateTimeOffset.Now.AddSeconds(1); - - return notificationRequest.Schedule.RepeatType switch - { - NotificationRepeat.Daily => new NSDateComponents - { - Hour = dateTime.Hour, - Minute = dateTime.Minute, - Second = dateTime.Second - }, - NotificationRepeat.Weekly => new NSDateComponents - { - // IOS: Weekday units are the numbers 1 through n, where n is the number of days in the week. - // For example, in the Gregorian calendar, n is 7 and Sunday is represented by 1. - // .Net: The returned value is an integer between 0 and 6, - // where 0 indicates Sunday, 1 indicates Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates Thursday, 5 indicates Friday, and 6 indicates Saturday. - Weekday = (int)dateTime.DayOfWeek + 1, - Hour = dateTime.Hour, - Minute = dateTime.Minute, - Second = dateTime.Second - }, - NotificationRepeat.Monthly => new NSDateComponents - { - // Repeat on the same day of the month at the same time. - Day = dateTime.Day, - Hour = dateTime.Hour, - Minute = dateTime.Minute, - Second = dateTime.Second - }, - NotificationRepeat.No => new NSDateComponents - { - Day = dateTime.Day, - Month = dateTime.Month, - Year = dateTime.Year, - Hour = dateTime.Hour, - Minute = dateTime.Minute, - Second = dateTime.Second - }, - _ => new NSDateComponents - { - Day = dateTime.Day, - Hour = dateTime.Hour, - Minute = dateTime.Minute, - Second = dateTime.Second - } - }; - } - - /// - public void RegisterCategoryList(HashSet categoryList) - { - if (categoryList is null || categoryList.Count <= 0) - { - return; - } - - var nativeCategoryList = new List(); - foreach (var category in categoryList) - { - if (category.CategoryType == NotificationCategoryType.None) - { - continue; - } - - var nativeCategory = RegisterActionList(category); - if (nativeCategory != null) - { - nativeCategoryList.Add(nativeCategory); - } - } - - if (nativeCategoryList.Count <= 0) - { - return; - } - - UNUserNotificationCenter.Current.SetNotificationCategories( - new NSSet(nativeCategoryList.ToArray())); - } - - /// - /// - /// - /// - /// - protected static UNNotificationCategory? RegisterActionList(NotificationCategory? category) - { - if (category is null || category.CategoryType == NotificationCategoryType.None) - { - return null; - } - - var nativeActionList = new List(); - foreach (var notificationAction in category.ActionList) - { - if (notificationAction.ActionId == -1000) - { - continue; - } - - var identifier = notificationAction.ActionId.ToString(CultureInfo.InvariantCulture); - var title = notificationAction.Title; - var options = notificationAction.Apple.Action.ToNative(); - var hasTextInput = !string.IsNullOrEmpty(notificationAction.Apple.TextInputButtonTitle); - - if (OperatingSystem.IsIOSVersionAtLeast(15)) - { - var icon = notificationAction.Apple.Icon.Type switch - { - AppleActionIconType.None => null, - AppleActionIconType.System => UNNotificationActionIcon.CreateFromSystem(notificationAction.Apple.Icon.Name), - AppleActionIconType.Template => UNNotificationActionIcon.CreateFromTemplate(notificationAction.Apple.Icon.Name), - _ => null, - }; - - var nativeAction = hasTextInput - ? UNTextInputNotificationAction.FromIdentifier( - identifier, title, options, icon, - notificationAction.Apple.TextInputButtonTitle!, - notificationAction.Apple.TextInputPlaceholder ?? string.Empty) - : UNNotificationAction.FromIdentifier(identifier, title, options, icon); - - nativeActionList.Add(nativeAction); - } - else - { - var nativeAction = hasTextInput - ? UNTextInputNotificationAction.FromIdentifier( - identifier, title, options, - notificationAction.Apple.TextInputButtonTitle!, - notificationAction.Apple.TextInputPlaceholder ?? string.Empty) - : UNNotificationAction.FromIdentifier(identifier, title, options); - - nativeActionList.Add(nativeAction); - } - } - - if (nativeActionList.Count == 0) - { - return null; - } - - var categoryOptions = category.AppleOptions.ToNative(); - - var notificationCategory = UNNotificationCategory - .FromIdentifier(category.CategoryType.ToNative(), [.. nativeActionList], - [], categoryOptions); - - return notificationCategory; - } - - /// - public async Task> GetPendingNotificationList() - { - var pending = await UNUserNotificationCenter.Current.GetPendingNotificationRequestsAsync(); - - return [.. pending.Select(r => LocalNotificationCenter.GetRequest(r.Content) ?? new NotificationRequest())]; - } - - /// - public async Task> GetDeliveredNotificationList() - { - var delivered = await UNUserNotificationCenter.Current.GetDeliveredNotificationsAsync(); - - return [.. delivered.Select(r => LocalNotificationCenter.GetRequest(r.Request.Content) ?? new NotificationRequest())]; - } - - /// - public async Task> GetActiveNotifications() - { - var delivered = await UNUserNotificationCenter.Current.GetDeliveredNotificationsAsync(); - - return [.. delivered.Select(n => - { - var content = n.Request.Content; - var request = LocalNotificationCenter.GetRequest(content); - - _ = int.TryParse(n.Request.Identifier, out var notificationId); - - return new ActiveNotification - { - NotificationId = notificationId, - Title = content.Title, - Body = content.Body, - GroupKey = content.ThreadIdentifier, - Payload = request?.ReturningData - }; - })]; - } - - /// - public async Task AreNotificationsEnabled(NotificationPermission? permission = null) - { - var settings = await UNUserNotificationCenter.Current.GetNotificationSettingsAsync().ConfigureAwait(false); - return settings.AlertSetting == UNNotificationSetting.Enabled; - } - - /// - public async Task GetNotificationPermissionStatus() - { - var settings = await UNUserNotificationCenter.Current.GetNotificationSettingsAsync().ConfigureAwait(false); - - var isEnabled = settings.AuthorizationStatus is UNAuthorizationStatus.Authorized - or UNAuthorizationStatus.Provisional; - - return new NotificationPermissionStatus - { - IsEnabled = isEnabled, - IsAlertEnabled = settings.AlertSetting == UNNotificationSetting.Enabled, - IsSoundEnabled = settings.SoundSetting == UNNotificationSetting.Enabled, - IsBadgeEnabled = settings.BadgeSetting == UNNotificationSetting.Enabled, - IsProvisionalEnabled = settings.AuthorizationStatus == UNAuthorizationStatus.Provisional, - IsCriticalAlertEnabled = settings.CriticalAlertSetting == UNNotificationSetting.Enabled, - IsCarPlayEnabled = settings.CarPlaySetting == UNNotificationSetting.Enabled, - IsTimeSensitiveEnabled = settings.TimeSensitiveSetting == UNNotificationSetting.Enabled, - CanScheduleExactAlarms = true - }; - } - - /// - public async Task RequestNotificationPermission(NotificationPermission? permission = null) - { - try - { - permission ??= new NotificationPermission(); - - if (!permission.AskPermission) - { - return false; - } - - var allowed = await AreNotificationsEnabled(permission); - if (allowed) - { - return true; - } - - // Ask the user for permission to show notifications on IOS 10.0+ - var authorizationOptions = permission.Apple.NotificationAuthorization.ToNative(); - var (alertsAllowed, error) = await UNUserNotificationCenter.Current.RequestAuthorizationAsync(authorizationOptions).ConfigureAwait(false); - - if (error != null) - { - LocalNotificationLogger.Log(error.LocalizedDescription); - } - - if (alertsAllowed) - { - if (permission.Apple.LocationAuthorization == AppleLocationAuthorization.No) - { - return alertsAllowed; - } - - if (GeofenceHandlerRegistry.Handler is null) - { - LocalNotificationLogger.Log(Properties.Resources.GeofencePackageMissing); - } - else - { - GeofenceHandlerRegistry.Handler.RequestLocationNotificationPermission(permission); - } - } - - return alertsAllowed; - } - catch (Exception ex) - { - LocalNotificationLogger.Log(ex); - return false; - } - } -} \ No newline at end of file diff --git a/Source/Plugin.LocalNotification/Platforms/MacCatalyst/UserNotificationCenterDelegate.cs b/Source/Plugin.LocalNotification/Platforms/MacCatalyst/UserNotificationCenterDelegate.cs deleted file mode 100644 index 4d6e4d9..0000000 --- a/Source/Plugin.LocalNotification/Platforms/MacCatalyst/UserNotificationCenterDelegate.cs +++ /dev/null @@ -1,252 +0,0 @@ -using Plugin.LocalNotification.Core; -using Plugin.LocalNotification.EventArgs; -using System.Globalization; -using UIKit; -using UserNotifications; - -namespace Plugin.LocalNotification.Platforms; - -/// -/// Handles IOS user notification center delegate callbacks for local notifications -/// -/// -public class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate -{ - /// - /// Called when a notification response is received - when user takes action on a delivered notification - /// - /// The notification center that received the response - /// The user's response to the notification - /// The completion handler to execute when done processing the response - /// - public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, - UNNotificationResponse response, Action completionHandler) - { - try - { - if (response is null) - { - return; - } - - var notificationService = TryGetDefaultIOsNotificationService(); - var notificationRequest = LocalNotificationCenter.GetRequest(response.Notification.Request.Content); - - // if notificationRequest is null this maybe not a notification from this plugin. - if (notificationRequest is null) - { - completionHandler?.Invoke(); - - LocalNotificationLogger.Log("Notification request not found"); - return; - } - - // Capture launch notification details if this is the first response after cold start. - if (LocalNotificationCenter.IsCapturingLaunchNotification) - { - LocalNotificationCenter.IsCapturingLaunchNotification = false; - - var launchActionId = NotificationActionEventArgs.TapActionId; - - if (!response.IsDefaultAction && - !string.IsNullOrWhiteSpace(response.ActionIdentifier) && - int.TryParse(response.ActionIdentifier, out var parsedLaunchActionId)) - { - launchActionId = parsedLaunchActionId; - } - else if (response.IsDismissAction) - { - launchActionId = NotificationActionEventArgs.DismissedActionId; - } - - LocalNotificationCenter.LaunchNotificationDetails = new Core.Models.NotificationLaunchDetails - { - DidNotificationLaunchApp = true, - Request = notificationRequest, - ActionId = launchActionId - }; - } - - if (response.Notification.Request.Content.Badge != null) - { - var badgeNumber = Convert.ToInt32(response.Notification.Request.Content.Badge.ToString(), CultureInfo.CurrentCulture); - - center.InvokeOnMainThread(() => - { - if (UIDevice.CurrentDevice.CheckSystemVersion(16, 0)) - { - center.SetBadgeCount(badgeNumber, (error) => - { - if (error != null) - { - LocalNotificationLogger.Log(error.LocalizedDescription); - } - }); - } - else - { - UIApplication.SharedApplication.ApplicationIconBadgeNumber -= badgeNumber; - } - }); - } - - // Take action based on identifier - if (!response.IsDefaultAction) - { - if (string.IsNullOrWhiteSpace(response.ActionIdentifier) == false && - int.TryParse(response.ActionIdentifier, out var actionId)) - { - var actionArgs = new NotificationActionEventArgs - { - ActionId = actionId, - Request = notificationRequest - }; - - // Capture inline-reply text from a UNTextInputNotificationAction response. - if (response is UNTextInputNotificationResponse textResponse) - { - actionArgs.Input = textResponse.UserText; - } - - notificationService.OnNotificationActionTapped(actionArgs); - - completionHandler?.Invoke(); - return; - } - } - - if (response.IsDismissAction) - { - var actionArgs = new NotificationActionEventArgs - { - ActionId = NotificationActionEventArgs.DismissedActionId, - Request = notificationRequest - }; - notificationService.OnNotificationActionTapped(actionArgs); - - completionHandler?.Invoke(); - return; - } - - var args = new NotificationActionEventArgs - { - ActionId = NotificationActionEventArgs.TapActionId, - Request = notificationRequest - }; - notificationService.OnNotificationActionTapped(args); - - completionHandler?.Invoke(); - } - catch (Exception ex) - { - LocalNotificationLogger.Log(ex); - } - } - - /// - /// Called when a notification is about to be presented while the app is in the foreground - /// - /// The notification center that is about to present the notification - /// The notification to be presented - /// The completion handler to execute with the presentation options - /// - public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, - Action completionHandler) - { - try - { - var presentationOptions = UNNotificationPresentationOptions.None; - - var notificationService = TryGetDefaultIOsNotificationService(); - var notificationRequest = LocalNotificationCenter.GetRequest(notification?.Request.Content); - - // if notificationRequest is null this maybe not a notification from this plugin. - if (notificationRequest is null) - { - completionHandler?.Invoke(presentationOptions); - - LocalNotificationLogger.Log("Notification request not found"); - return; - } - - if (notificationRequest.Schedule.NotifyAutoCancelTime.HasValue && - notificationRequest.Schedule.NotifyAutoCancelTime <= DateTimeOffset.Now) - { - _ = notificationService.Cancel(notificationRequest.NotificationId); - - completionHandler?.Invoke(presentationOptions); - - LocalNotificationLogger.Log("Notification Auto Canceled"); - return; - } - - var requestHandled = false; - if (notificationService.NotificationReceiving is not null) - { - var requestArg = notificationService.NotificationReceiving(notificationRequest).GetAwaiter().GetResult(); - if (requestArg is not null) - { - if (requestArg.Handled) - { - LocalNotificationLogger.Log("Notification Handled"); - requestHandled = true; - } - } - } - - if (requestHandled == false) - { - if (OperatingSystem.IsMacCatalystVersionAtLeast(14)) - { - if (notificationRequest.Apple.PresentAsBanner) - { - presentationOptions |= UNNotificationPresentationOptions.Banner; - } - - if (notificationRequest.Apple.ShowInNotificationCenter) - { - presentationOptions |= UNNotificationPresentationOptions.List; - } - } - else - { - presentationOptions |= UNNotificationPresentationOptions.Alert; - } - - if (notificationRequest.Apple.ApplyBadgeValue) - { - presentationOptions |= UNNotificationPresentationOptions.Badge; - } - if (notificationRequest.Apple.PlayForegroundSound) - { - presentationOptions |= UNNotificationPresentationOptions.Sound; - } - - if (notificationRequest.Apple.HideForegroundAlert) - { - presentationOptions = UNNotificationPresentationOptions.None; - } - } - - var args = new NotificationEventArgs - { - Request = notificationRequest - }; - notificationService.OnNotificationReceived(args); - - completionHandler?.Invoke(presentationOptions); - } - catch (Exception ex) - { - LocalNotificationLogger.Log(ex); - } - } - - /// - /// Attempts to get the default IOS notification service implementation - /// - /// A new or existing instance of NotificationServiceImpl - internal static NotificationServiceImpl TryGetDefaultIOsNotificationService() => LocalNotificationCenter.Current is NotificationServiceImpl notificationService - ? notificationService - : new NotificationServiceImpl(); -} \ No newline at end of file diff --git a/Source/Plugin.LocalNotification/Platforms/iOS/LocalNotificationCenter.cs b/Source/Plugin.LocalNotification/Platforms/iOS/LocalNotificationCenter.cs deleted file mode 100644 index 12bcbd2..0000000 --- a/Source/Plugin.LocalNotification/Platforms/iOS/LocalNotificationCenter.cs +++ /dev/null @@ -1,135 +0,0 @@ -using Foundation; -using Plugin.LocalNotification.Core; -using Plugin.LocalNotification.Core.Models; -using Plugin.LocalNotification.Platforms; -using UIKit; -using UserNotifications; - -namespace Plugin.LocalNotification; - -public partial class LocalNotificationCenter -{ - /// - /// Internal flag set to true during FinishedLaunching so that the notification - /// delegate can identify the very first DidReceiveNotificationResponse call as the - /// response that cold-started the app. - /// - internal static bool IsCapturingLaunchNotification { get; set; } - - /// - /// Sets the for IOS notifications. Allows developers to provide a custom delegate for handling notification events. - /// - /// The custom notification center delegate to use. If null, uses the default . - public static void SetUserNotificationCenterDelegate(UserNotificationCenterDelegate? notificationDelegate = null) => UNUserNotificationCenter.Current.Delegate = notificationDelegate ?? new UserNotificationCenterDelegate(); - - /// - /// Gets the from the provided . - /// - /// The notification content to extract the request from. - /// The deserialized , or null if not found. - public static NotificationRequest? GetRequest(UNNotificationContent? notificationContent) - { - if (notificationContent is null) - { - return null; - } - - var dictionary = notificationContent.UserInfo; - - if (!dictionary.ContainsKey(new NSString(RequestConstants.ReturnRequest))) - { - return null; - } - - var requestSerialize = dictionary[RequestConstants.ReturnRequest].ToString(); - - var request = GetRequest(requestSerialize); - - return request; - } - - /// - /// Resets the application icon badge number when there are no notifications. - /// - /// The current instance. - public static void ResetApplicationIconBadgeNumber(UIApplication uiApplication) - { - try - { - var notificationList = new List(); - //Remove badges on app enter foreground if user cleared the notification in the notification panel - var completionSource = new TaskCompletionSource(); - UNUserNotificationCenter.Current.GetDeliveredNotifications((notificationArray) => - { - notificationList.AddRange(notificationArray); - completionSource.SetResult(true); - }); - completionSource.Task.Wait(); - if (notificationList.Count != 0) - { - return; - } - - uiApplication.InvokeOnMainThread(() => - { - if (OperatingSystem.IsIOSVersionAtLeast(16)) - { - UNUserNotificationCenter.Current.SetBadgeCount(0, (error) => - { - if (error != null) - { - LocalNotificationLogger.Log(error.LocalizedDescription); - } - }); - } - else - { - uiApplication.ApplicationIconBadgeNumber = 0; - UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0; - } - }); - } - catch (Exception ex) - { - LocalNotificationLogger.Log(ex); - throw; - } - } - - /// - /// Asynchronously resets the application icon badge number when there are no notifications. - /// - /// The current instance. - public static async Task ResetApplicationIconBadgeNumberAsync(UIApplication uiApplication) - { - try - { - //Remove badges on app enter foreground if user cleared the notification in the notification panel - var notificationList = await UNUserNotificationCenter.Current.GetDeliveredNotificationsAsync() - .ConfigureAwait(false); - - if (notificationList.Length != 0) - { - return; - } - - uiApplication.InvokeOnMainThread(async () => - { - if (OperatingSystem.IsIOSVersionAtLeast(16)) - { - await UNUserNotificationCenter.Current.SetBadgeCountAsync(0); - } - else - { - uiApplication.ApplicationIconBadgeNumber = 0; - UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0; - } - }); - } - catch (Exception ex) - { - LocalNotificationLogger.Log(ex); - throw; - } - } -} \ No newline at end of file