Skip to content
Shiny.NET

Client Apps

Shiny.Push is the on-device half: it registers with the platform and hands your app a token in IPushDelegate.OnNewToken. This page covers the server half of that handoff. For the platform consoles and app setup, see the client Platform Setup.

Client platform Token from OnNewToken DevicePlatform Server transport
iOS, Mac Catalyst APNs device token (hex) iOS APNs
macOS APNs device token (hex) MacOS APNs
Android FCM registration token Android FCM
Windows WNS channel URI Windows WNS
Blazor WebAssembly PushSubscription serialized as JSON WebBrowser Web Push
Any, with Azure Notification Hubs hub installation id n/a Notification Hubs, not this library

The app sends its token, platform and environment (see the client’s Send the token to your server). One endpoint covers every platform:

record RegisterRequest(
string DeviceToken,
DevicePlatform Platform,
PushEnvironment Environment = PushEnvironment.Production,
string? DeviceId = null,
string? UserIdentifier = null);
app.MapPost("/push/register", async (RegisterRequest req, IPushManager push) =>
{
var registration = new DeviceRegistration
{
DeviceToken = req.DeviceToken,
Platform = req.Platform,
Environment = req.Environment,
DeviceId = req.DeviceId,
UserIdentifier = req.UserIdentifier
};
if (req.Platform == DevicePlatform.WebBrowser)
registration = WebPushSubscription.ToRegistration(registration);
await push.RegisterDevice(registration);
return Results.NoContent();
});

Add JsonStringEnumConverter to the HTTP JSON options if the app sends the enums as strings. Unregister with IPushManager.UnregisterDevice(token, platform) from the app’s OnUnRegistered.

Use the Environment the app reports. Debug-signed builds get sandbox tokens, while App Store and TestFlight builds get production tokens. The APNs transport routes each device to the matching host, and a token sent to the wrong one fails with BadDeviceToken.

With Shiny.Push.FirebaseMessaging, OnNewToken receives an FCM token on iOS, but the FCM transport only delivers to Android registrations. Either send IPushManager.NativeRegistrationToken (the APNs token) from iOS and register it as iOS for the APNs transport, or deliver those FCM tokens with your own sender.

On the web, Shiny.Push reports the whole browser subscription as JSON:

{ "endpoint": "https://fcm.googleapis.com/fcm/send/…", "expirationTime": null, "keys": { "p256dh": "…", "auth": "…" } }

The Web Push transport needs the endpoint as DeviceToken and the keys in Data:

using System.Text.Json;
static class WebPushSubscription
{
public static DeviceRegistration ToRegistration(DeviceRegistration registration)
{
using var doc = JsonDocument.Parse(registration.DeviceToken);
var root = doc.RootElement;
var keys = root.GetProperty("keys");
return registration with
{
DeviceToken = root.GetProperty("endpoint").GetString()!,
Data = new Dictionary<string, string>
{
["p256dh"] = keys.GetProperty("p256dh").GetString()!,
["auth"] = keys.GetProperty("auth").GetString()!
}
};
}
}

When the app unregisters, OnUnRegistered receives the same JSON, so parse out the endpoint before calling UnregisterDevice.

Client Make sure to
iOS Set Apple.ContentAvailable = true when OnReceived must run in the background. Apple throttles these.
Android Include Data so OnReceived fires, and put deep links in Data: DeepLink becomes click_action, which must match the app’s intent filter for OnEntry to fire.
Web Put deep links and anything the app needs in Data. The service worker only shows title, body and icon.
Windows Toasts are built from Title and Message. Use WindowsPushOptions.Payload for custom XML.