diff --git a/UserNotifications/iOS/CustomizedExpandedModifiedRemoteNotification.png b/UserNotifications/iOS/CustomizedExpandedModifiedRemoteNotification.png
new file mode 100644
index 0000000..5948143
Binary files /dev/null and b/UserNotifications/iOS/CustomizedExpandedModifiedRemoteNotification.png differ
diff --git a/UserNotifications/iOS/CustomizedExpandedRemoteNotification.png b/UserNotifications/iOS/CustomizedExpandedRemoteNotification.png
new file mode 100644
index 0000000..0b68efe
Binary files /dev/null and b/UserNotifications/iOS/CustomizedExpandedRemoteNotification.png differ
diff --git a/UserNotifications/iOS/LocalNotification.png b/UserNotifications/iOS/LocalNotification.png
new file mode 100644
index 0000000..1ff56b6
Binary files /dev/null and b/UserNotifications/iOS/LocalNotification.png differ
diff --git a/UserNotifications/iOS/NotificationContentExtension/Entitlements.plist b/UserNotifications/iOS/NotificationContentExtension/Entitlements.plist
new file mode 100644
index 0000000..9ae5993
--- /dev/null
+++ b/UserNotifications/iOS/NotificationContentExtension/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/UserNotifications/iOS/NotificationContentExtension/Info.plist b/UserNotifications/iOS/NotificationContentExtension/Info.plist
new file mode 100644
index 0000000..4ed4c52
--- /dev/null
+++ b/UserNotifications/iOS/NotificationContentExtension/Info.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ CFBundleDisplayName
+ NotificationContent
+ CFBundleName
+ NotificationTest.NotificationContent
+ CFBundleDevelopmentRegion
+ en
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ NSExtension
+
+ NSExtensionAttributes
+
+ UNNotificationExtensionCategory
+ general
+ UNNotificationExtensionInitialContentSizeRatio
+ 0.5
+ UNNotificationExtensionDefaultContentHidden
+
+
+ NSExtensionMainStoryboard
+ MainInterface
+ NSExtensionPointIdentifier
+ com.apple.usernotifications.content-extension
+
+
+
diff --git a/UserNotifications/iOS/NotificationContentExtension/MainInterface.storyboard b/UserNotifications/iOS/NotificationContentExtension/MainInterface.storyboard
new file mode 100644
index 0000000..ab87282
--- /dev/null
+++ b/UserNotifications/iOS/NotificationContentExtension/MainInterface.storyboard
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UserNotifications/iOS/NotificationContentExtension/NotificationContentExtension.csproj b/UserNotifications/iOS/NotificationContentExtension/NotificationContentExtension.csproj
new file mode 100644
index 0000000..a6da7c7
--- /dev/null
+++ b/UserNotifications/iOS/NotificationContentExtension/NotificationContentExtension.csproj
@@ -0,0 +1,16 @@
+
+
+ net9.0-ios
+ Library
+ enable
+ enable
+ 15.0
+ com.rolfkvinge.usernotifications.notificationcontentextension
+ True
+ User Notifications Content Extension Profile
+
+
+
+
+
+
diff --git a/UserNotifications/iOS/NotificationContentExtension/NotificationViewController.cs b/UserNotifications/iOS/NotificationContentExtension/NotificationViewController.cs
new file mode 100644
index 0000000..731fc76
--- /dev/null
+++ b/UserNotifications/iOS/NotificationContentExtension/NotificationViewController.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Foundation;
+using ObjCRuntime;
+using UIKit;
+using UserNotifications;
+using UserNotificationsUI;
+
+namespace NotificationContentExtension
+{
+ [Register ("NotificationViewController")]
+ public class NotificationViewController : UIViewController, IUNNotificationContentExtension
+ {
+ const int LabelHeight = 88;
+ UILabel? notificationLabel;
+
+ protected NotificationViewController (NativeHandle handle) : base (handle)
+ {
+ // Note: this .ctor should not contain any initialization logic.
+ // it only exists so that the OS can instantiate an instance of this class.
+ }
+
+ public override void ViewDidLoad ()
+ {
+ base.ViewDidLoad ();
+
+ Console.WriteLine ($"UserNotifications.NotificationContentExtension.NotificationViewController.ViewDidLoad ()");
+
+ View.BackgroundColor = UIColor.Clear;
+
+ notificationLabel = new UILabel ()
+ {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ Lines = 0,
+ TextAlignment = UITextAlignment.Center,
+ };
+ View.AddSubview (notificationLabel);
+
+ notificationLabel.TopAnchor.ConstraintEqualTo (View.TopAnchor).Active = true;
+ notificationLabel.LeadingAnchor.ConstraintEqualTo (View.LeadingAnchor).Active = true;
+ notificationLabel.TrailingAnchor.ConstraintEqualTo (View.TrailingAnchor).Active = true;
+ notificationLabel.HeightAnchor.ConstraintEqualTo (LabelHeight).Active = true;
+ }
+
+ void IUNNotificationContentExtension.DidReceiveNotification(UNNotification notification)
+ {
+ Console.WriteLine ($"UserNotifications.NotificationContentExtension.NotificationViewController.DidReceiveNotification ({notification})");
+
+ if (notificationLabel is not null) {
+ notificationLabel.Text =
+ $"➡️ {notification.Request.Content.Title}\n" +
+ $"↪️ {notification.Request.Content.Subtitle}\n" +
+ $"⏩ {notification.Request.Content.Body}";
+ }
+ }
+ }
+}
+
diff --git a/UserNotifications/iOS/NotificationServiceExtension/Entitlements.plist b/UserNotifications/iOS/NotificationServiceExtension/Entitlements.plist
new file mode 100644
index 0000000..9ae5993
--- /dev/null
+++ b/UserNotifications/iOS/NotificationServiceExtension/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/UserNotifications/iOS/NotificationServiceExtension/Info.plist b/UserNotifications/iOS/NotificationServiceExtension/Info.plist
new file mode 100644
index 0000000..9c6a8de
--- /dev/null
+++ b/UserNotifications/iOS/NotificationServiceExtension/Info.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ CFBundleDisplayName
+ NotificationService
+ CFBundleName
+ NotificationTest.NotificationService
+ CFBundleDevelopmentRegion
+ en
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ NSExtension
+
+ NSExtensionPointIdentifier
+ com.apple.usernotifications.service
+ NSExtensionPrincipalClass
+ NotificationService
+
+
+
diff --git a/UserNotifications/iOS/NotificationServiceExtension/NotificationService.cs b/UserNotifications/iOS/NotificationServiceExtension/NotificationService.cs
new file mode 100644
index 0000000..bb1a103
--- /dev/null
+++ b/UserNotifications/iOS/NotificationServiceExtension/NotificationService.cs
@@ -0,0 +1,37 @@
+using System;
+
+using Foundation;
+using ObjCRuntime;
+using UIKit;
+using UserNotifications;
+
+namespace NotificationServiceExtension
+{
+ [Register ("NotificationService")] // this must match the value of the 'NSExtensionPrincipalClass' key in the extension's Info.plist
+ public class NotificationService : UNNotificationServiceExtension
+ {
+ protected NotificationService (NativeHandle handle) : base (handle)
+ {
+ // Note: this .ctor should not contain any initialization logic.
+ }
+
+ public override void DidReceiveNotificationRequest(UNNotificationRequest request, Action contentHandler)
+ {
+ Console.WriteLine ($"UserNotifications.NotificationServiceExtension.DidReceiveNotificationRequest ({request})");
+
+ var newContent = (UNMutableNotificationContent) request.Content.MutableCopy ();
+
+ // Modify the notification content here...
+ newContent.Title = $"[modified] {newContent.Title}";
+
+ contentHandler (newContent);
+ }
+
+ public override void TimeWillExpire ()
+ {
+ // Called just before the extension will be terminated by the system.
+ // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
+ }
+ }
+}
+
diff --git a/UserNotifications/iOS/NotificationServiceExtension/NotificationServiceExtension.csproj b/UserNotifications/iOS/NotificationServiceExtension/NotificationServiceExtension.csproj
new file mode 100644
index 0000000..40612f1
--- /dev/null
+++ b/UserNotifications/iOS/NotificationServiceExtension/NotificationServiceExtension.csproj
@@ -0,0 +1,16 @@
+
+
+ net9.0-ios
+ Library
+ enable
+ enable
+ 15.0
+ com.rolfkvinge.usernotifications.notificationserviceextension
+ True
+ User Notifications Service Extension Profile
+
+
+
+
+
+
diff --git a/UserNotifications/iOS/README.md b/UserNotifications/iOS/README.md
new file mode 100644
index 0000000..91e79fa
--- /dev/null
+++ b/UserNotifications/iOS/README.md
@@ -0,0 +1,117 @@
+---
+name: User notifications in iOS
+description: "Demonstrates how to use user notifications in a .NET for iOS app"
+page_type: sample
+languages:
+- csharp
+products:
+- dotnet-macios
+urlFragment: usernotifications-ios
+---
+
+# User Notifications in iOS
+
+User Notifications is a sample app that accompanies the article [User notifications](https://learn.microsoft.com/en-us/dotnet/ios/app-fundamentals/user-notifications/user-notifications).
+
+It demonstrates how to delivery and handling of user notifications at runtime.
+
+Note that running this example project locally requires creating new app
+identifiers and provisioning profiles for both the main project and each app
+extension project, and then updating the bundle identifier (the
+`ApplicationId` in the project file) for each project according to the chosen
+app identifier.
+
+See the [User Notifications](https://learn.microsoft.com/en-us/dotnet/ios/app-fundamentals/user-notifications/user-notifications) article for more information.
+
+## Local notifications
+
+Clicking on the `Send Local Notification` button sends a local notification:
+
+[](LocalNotification.png)
+
+## Remote notification
+
+Sending a remote notification (for instance using Apple's Push Notification Console):
+
+[](RemoteNotification.png)
+
+Example payload:
+
+```json
+{
+ "aps": {
+ "alert": {
+ "title": "Hello From Apple's Push Notification Console",
+ "subtitle": "Subtitle",
+ "body": "Body" }
+ }
+}
+```
+
+## Modified remote notification using a Notification Service extension:
+
+Sending a remote notification (for instance using Apple's Push Notification
+Console), with the `mutable-content` key in the payload set to `1` makes the
+iOS device deliver the notification to any Notification Service extensions,
+which can modify the payload:
+
+[](ModifiedRemoteNotification.png)
+
+Example payload:
+
+```json
+{
+ "aps": {
+ "alert": {
+ "title": "Hello From Apple's Push Notification Console",
+ "subtitle": "Subtitle",
+ "body": "Body" },
+ "mutable-content": 1
+ }
+}
+```
+
+
+## Modified remote notification using a Notification Service extension:
+
+If the user long-presses a notification, iOS can display an extended interface
+for the notification if the app contains a Content Service extension:
+
+[](CustomizedExpandedRemoteNotification.png)
+
+This requires the `category` key in the payload to be set to a category listed in the `UNNotificationExtensionCategory` entry in the Notification Service extension's `Info.plist`.
+
+Example payload:
+
+```json
+{
+ "aps": {
+ "alert": {
+ "title": "Hello From Apple's Push Notification Console",
+ "subtitle": "Subtitle",
+ "body": "Body" },
+ "category": "general"
+ }
+}
+```
+
+## Both extensions at the same time
+
+Both a Notification Service extension and a Content Service extension can process a notification:
+
+[](CustomizedExpandedModifiedRemoteNotification.png)
+
+Example payload:
+
+```json
+{
+ "aps": {
+ "alert": {
+ "title": "Hello From Apple's Push Notification Console",
+ "subtitle": "Subtitle",
+ "body": "Body" },
+ "category": "general",
+ "mutable-content": 1
+ }
+}
+```
diff --git a/UserNotifications/iOS/RemoteNotification.png b/UserNotifications/iOS/RemoteNotification.png
new file mode 100644
index 0000000..9cfdd53
Binary files /dev/null and b/UserNotifications/iOS/RemoteNotification.png differ
diff --git a/UserNotifications/iOS/RemoteNotificationModified.png b/UserNotifications/iOS/RemoteNotificationModified.png
new file mode 100644
index 0000000..0ede6b3
Binary files /dev/null and b/UserNotifications/iOS/RemoteNotificationModified.png differ
diff --git a/UserNotifications/iOS/UserNotifications/AppDelegate.cs b/UserNotifications/iOS/UserNotifications/AppDelegate.cs
new file mode 100644
index 0000000..46e2bb8
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/AppDelegate.cs
@@ -0,0 +1,80 @@
+using UserNotifications;
+
+namespace NotificationTest;
+
+[Register ("AppDelegate")]
+public class AppDelegate : UIApplicationDelegate, IUNUserNotificationCenterDelegate {
+ public override UIWindow? Window {
+ get;
+ set;
+ }
+
+ public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
+ {
+ UNUserNotificationCenter.Current.Delegate = this;
+
+ UNNotificationAction dismissAction =
+ UNNotificationAction.FromIdentifier("dismiss", "Dismiss", UNNotificationActionOptions.Destructive);
+
+ UNNotificationCategory watchCategory = UNNotificationCategory.FromIdentifier("dismiss",
+ new[] { dismissAction }, [], "", UNNotificationCategoryOptions.None);
+
+ NSSet categories = new NSSet(watchCategory);
+ UNUserNotificationCenter.Current.SetNotificationCategories(categories);
+
+ var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound | UNAuthorizationOptions.Badge;
+ UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
+ {
+ System.Diagnostics.Debug.WriteLine($"Notification permission granted: {granted} (error: {error})");
+ if (granted)
+ UNUserNotificationCenter.Current.Delegate = new NotificationReceiver ();
+ });
+ UIApplication.SharedApplication.RegisterForRemoteNotifications();
+
+ Window = new UIWindow (UIScreen.MainScreen.Bounds);
+ Window.RootViewController = new RootViewController();
+ Window.MakeKeyAndVisible();
+ return true;
+ }
+
+ public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action completionHandler)
+ {
+ completionHandler(UNNotificationPresentationOptions.List | UNNotificationPresentationOptions.Banner |
+ UNNotificationPresentationOptions.Sound);
+ }
+
+ public override void RegisteredForRemoteNotifications(UIKit.UIApplication application, NSData deviceToken)
+ {
+ Console.WriteLine($"UserNotifications.AppDelegate.RegisteredForRemoteNotifications() Device Token: {deviceToken.DebugDescription}");
+ Console.WriteLine($"UserNotifications.AppDelegate.RegisteredForRemoteNotifications() Device Token Hex: {string.Join ("", deviceToken.ToArray ().Select (v => $"{v:x2}"))}");
+ }
+
+ public override void FailedToRegisterForRemoteNotifications(UIKit.UIApplication application, NSError error)
+ {
+ Console.WriteLine ($"UserNotifications.AppDelegate.FailedToRegisterForRemoteNotifications(): {error}");
+ }
+
+ public override void DidReceiveRemoteNotification (UIApplication application, NSDictionary userInfo, Action completionHandler)
+ {
+ Console.WriteLine ($"UserNotifications.AppDelegate.DidReceiveRemoteNotification ({userInfo})");
+ completionHandler (UIBackgroundFetchResult.NewData);
+ }
+}
+
+public class NotificationReceiver : UNUserNotificationCenterDelegate
+{
+ // Called if app is in the foreground.
+ public override void WillPresentNotification (UNUserNotificationCenter center, UNNotification notification, Action completionHandler)
+ {
+ var presentationOptions = UNNotificationPresentationOptions.Banner;
+ Console.WriteLine ($"UserNotifications.NotificationReceiver.WillPresentNotification ({notification}) => {presentationOptions}");
+ completionHandler (presentationOptions);
+ }
+
+ // Called if app is in the background, or killed state.
+ public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
+ {
+ Console.WriteLine ($"UserNotifications.NotificationReceiver.DidReceiveNotificationResponse ({response})");
+ completionHandler();
+ }
+}
\ No newline at end of file
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Contents.json b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..98f4d03
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,117 @@
+{
+ "images": [
+ {
+ "scale": "2x",
+ "size": "20x20",
+ "idiom": "iphone",
+ "filename": "Icon40.png"
+ },
+ {
+ "scale": "3x",
+ "size": "20x20",
+ "idiom": "iphone",
+ "filename": "Icon60.png"
+ },
+ {
+ "scale": "2x",
+ "size": "29x29",
+ "idiom": "iphone",
+ "filename": "Icon58.png"
+ },
+ {
+ "scale": "3x",
+ "size": "29x29",
+ "idiom": "iphone",
+ "filename": "Icon87.png"
+ },
+ {
+ "scale": "2x",
+ "size": "40x40",
+ "idiom": "iphone",
+ "filename": "Icon80.png"
+ },
+ {
+ "scale": "3x",
+ "size": "40x40",
+ "idiom": "iphone",
+ "filename": "Icon120.png"
+ },
+ {
+ "scale": "2x",
+ "size": "60x60",
+ "idiom": "iphone",
+ "filename": "Icon120.png"
+ },
+ {
+ "scale": "3x",
+ "size": "60x60",
+ "idiom": "iphone",
+ "filename": "Icon180.png"
+ },
+ {
+ "scale": "1x",
+ "size": "20x20",
+ "idiom": "ipad",
+ "filename": "Icon20.png"
+ },
+ {
+ "scale": "2x",
+ "size": "20x20",
+ "idiom": "ipad",
+ "filename": "Icon40.png"
+ },
+ {
+ "scale": "1x",
+ "size": "29x29",
+ "idiom": "ipad",
+ "filename": "Icon29.png"
+ },
+ {
+ "scale": "2x",
+ "size": "29x29",
+ "idiom": "ipad",
+ "filename": "Icon58.png"
+ },
+ {
+ "scale": "1x",
+ "size": "40x40",
+ "idiom": "ipad",
+ "filename": "Icon40.png"
+ },
+ {
+ "scale": "2x",
+ "size": "40x40",
+ "idiom": "ipad",
+ "filename": "Icon80.png"
+ },
+ {
+ "scale": "1x",
+ "size": "76x76",
+ "idiom": "ipad",
+ "filename": "Icon76.png"
+ },
+ {
+ "scale": "2x",
+ "size": "76x76",
+ "idiom": "ipad",
+ "filename": "Icon152.png"
+ },
+ {
+ "scale": "2x",
+ "size": "83.5x83.5",
+ "idiom": "ipad",
+ "filename": "Icon167.png"
+ },
+ {
+ "scale": "1x",
+ "size": "1024x1024",
+ "idiom": "ios-marketing",
+ "filename": "Icon1024.png"
+ }
+ ],
+ "properties": {},
+ "info": {
+ "version": 1,
+ "author": "xcode"
+ }
+}
\ No newline at end of file
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon1024.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon1024.png
new file mode 100644
index 0000000..b573205
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon1024.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon120.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon120.png
new file mode 100644
index 0000000..0b74155
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon120.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon152.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon152.png
new file mode 100644
index 0000000..1c19313
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon152.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon167.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon167.png
new file mode 100644
index 0000000..4e3e8bd
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon167.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon180.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon180.png
new file mode 100644
index 0000000..40a7371
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon180.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon20.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon20.png
new file mode 100644
index 0000000..8bb1383
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon20.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon29.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon29.png
new file mode 100644
index 0000000..bdd130c
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon29.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon40.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon40.png
new file mode 100644
index 0000000..75d2789
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon40.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon58.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon58.png
new file mode 100644
index 0000000..06afa60
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon58.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon60.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon60.png
new file mode 100644
index 0000000..2e0db2a
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon60.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon76.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon76.png
new file mode 100644
index 0000000..755bc88
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon76.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon80.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon80.png
new file mode 100644
index 0000000..6559bb4
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon80.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon87.png b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon87.png
new file mode 100644
index 0000000..ca28c8d
Binary files /dev/null and b/UserNotifications/iOS/UserNotifications/Assets.xcassets/AppIcon.appiconset/Icon87.png differ
diff --git a/UserNotifications/iOS/UserNotifications/Entitlements.plist b/UserNotifications/iOS/UserNotifications/Entitlements.plist
new file mode 100644
index 0000000..36a8706
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/UserNotifications/iOS/UserNotifications/Info.plist b/UserNotifications/iOS/UserNotifications/Info.plist
new file mode 100644
index 0000000..63d7162
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ CFBundleDisplayName
+ notificationTest
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1.0
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/AppIcon.appiconset
+
+
diff --git a/UserNotifications/iOS/UserNotifications/LaunchScreen.storyboard b/UserNotifications/iOS/UserNotifications/LaunchScreen.storyboard
new file mode 100644
index 0000000..2296c6b
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/LaunchScreen.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/UserNotifications/iOS/UserNotifications/Main.cs b/UserNotifications/iOS/UserNotifications/Main.cs
new file mode 100644
index 0000000..5c08649
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/Main.cs
@@ -0,0 +1,6 @@
+using NotificationTest;
+
+// This is the main entry point of the application.
+// If you want to use a different Application Delegate class from "AppDelegate"
+// you can specify it here.
+UIApplication.Main (args, null, typeof (AppDelegate));
diff --git a/UserNotifications/iOS/UserNotifications/Resources/LaunchScreen.xib b/UserNotifications/iOS/UserNotifications/Resources/LaunchScreen.xib
new file mode 100644
index 0000000..8190201
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/Resources/LaunchScreen.xib
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UserNotifications/iOS/UserNotifications/RootViewController.cs b/UserNotifications/iOS/UserNotifications/RootViewController.cs
new file mode 100644
index 0000000..0b0d8f8
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/RootViewController.cs
@@ -0,0 +1,44 @@
+using UserNotifications;
+
+namespace NotificationTest;
+
+[Register ("RootViewController")]
+public class RootViewController : UIViewController
+{
+ public override void ViewDidLoad ()
+ {
+ base.ViewDidLoad ();
+
+ if (View == null)
+ return;
+
+ View.BackgroundColor = UIColor.Black;
+
+ UIButton button = new UIButton (UIButtonType.Custom)
+ {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ BackgroundColor = UIColor.Purple
+ };
+ button.SetTitle ("Send Local Notification", UIControlState.Normal);
+ button.SetTitleColor (UIColor.White, UIControlState.Normal);
+ button.TouchUpInside += (sender, e) =>
+ {
+ var content = new UNMutableNotificationContent ()
+ {
+ Title = "Hi there",
+ Body = "Have a nice day",
+ Sound = UNNotificationSound.Default,
+ CategoryIdentifier = "general"
+ };
+ var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger (0.1f, false);
+ var request = UNNotificationRequest.FromIdentifier ("notificationTest", content, trigger);
+ UNUserNotificationCenter.Current.AddNotificationRequest (request, null);
+ };
+ View.AddSubview (button);
+
+ button.CenterYAnchor.ConstraintEqualTo (View.CenterYAnchor).Active = true;
+ button.LeadingAnchor.ConstraintEqualTo (View.LeadingAnchor).Active = true;
+ button.TrailingAnchor.ConstraintEqualTo (View.TrailingAnchor).Active = true;
+ button.HeightAnchor.ConstraintEqualTo (50).Active = true;
+ }
+}
diff --git a/UserNotifications/iOS/UserNotifications/SceneDelegate.cs b/UserNotifications/iOS/UserNotifications/SceneDelegate.cs
new file mode 100644
index 0000000..39fb70c
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/SceneDelegate.cs
@@ -0,0 +1,54 @@
+namespace NotificationTest;
+
+[Register ("SceneDelegate")]
+public class SceneDelegate : UIResponder, IUIWindowSceneDelegate {
+
+ [Export ("window")]
+ public UIWindow? Window { get; set; }
+
+ [Export ("scene:willConnectToSession:options:")]
+ public void WillConnect (UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
+ {
+ // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
+ // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
+ // This delegate does not imply the connecting scene or session are new (see UIApplicationDelegate `GetConfiguration` instead).
+ }
+
+ [Export ("sceneDidDisconnect:")]
+ public void DidDisconnect (UIScene scene)
+ {
+ // Called as the scene is being released by the system.
+ // This occurs shortly after the scene enters the background, or when its session is discarded.
+ // Release any resources associated with this scene that can be re-created the next time the scene connects.
+ // The scene may re-connect later, as its session was not neccessarily discarded (see UIApplicationDelegate `DidDiscardSceneSessions` instead).
+ }
+
+ [Export ("sceneDidBecomeActive:")]
+ public void DidBecomeActive (UIScene scene)
+ {
+ // Called when the scene has moved from an inactive state to an active state.
+ // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
+ }
+
+ [Export ("sceneWillResignActive:")]
+ public void WillResignActive (UIScene scene)
+ {
+ // Called when the scene will move from an active state to an inactive state.
+ // This may occur due to temporary interruptions (ex. an incoming phone call).
+ }
+
+ [Export ("sceneWillEnterForeground:")]
+ public void WillEnterForeground (UIScene scene)
+ {
+ // Called as the scene transitions from the background to the foreground.
+ // Use this method to undo the changes made on entering the background.
+ }
+
+ [Export ("sceneDidEnterBackground:")]
+ public void DidEnterBackground (UIScene scene)
+ {
+ // Called as the scene transitions from the foreground to the background.
+ // Use this method to save data, release shared resources, and store enough scene-specific state information
+ // to restore the scene back to its current state.
+ }
+}
diff --git a/UserNotifications/iOS/UserNotifications/UserNotifications.csproj b/UserNotifications/iOS/UserNotifications/UserNotifications.csproj
new file mode 100644
index 0000000..97e1ed3
--- /dev/null
+++ b/UserNotifications/iOS/UserNotifications/UserNotifications.csproj
@@ -0,0 +1,23 @@
+
+
+ net9.0-ios
+ Exe
+ enable
+ enable
+ 15.0
+ com.rolfkvinge.usernotifications
+ User Notifications Profile
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+