using System; #if UNITY_ANDROID using Unity.Notifications.Android; #else using System.Globalization; using Unity.Notifications.iOS; #endif namespace Unity.Notifications { /// /// Options, specifying how notifications should be presented to the user. /// These option can be bitwise-ored to combine them. /// /// /// On Android Alert and Sound flags are used to choose importance level for the channel, so specifying Alert also includes sound. /// /// [Flags] public enum NotificationPresentation { /// /// Specifies that when notification arrives, a pop-up should show up on screen. /// Alerts can be disabled by user in device settings. They may also be disabled by default. /// Alert = 1, /// /// Whether notifications can set a badge on applications launcher. /// Badge = 1 << 1, /// /// Whether notifications cause device to play sound uppon arrival. /// Sound = 1 << 2, /// /// Causes device to vibrate when notification is received. Android only. /// Vibrate = 1 << 3, } /// /// The settings section to open, if possible. /// public enum NotificationSettingsSection { /// /// Opens settings for application and tries to open the section for notifications. /// Application, /// /// Tries to navigate to section for a particular notification category. /// Since Android 8.0 will open notification settings for the specific notification channel. /// Category, } /// /// Initialization arguments for . /// Recommended to use to retrieve recommened default values and then alter it. /// It is required to manually set . /// public struct NotificationCenterArgs { /// /// Returns recommended default values for all settings. /// public static NotificationCenterArgs Default => new NotificationCenterArgs() { PresentationOptions = NotificationPresentation.Badge | NotificationPresentation.Sound, }; /// /// Options specifying how notifications should be presented to user when they arrive. /// On Android these only have effect if notification channel is created uppon initialization (all channel related properties are set). /// On iOS these only have effect if permission to post notification is later requested using /// public NotificationPresentation PresentationOptions { get; set; } /// /// A custom non-empty string to identify notification channel. Required, Android only. /// All notifications will be sent to this channel. /// Channel is created automatically during initialization if and are both set. /// If name and description are left null, channel with given identifier has to be created manually (for example using ). /// public string AndroidChannelId { get; set; } /// /// A user visible name for notification channel. Optional, Android only. /// Leave null, if you wish to create channel manually. /// Set this to channel name for it to be created automatically during initialization. /// If this is set, then must also be set. /// /// public string AndroidChannelName { get; set; } /// /// A user visible description for the channel. Optional, Android only. /// Leave null, if you wish to create channel manually. /// Set this to channel description for it to be created automatically during initialization. /// If this is set, then must also be set. /// /// public string AndroidChannelDescription { get; set; } } /// /// Send, receive and manage notifications. /// Must be initialized before use. See . /// public static class NotificationCenter { /// /// Delegate for . /// /// Notification that has been received. public delegate void NotificationReceivedCallback(Notification notification); static bool s_Initialized = false; static NotificationCenterArgs s_Args; static event NotificationReceivedCallback s_OnNotificationReceived; static bool s_OnNotificationReceivedSet = false; #if UNITY_ANDROID static void NotificationReceived(AndroidNotificationIntentData data) #else static void NotificationReceived(iOSNotification notif) #endif { if (s_OnNotificationReceived != null) { #if UNITY_ANDROID var notification = new Notification(data.Notification, data.Id); #else var notification = new Notification(notif); #endif s_OnNotificationReceived(notification); } } /// /// An event that fires when notification is received. /// Application must be running for this event to work. /// On Android this even fires if application is in foreground or when it's brought back from background. /// On iOS this even only fires when notification is received while app is in foreground. /// /// /// This event is the same as AndroidNotificationCenter.OnNotificationReceived and iOSNotificationCenter.OnNotificationReceived. /// public static event NotificationReceivedCallback OnNotificationReceived { add { if (!s_OnNotificationReceivedSet) { #if UNITY_ANDROID AndroidNotificationCenter.OnNotificationReceived += NotificationReceived; #else iOSNotificationCenter.OnNotificationReceived += NotificationReceived; #endif s_OnNotificationReceivedSet = true; } s_OnNotificationReceived += value; } remove { s_OnNotificationReceived -= value; } } /// /// Initializes notification center with given arguments. /// On Android it will also create notification channel if arguments are set accordingly. /// /// Arguments for initialization. public static void Initialize(NotificationCenterArgs args) { if (s_Initialized) return; if (string.IsNullOrEmpty(args.AndroidChannelId)) throw new ArgumentException("AndroidChannel not provided"); s_Args = args; s_Initialized = true; #if UNITY_ANDROID AndroidNotificationCenter.Initialize(); if (args.AndroidChannelName != null || args.AndroidChannelDescription != null) { Importance importance = Importance.Low; if (0 != (args.PresentationOptions & NotificationPresentation.Alert)) importance = Importance.High; else if (0 != (args.PresentationOptions & NotificationPresentation.Sound)) importance = Importance.Default; AndroidNotificationCenter.RegisterNotificationChannel(new AndroidNotificationChannel() { Id = args.AndroidChannelId, Name = args.AndroidChannelName, Description = args.AndroidChannelDescription, Importance = importance, CanShowBadge = 0 != (args.PresentationOptions & NotificationPresentation.Badge), EnableVibration = 0 != (args.PresentationOptions & NotificationPresentation.Vibrate), }); } #endif } /// /// Request for users permission to post notifications. /// Requests users permission to send notifications. Unless already allowed or permanently denied, shows UI to the user. /// Users can revoke permission in Settings while app is not running. /// /// An object for tracking the request and obtaining results. /// Before Android 13 no permission is required. public static NotificationsPermissionRequest RequestPermission() { CheckInitialized(); int iOSAuthorizationOptions = 0; #if UNITY_IOS if (0 != (s_Args.PresentationOptions & NotificationPresentation.Alert)) iOSAuthorizationOptions |= (int)AuthorizationOption.Alert; if (0 != (s_Args.PresentationOptions & NotificationPresentation.Badge)) iOSAuthorizationOptions |= (int)AuthorizationOption.Badge; if (0 != (s_Args.PresentationOptions & NotificationPresentation.Sound)) iOSAuthorizationOptions |= (int)AuthorizationOption.Sound; #endif return new NotificationsPermissionRequest(iOSAuthorizationOptions); } static void CheckInitialized() { if (!s_Initialized) throw new Exception("NotificationCenter not initialized"); } /// /// Schedule notification to be shown in the future. /// /// Type of the schedule, usually deduced from actually passed one. /// Notification to send. /// Schedule, specifying, when notification should be shown. /// Notification identifier. public static int ScheduleNotification(Notification notification, T schedule) where T : NotificationSchedule { string category = null; #if UNITY_ANDROID category = s_Args.AndroidChannelId; #endif return ScheduleNotification(notification, category, schedule); } /// /// Schedule notification to be shown in the future. /// Allows to explicitly specify the category to send notification to. On Android it is notification channel. /// Channel or category has to be created manually using AndroidNotificationCenter and iOSNotificationCenter respectively. /// /// Type of the schedule, usually deduced from actually passed one. /// Notification to send. /// Identifier for iOS category or Android channel. /// Schedule, specifying, when notification should be shown. /// Notification identifier. public static int ScheduleNotification(Notification notification, string category, T schedule) where T : NotificationSchedule { CheckInitialized(); #if UNITY_ANDROID var n = (AndroidNotification)notification; schedule.Schedule(ref n); if (notification.Identifier.HasValue) { AndroidNotificationCenter.SendNotificationWithExplicitID(n, category, notification.Identifier.Value); return notification.Identifier.Value; } else return AndroidNotificationCenter.SendNotification(n, category); #else var n = (iOSNotification)notification; if (n == null) throw new ArgumentException("Passed notifiation is empty"); n.CategoryIdentifier = category; schedule.Schedule(ref n); iOSNotificationCenter.ScheduleNotification(n); if (notification.Identifier.HasValue) return notification.Identifier.Value; // iOSNotification is class and has auto-generated id set at this point // for consistency with Android set it back to null, so same Notification can be sent again as new one int id = int.Parse(n.Identifier, NumberStyles.None, CultureInfo.InvariantCulture); n.Identifier = null; return id; #endif } /// /// Returns last notification tapped by user, or null. /// public static Notification? LastRespondedNotification { get { CheckInitialized(); #if UNITY_ANDROID var intent = AndroidNotificationCenter.GetLastNotificationIntent(); if (intent == null) return null; return new Notification(intent.Notification, intent.Id); #else var notification = iOSNotificationCenter.GetLastRespondedNotification(); if (notification == null) return null; return new Notification(notification); #endif } } /// /// Cancel a scheduled notification. /// /// ID of the notification to cancel. public static void CancelScheduledNotification(int id) { CheckInitialized(); #if UNITY_ANDROID AndroidNotificationCenter.CancelScheduledNotification(id); #else iOSNotificationCenter.RemoveScheduledNotification(id.ToString(CultureInfo.InvariantCulture)); #endif } /// /// Cancel delivered notification. /// Removes notification from the tray. /// /// ID of the notification to cancel. public static void CancelDeliveredNotification(int id) { CheckInitialized(); #if UNITY_ANDROID AndroidNotificationCenter.CancelDisplayedNotification(id); #else iOSNotificationCenter.RemoveDeliveredNotification(id.ToString(CultureInfo.InvariantCulture)); #endif } /// /// Cancel all future notifications. /// public static void CancelAllScheduledNotifications() { CheckInitialized(); #if UNITY_ANDROID AndroidNotificationCenter.CancelAllScheduledNotifications(); #else iOSNotificationCenter.RemoveAllScheduledNotifications(); #endif } /// /// Remove all already delivered notifications. /// public static void CancelAllDeliveredNotifications() { CheckInitialized(); #if UNITY_ANDROID AndroidNotificationCenter.CancelAllDisplayedNotifications(); #else iOSNotificationCenter.RemoveAllDeliveredNotifications(); #endif } /// /// Clear Application badge. iOS only. /// iOS applications can set numeric badge on app icon. Calling this method removes that badge. /// On Android badge is removed automatically when notifications are removed. /// public static void ClearBadge() { CheckInitialized(); #if UNITY_IOS iOSNotificationCenter.ApplicationBadge = 0; #endif } /// /// Opens settings for the application. /// If possible, will try to navigate as close to requested section as it can. /// On iOS and Android prior to 8.0 will open settings for the application. /// Since Android 8.0 will open notification settings for either application or the default channel. /// /// The section to navigate to. public static void OpenNotificationSettings(NotificationSettingsSection section = NotificationSettingsSection.Application) { CheckInitialized(); #if UNITY_ANDROID string channel = section switch { NotificationSettingsSection.Category => s_Args.AndroidChannelId, NotificationSettingsSection.Application => null, _ => null, }; AndroidNotificationCenter.OpenNotificationSettings(channel); #else iOSNotificationCenter.OpenNotificationSettings(); #endif } } }