From 818209657d31e09bc30161182ceb662a4ab272bc Mon Sep 17 00:00:00 2001 From: Fadi George Date: Wed, 8 Jul 2026 15:06:12 -0700 Subject: [PATCH 1/6] fix(examples): add iOS delegate shim for OneSignal compatibility --- examples/plugin-local-notif/MauiProgram.cs | 13 +++++++- ...OneSignalCompatibleNotificationDelegate.cs | 30 +++++++++++++++++++ examples/plugin-local-notif/README.md | 18 ++++++++--- 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs diff --git a/examples/plugin-local-notif/MauiProgram.cs b/examples/plugin-local-notif/MauiProgram.cs index 16002d69..1ef1edc1 100644 --- a/examples/plugin-local-notif/MauiProgram.cs +++ b/examples/plugin-local-notif/MauiProgram.cs @@ -12,7 +12,18 @@ public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); - builder.UseMauiApp().UseLocalNotification(); + builder.UseMauiApp() + .UseLocalNotification(options => + { +#if IOS + options.AddiOS(ios => + { + ios.SetCustomUserNotificationCenterDelegate( + new OneSignalCompatibleNotificationDelegate() + ); + }); +#endif + }); var app = builder.Build(); diff --git a/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs b/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs new file mode 100644 index 00000000..29c78184 --- /dev/null +++ b/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs @@ -0,0 +1,30 @@ +using Foundation; +using Plugin.LocalNotification.Platforms; +using UserNotifications; + +namespace PluginLocalNotifDemo; + +public sealed class OneSignalCompatibleNotificationDelegate : UserNotificationCenterDelegate +{ + // OneSignal's swizzle forwards to prefixed selectors; exporting them gives + // Xamarin a managed target while preserving Plugin.LocalNotification handling. + [Export("onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler:")] + public void OneSignalWillPresentNotification( + UNUserNotificationCenter center, + UNNotification notification, + Action completionHandler + ) + { + WillPresentNotification(center, notification, completionHandler); + } + + [Export("onesignalUserNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")] + public void OneSignalDidReceiveNotificationResponse( + UNUserNotificationCenter center, + UNNotificationResponse response, + Action completionHandler + ) + { + DidReceiveNotificationResponse(center, response, completionHandler); + } +} diff --git a/examples/plugin-local-notif/README.md b/examples/plugin-local-notif/README.md index bc7a0194..035da141 100644 --- a/examples/plugin-local-notif/README.md +++ b/examples/plugin-local-notif/README.md @@ -23,7 +23,9 @@ onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler: Both failures point at the same interaction: OneSignal's native iOS SDK swizzles `UNUserNotificationCenterDelegate` methods, while `Plugin.LocalNotification` -installs its own delegate that only implements the normal Apple selectors. +installs its own delegate that only implements the normal Apple selectors. This +sample registers a small iOS delegate shim so the OneSignal-prefixed selectors +can be marshalled back to Plugin.LocalNotification's normal handlers. ## Run @@ -50,7 +52,15 @@ devices. 3. Tap `Request LocalNotification Permission`. 4. Tap `Show Local Notification` while the app is foregrounded. 5. If the notification is delivered, tap it from Notification Center. -6. Watch device logs for the `onesignalUserNotificationCenter:*` selector crash. +6. Send a OneSignal push while the app is foregrounded, then send another while + the app is backgrounded and tap it from Notification Center. +7. Watch device logs to confirm the `onesignalUserNotificationCenter:*` selector + paths no longer crash. + +To reproduce the original issue #132 crash, remove the +`OneSignalCompatibleNotificationDelegate` registration from `MauiProgram.cs` and +delete `Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs`, then repeat +the iOS push steps. The bundled app ID matches the main demo app's default ID when `ONESIGNAL_APP_ID` is missing or still set to the placeholder. To test against a @@ -61,5 +71,5 @@ different OneSignal app, set `ONESIGNAL_APP_ID` in `.env`. The native OneSignal iOS SDK now documents disabling swizzling via `OneSignal_disable_swizzling` and manually forwarding notification delegate methods. This .NET binding currently does not expose the newer manual forwarding -APIs, so this sample keeps swizzling enabled and demonstrates the reported -interaction directly. +APIs, so this sample keeps swizzling enabled and uses the delegate shim as a +local compatibility workaround. From 35a3e8c14eab319666c73ba26a1d9e9d5f4bfa34 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Wed, 8 Jul 2026 20:18:09 -0700 Subject: [PATCH 2/6] chore(examples): add OneSignal notification button --- examples/plugin-local-notif/.env.example | 1 - examples/plugin-local-notif/DotEnv.cs | 7 +++ examples/plugin-local-notif/MainPage.cs | 70 ++++++++++++++++++++++ examples/plugin-local-notif/MauiProgram.cs | 17 +++--- examples/plugin-local-notif/README.md | 6 +- 5 files changed, 88 insertions(+), 13 deletions(-) diff --git a/examples/plugin-local-notif/.env.example b/examples/plugin-local-notif/.env.example index 96620213..2c398f31 100644 --- a/examples/plugin-local-notif/.env.example +++ b/examples/plugin-local-notif/.env.example @@ -1,2 +1 @@ -# Default App ID (used when ONESIGNAL_APP_ID is empty or missing): 77e32082-ea27-42e3-a898-c72e141824ef ONESIGNAL_APP_ID=your-onesignal-app-id diff --git a/examples/plugin-local-notif/DotEnv.cs b/examples/plugin-local-notif/DotEnv.cs index 3ff7262c..43d32061 100644 --- a/examples/plugin-local-notif/DotEnv.cs +++ b/examples/plugin-local-notif/DotEnv.cs @@ -2,6 +2,8 @@ namespace PluginLocalNotifDemo; public static class DotEnv { + public const string OneSignalAppIdPlaceholder = "your-onesignal-app-id"; + private static readonly Dictionary Values = new(); private static bool _loaded; @@ -54,4 +56,9 @@ var line in reader.ReadToEnd().Split('\n', StringSplitOptions.RemoveEmptyEntries } public static string Get(string key) => Values.TryGetValue(key, out var value) ? value : ""; + + public static string OneSignalAppId => Get("ONESIGNAL_APP_ID").Trim(); + + public static bool HasOneSignalAppId => + !string.IsNullOrWhiteSpace(OneSignalAppId) && OneSignalAppId != OneSignalAppIdPlaceholder; } diff --git a/examples/plugin-local-notif/MainPage.cs b/examples/plugin-local-notif/MainPage.cs index b3c2dea0..77c1e836 100644 --- a/examples/plugin-local-notif/MainPage.cs +++ b/examples/plugin-local-notif/MainPage.cs @@ -1,3 +1,5 @@ +using System.Text; +using System.Text.Json; using OneSignalSDK.DotNet; using OneSignalSDK.DotNet.Core.Notifications; using OneSignalSDK.DotNet.Core.User; @@ -44,6 +46,12 @@ public MainPage() }; requestOneSignalPermissionButton.Clicked += async (s, e) => { + if (!DotEnv.HasOneSignalAppId) + { + SetStatus("Set ONESIGNAL_APP_ID in .env before requesting OneSignal permission."); + return; + } + var granted = await OneSignal.Notifications.RequestPermissionAsync(true); SetStatus($"OneSignal permission granted: {granted}"); RefreshPermissionLabel(); @@ -88,6 +96,24 @@ public MainPage() ); }; + var showOneSignalNotificationButton = new Button + { + Text = "Show OneSignal Notification", + AutomationId = "show_onesignal_notification_button", + }; + showOneSignalNotificationButton.Clicked += async (s, e) => + { + showOneSignalNotificationButton.IsEnabled = false; + try + { + await SendSimpleOneSignalNotificationAsync(); + } + finally + { + showOneSignalNotificationButton.IsEnabled = true; + } + }; + var clearButton = new Button { Text = "Clear Delivered Notifications", @@ -133,6 +159,7 @@ public MainPage() requestOneSignalPermissionButton, requestLocalPermissionButton, showLocalNotificationButton, + showOneSignalNotificationButton, clearButton, refreshPushInfoButton, _statusLabel, @@ -185,6 +212,49 @@ private void OnUserChanged(object? sender, UserStateChangedEventArgs args) MainThread.BeginInvokeOnMainThread(RefreshPushInfoLabel); } + private async Task SendSimpleOneSignalNotificationAsync() + { + if (!DotEnv.HasOneSignalAppId) + { + SetStatus("Set ONESIGNAL_APP_ID in .env before sending a OneSignal notification."); + return; + } + + var pushSubscriptionId = OneSignal.User.PushSubscription.Id; + if (string.IsNullOrWhiteSpace(pushSubscriptionId)) + { + SetStatus("No OneSignal push subscription ID yet. Refresh after permission is granted."); + return; + } + + using var client = new HttpClient(); + client.DefaultRequestHeaders.Add("Accept", "application/vnd.onesignal.v1+json"); + + var payload = new Dictionary + { + ["app_id"] = DotEnv.OneSignalAppId, + ["headings"] = new Dictionary { ["en"] = "Simple Notification" }, + ["contents"] = new Dictionary + { + ["en"] = "This is a simple push notification", + }, + ["include_subscription_ids"] = new[] { pushSubscriptionId }, + }; + + var json = JsonSerializer.Serialize(payload); + var response = await client.PostAsync( + "https://onesignal.com/api/v1/notifications", + new StringContent(json, Encoding.UTF8, "application/json") + ); + var responseJson = await response.Content.ReadAsStringAsync(); + + SetStatus( + response.IsSuccessStatusCode + ? $"OneSignal notification requested: {responseJson}" + : $"OneSignal notification failed: {responseJson}" + ); + } + private void SetStatus(string message) { MainThread.BeginInvokeOnMainThread(() => diff --git a/examples/plugin-local-notif/MauiProgram.cs b/examples/plugin-local-notif/MauiProgram.cs index 1ef1edc1..26654d36 100644 --- a/examples/plugin-local-notif/MauiProgram.cs +++ b/examples/plugin-local-notif/MauiProgram.cs @@ -6,8 +6,6 @@ namespace PluginLocalNotifDemo; public static class MauiProgram { - private const string DefaultAppId = "77e32082-ea27-42e3-a898-c72e141824ef"; - public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); @@ -29,14 +27,15 @@ public static MauiApp CreateMauiApp() DotEnv.Load(); - var envAppId = DotEnv.Get("ONESIGNAL_APP_ID"); - var appId = - string.IsNullOrWhiteSpace(envAppId) || envAppId == "your-onesignal-app-id" - ? DefaultAppId - : envAppId.Trim(); - OneSignal.Debug.LogLevel = OsLogLevel.VERBOSE; - OneSignal.Initialize(appId); + if (DotEnv.HasOneSignalAppId) + { + OneSignal.Initialize(DotEnv.OneSignalAppId); + } + else + { + System.Diagnostics.Debug.WriteLine("Set ONESIGNAL_APP_ID in .env to initialize OneSignal."); + } OneSignal.Notifications.WillDisplay += (s, e) => System.Diagnostics.Debug.WriteLine("OneSignal notification will display"); diff --git a/examples/plugin-local-notif/README.md b/examples/plugin-local-notif/README.md index 035da141..e8ea663d 100644 --- a/examples/plugin-local-notif/README.md +++ b/examples/plugin-local-notif/README.md @@ -33,6 +33,7 @@ From this directory, run iOS: ```sh cp .env.example .env +# Set ONESIGNAL_APP_ID in .env before launching. ./run-ios.sh ``` @@ -62,9 +63,8 @@ To reproduce the original issue #132 crash, remove the delete `Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs`, then repeat the iOS push steps. -The bundled app ID matches the main demo app's default ID when -`ONESIGNAL_APP_ID` is missing or still set to the placeholder. To test against a -different OneSignal app, set `ONESIGNAL_APP_ID` in `.env`. +Set `ONESIGNAL_APP_ID` in `.env` before running the sample. The app does not +fall back to a built-in OneSignal app id. ## Notes From c8dd9c05184b0e4484ccaad66b7d7e443d008f0f Mon Sep 17 00:00:00 2001 From: Fadi George Date: Wed, 8 Jul 2026 20:32:19 -0700 Subject: [PATCH 3/6] fix(examples): handle remote push in delegate shim --- examples/plugin-local-notif/MainPage.cs | 7 +-- ...OneSignalCompatibleNotificationDelegate.cs | 63 +++++++++++++++++-- examples/plugin-local-notif/README.md | 11 +++- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/examples/plugin-local-notif/MainPage.cs b/examples/plugin-local-notif/MainPage.cs index 77c1e836..f2aed882 100644 --- a/examples/plugin-local-notif/MainPage.cs +++ b/examples/plugin-local-notif/MainPage.cs @@ -187,10 +187,9 @@ private void RefreshPushInfoLabel() { var pushSubscription = OneSignal.User.PushSubscription; _pushInfoLabel.Text = - $"OneSignal ID: {FormatValue(OneSignal.User.OneSignalId)}\n" - + $"Push subscription ID: {FormatValue(pushSubscription.Id)}\n" - + $"Push opted in: {pushSubscription.OptedIn}\n" - + $"Push token: {FormatValue(pushSubscription.Token)}"; + $"OneSignal ID:\n{FormatValue(OneSignal.User.OneSignalId)}\n" + + $"Push subscription ID:\n{FormatValue(pushSubscription.Id)}\n" + + $"Push opted in: {pushSubscription.OptedIn}"; } private void OnPermissionChanged(object? sender, NotificationPermissionChangedEventArgs args) diff --git a/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs b/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs index 29c78184..334ca082 100644 --- a/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs +++ b/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs @@ -6,8 +6,37 @@ namespace PluginLocalNotifDemo; public sealed class OneSignalCompatibleNotificationDelegate : UserNotificationCenterDelegate { - // OneSignal's swizzle forwards to prefixed selectors; exporting them gives - // Xamarin a managed target while preserving Plugin.LocalNotification handling. + // OneSignal's swizzle can exchange method implementations on this class, so + // depending on which slot iOS invokes, either the normal overrides or the + // onesignal-prefixed exports receive the callback. Both route remote pushes + // to foreground presentation and leave local notifications to the plugin. + public override void WillPresentNotification( + UNUserNotificationCenter center, + UNNotification notification, + Action completionHandler + ) + { + if (HandledAsRemotePush(notification, completionHandler)) + return; + + base.WillPresentNotification(center, notification, completionHandler); + } + + public override void DidReceiveNotificationResponse( + UNUserNotificationCenter center, + UNNotificationResponse response, + Action completionHandler + ) + { + if (response.Notification.Request.Trigger is UNPushNotificationTrigger) + { + completionHandler(); + return; + } + + base.DidReceiveNotificationResponse(center, response, completionHandler); + } + [Export("onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler:")] public void OneSignalWillPresentNotification( UNUserNotificationCenter center, @@ -15,7 +44,10 @@ public void OneSignalWillPresentNotification( Action completionHandler ) { - WillPresentNotification(center, notification, completionHandler); + if (HandledAsRemotePush(notification, completionHandler)) + return; + + base.WillPresentNotification(center, notification, completionHandler); } [Export("onesignalUserNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")] @@ -25,6 +57,29 @@ public void OneSignalDidReceiveNotificationResponse( Action completionHandler ) { - DidReceiveNotificationResponse(center, response, completionHandler); + if (response.Notification.Request.Trigger is UNPushNotificationTrigger) + { + completionHandler(); + return; + } + + base.DidReceiveNotificationResponse(center, response, completionHandler); + } + + private static bool HandledAsRemotePush( + UNNotification notification, + Action completionHandler + ) + { + if (notification.Request.Trigger is not UNPushNotificationTrigger) + return false; + + completionHandler( + UNNotificationPresentationOptions.Banner + | UNNotificationPresentationOptions.List + | UNNotificationPresentationOptions.Sound + | UNNotificationPresentationOptions.Badge + ); + return true; } } diff --git a/examples/plugin-local-notif/README.md b/examples/plugin-local-notif/README.md index e8ea663d..f270119d 100644 --- a/examples/plugin-local-notif/README.md +++ b/examples/plugin-local-notif/README.md @@ -24,8 +24,9 @@ onesignalUserNotificationCenter:willPresentNotification:withCompletionHandler: Both failures point at the same interaction: OneSignal's native iOS SDK swizzles `UNUserNotificationCenterDelegate` methods, while `Plugin.LocalNotification` installs its own delegate that only implements the normal Apple selectors. This -sample registers a small iOS delegate shim so the OneSignal-prefixed selectors -can be marshalled back to Plugin.LocalNotification's normal handlers. +sample registers a small iOS delegate shim that exports the OneSignal-prefixed +selectors and overrides the plugin's normal handlers. Remote pushes are shown as +foreground banners; local notifications keep the plugin's behavior. ## Run @@ -73,3 +74,9 @@ The native OneSignal iOS SDK now documents disabling swizzling via methods. This .NET binding currently does not expose the newer manual forwarding APIs, so this sample keeps swizzling enabled and uses the delegate shim as a local compatibility workaround. + +Because OneSignal's swizzle exchanges implementations on the shim class, the +normal delegate callbacks bypass OneSignal's own notification processing. With +this workaround, OneSignal iOS foreground lifecycle events (`WillDisplay`, +`Clicked`) may not fire; the durable fix is exposing the manual forwarding APIs +in the binding. From f8ab9aad73e1bd9520f3b1d33ac72ffac83dae0d Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 21 Jul 2026 15:23:17 -0700 Subject: [PATCH 4/6] docs: [SDK-4788] clarify local notification workaround Co-authored-by: Cursor --- examples/plugin-local-notif/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/plugin-local-notif/README.md b/examples/plugin-local-notif/README.md index f270119d..03f125be 100644 --- a/examples/plugin-local-notif/README.md +++ b/examples/plugin-local-notif/README.md @@ -3,6 +3,11 @@ Minimal .NET MAUI app for investigating the iOS interaction reported in [GitHub issue #132](https://github.com/OneSignal/OneSignal-DotNet-SDK/issues/132). +This example is a temporary compatibility workaround, not a first-party +OneSignal local notification implementation. OneSignal hopes to support local +notifications directly in a future SDK release, at which point that support +should replace this delegate shim. No release timeline is currently committed. + ## What This Reproduces Issue #132 reports an iOS crash when `OneSignalSDK.DotNet` and From ee49195606d861d14a490ea32470823970846527 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 21 Jul 2026 15:48:10 -0700 Subject: [PATCH 5/6] style(examples): reformat long lines --- examples/plugin-local-notif/MainPage.cs | 4 +++- examples/plugin-local-notif/MauiProgram.cs | 7 +++++-- .../iOS/OneSignalCompatibleNotificationDelegate.cs | 4 +++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/plugin-local-notif/MainPage.cs b/examples/plugin-local-notif/MainPage.cs index f2aed882..66e64176 100644 --- a/examples/plugin-local-notif/MainPage.cs +++ b/examples/plugin-local-notif/MainPage.cs @@ -222,7 +222,9 @@ private async Task SendSimpleOneSignalNotificationAsync() var pushSubscriptionId = OneSignal.User.PushSubscription.Id; if (string.IsNullOrWhiteSpace(pushSubscriptionId)) { - SetStatus("No OneSignal push subscription ID yet. Refresh after permission is granted."); + SetStatus( + "No OneSignal push subscription ID yet. Refresh after permission is granted." + ); return; } diff --git a/examples/plugin-local-notif/MauiProgram.cs b/examples/plugin-local-notif/MauiProgram.cs index 26654d36..e61bc674 100644 --- a/examples/plugin-local-notif/MauiProgram.cs +++ b/examples/plugin-local-notif/MauiProgram.cs @@ -10,7 +10,8 @@ public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); - builder.UseMauiApp() + builder + .UseMauiApp() .UseLocalNotification(options => { #if IOS @@ -34,7 +35,9 @@ public static MauiApp CreateMauiApp() } else { - System.Diagnostics.Debug.WriteLine("Set ONESIGNAL_APP_ID in .env to initialize OneSignal."); + System.Diagnostics.Debug.WriteLine( + "Set ONESIGNAL_APP_ID in .env to initialize OneSignal." + ); } OneSignal.Notifications.WillDisplay += (s, e) => diff --git a/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs b/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs index 334ca082..cf21c4e4 100644 --- a/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs +++ b/examples/plugin-local-notif/Platforms/iOS/OneSignalCompatibleNotificationDelegate.cs @@ -50,7 +50,9 @@ Action completionHandler base.WillPresentNotification(center, notification, completionHandler); } - [Export("onesignalUserNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")] + [Export( + "onesignalUserNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:" + )] public void OneSignalDidReceiveNotificationResponse( UNUserNotificationCenter center, UNNotificationResponse response, From faf965ea08a563a4a6947c5d07328ca2feeb25b3 Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 21 Jul 2026 16:17:29 -0700 Subject: [PATCH 6/6] fix: [SDK-4788] handle notification demo failures Co-authored-by: Cursor --- examples/plugin-local-notif/MainPage.cs | 31 ++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/examples/plugin-local-notif/MainPage.cs b/examples/plugin-local-notif/MainPage.cs index 66e64176..025281e1 100644 --- a/examples/plugin-local-notif/MainPage.cs +++ b/examples/plugin-local-notif/MainPage.cs @@ -35,9 +35,12 @@ public MainPage() LineBreakMode = LineBreakMode.WordWrap, }; - OneSignal.Notifications.PermissionChanged += OnPermissionChanged; - OneSignal.User.PushSubscription.Changed += OnPushSubscriptionChanged; - OneSignal.User.Changed += OnUserChanged; + if (DotEnv.HasOneSignalAppId) + { + OneSignal.Notifications.PermissionChanged += OnPermissionChanged; + OneSignal.User.PushSubscription.Changed += OnPushSubscriptionChanged; + OneSignal.User.Changed += OnUserChanged; + } var requestOneSignalPermissionButton = new Button { @@ -108,6 +111,10 @@ public MainPage() { await SendSimpleOneSignalNotificationAsync(); } + catch (Exception exception) + { + SetStatus($"OneSignal notification failed: {exception.Message}"); + } finally { showOneSignalNotificationButton.IsEnabled = true; @@ -121,6 +128,12 @@ public MainPage() }; clearButton.Clicked += (s, e) => { + if (!DotEnv.HasOneSignalAppId) + { + SetStatus("Set ONESIGNAL_APP_ID in .env before clearing OneSignal notifications."); + return; + } + OneSignal.Notifications.ClearAllNotifications(); SetStatus("Cleared delivered notifications through OneSignal."); }; @@ -180,11 +193,23 @@ protected override void OnAppearing() private void RefreshPermissionLabel() { + if (!DotEnv.HasOneSignalAppId) + { + _permissionLabel.Text = "OneSignal permission: unavailable (app ID not set)"; + return; + } + _permissionLabel.Text = $"OneSignal permission: {OneSignal.Notifications.Permission}"; } private void RefreshPushInfoLabel() { + if (!DotEnv.HasOneSignalAppId) + { + _pushInfoLabel.Text = "OneSignal push subscription: unavailable (app ID not set)"; + return; + } + var pushSubscription = OneSignal.User.PushSubscription; _pushInfoLabel.Text = $"OneSignal ID:\n{FormatValue(OneSignal.User.OneSignalId)}\n"