Skip to content
Shiny.NET

Shiny Core

Shiny.Core is the package every other Shiny module sits on. You rarely reference it on purpose, because Jobs, Locations, BluetoothLE, Push and the rest all pull it in. It is still worth knowing what it gives you, since a lot of it is useful in your own code.

GitHub GitHub stars for shinyorg/shiny
Downloads NuGet downloads for Shiny.Core
Frameworks
.NET
.NET MAUI
Blazor
Operating Systems
Android
iOS
tvOS
macOS
Windows
Linux
Web

Host

HostBuilder and IHost build the DI container, run startup tasks, and expose a static Host.Current so platform callbacks can find your services, even when the OS starts the app in the background with no UI.

Platform abstraction

IPlatform gives every platform the same app-data, cache and public directories, plus main-thread marshalling. The concrete AndroidPlatform also handles runtime permissions, activity tracking and intents. Platform →

Lifecycle hooks

You implement IAndroidLifecycle.*, IIosLifecycle.* or IMacLifecycle.*, register the class, and Shiny calls it for app foreground/background, deep links, push tokens, activity results and more. Lifecycle Hooks →

Startup tasks

IShinyStartupTask runs as soon as the container is built. ShinyLifecycleTask does the same and also receives foreground/background changes on every platform. Startup Tasks →

Device monitoring

IConnectivity and IBattery report network reachability, connection types, charge level and charging state, with plain C# Changed events. Device Monitoring →

Permissions

AccessState is the one permission result used by every module. Assert() and PermissionException turn a bad state into a clear error. Access & Permissions →

It also includes a few small utilities that Shiny’s own modules use: NotifyPropertyChanged, a thread-safe BindingList<T>, DisposableCollection, and a delegate runner. See Utilities.

Storage and DI registration are separate packages that Shiny.Core depends on, so you get them automatically:

  • Stores (Shiny.Extensions.Stores): IKeyValueStore, the secure store, [Bind] persisted settings, and IRepository
  • Dependency Injection (Shiny.Extensions.DependencyInjection): the [Singleton] / [Scoped] / [Transient] source generator that emits AddGeneratedServices()
Package Use it for
Shiny.Core The core itself. Targets net10.0, Android, iOS, tvOS, Mac Catalyst, macOS and Windows. The net10.0 build also covers Linux and Blazor WebAssembly, choosing their implementations at runtime
Shiny.Hosting.Maui UseShiny() for .NET MAUI apps, including macOS (AppKit) apps on Microsoft.Maui.Platforms.MacOS. See MAUI hosting
Shiny.Hosting.Native ShinyAppDelegate, ShinyAndroidApplication and ShinyAndroidActivity for apps without MAUI, and the only way to host on tvOS. See Native hosting

Shiny.Core.Linux and Shiny.Core.Blazor are no longer published - remove them and keep Shiny.Core.

Most apps never touch the host directly, because the hosting model builds and runs it for you:

// .NET MAUI - every head, including macOS (AppKit) and Linux GTK
builder.UseShiny();
// Blazor WebAssembly - after Build(), before RunAsync()
await host.Services.UseShiny();

What the hosting layer does, and what you do yourself in a console, service, or Linux desktop app, looks like this:

using Shiny;
using Shiny.Hosting;
using Shiny.Infrastructure;
var builder = HostBuilder.Create();
// Platform TFMs (Android, iOS, macOS, Windows...) call this inside Build().
// Plain net10.0 has no hosting layer, so a console/service host (or GTK without MAUI) calls it itself.
builder.Services.AddShinyCoreServices();
builder.Services.AddConnectivity();
builder.Services.AddBattery();
builder.Services.AddGeneratedServices(); // your [Singleton]/[Scoped]/[Transient] classes
builder.Logging.AddConsole();
using IHost host = builder.Build();
host.Run(); // runs every IShinyStartupTask, then sets Host.Current

HostBuilder.Create(services, loggingBuilder) can wrap an existing IServiceCollection / ILoggingBuilder. That is how UseShiny() shares MAUI’s container. To use a third-party container, set ConfigureContainer:

builder.ConfigureContainer = services => new MyContainerAdapter(services).BuildServiceProvider();
Platform Registrations
All AddShinyStores(): the default and secure IKeyValueStore, IKeyValueStoreFactory
Android AndroidPlatform (also as IPlatform), AndroidLifecycleExecutor (runs as a startup task)
iOS / tvOS / Mac Catalyst IosPlatform (also as IPlatform), IosLifecycleExecutor (runs as a startup task)
macOS (AppKit) MacPlatform (also as IPlatform), MacLifecycleExecutor (runs as a startup task)
Windows WindowsPlatform (also as IPlatform)
Plain net10.0 NetPlatform (also as IPlatform). There is no lifecycle executor, because nothing tells a console app that it went to the background

IConnectivity and IBattery are not registered by AddShinyCoreServices. Modules that need them (Jobs, HTTP Transfers, Data Sync) add them on the platform targets. On plain net10.0 call AddConnectivity() / AddBattery() yourself. Both use TryAdd, so calling them again after a module has already registered them does nothing, and your own implementation registered before the module call is kept. See Device Monitoring.

Some code runs where constructor injection can’t reach it: an Android BroadcastReceiver, a Service the OS recreated after killing the process, or an AppDelegate callback. For that code, Shiny.Hosting.Host exposes the running host:

Member Description
Host.Current The running IHost. Throws InvalidOperationException with a setup hint before Run() has been called
Host.IsInitialized true once Run() has completed. Check it before touching Current in code that can run early
Host.ServiceProvider / Host.GetService<T>() Resolve from the container
Host.LoggingFactory The host’s ILoggerFactory
Host.Platform The concrete platform (AndroidPlatform, IosPlatform, MacPlatform) on those TFMs
Host.Lifecycle The platform lifecycle executor. This is what manual hosting forwards OS events into

As of v5, Shiny.Core has no dependency on System.Reactive. IConnectivity, IBattery and the lifecycle hooks all use plain C# events or interfaces, which keeps Core AOT- and trim-clean. When you want Rx semantics, wrap an event yourself with Observable.FromEventPattern.

claude plugin marketplace add shinyorg/skills
claude plugin install shiny@shiny

One plugin installs all 48 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.

copilot plugin marketplace add https://github.com/shinyorg/skills
copilot plugin install shiny@shiny

One plugin installs all 48 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.

View shiny-core Skill