Core infrastructure, hosting, DI, key-value stores, lifecycle hooks, and platform abstractions for Shiny on .NET MAUI, iOS, and Android
Shiny.Core is the foundational library for the Shiny ecosystem. It provides the hosting model, dependency injection infrastructure, key-value storage, object-store binding, platform abstractions, lifecycle hooks, and reactive helpers that all other Shiny modules build upon. Companion support libraries add connectivity monitoring, battery status, file-based repositories, and remote configuration.
IHost, HostBuilder, or UseShinyIKeyValueStore, settings, secure store)IObjectStoreBinderIPlatform, directories, main thread invocation)IAndroidLifecycle, IIosLifecycle)IShinyStartupTask, IShinyComponentStartup, ShinyLifecycleTask)AccessState, permission handling, or PermissionExceptionIConnectivity) or battery status (IBattery)IRepository, IRepositoryEntity)IRemoteConfigurationProvider)WhenAnyProperty, SubscribeAsync, SelectSwitch, etc.)INotifyReadOnlyCollection<T>, INotifyCollectionChanged<T>, BindingList<T>)| Item | Value |
|---|---|
| NuGet | Shiny.Core |
| Namespace | Shiny, Shiny.Hosting, Shiny.Stores, Shiny.Net, Shiny.Power, Shiny.Collections |
| Platforms | iOS, Android, Mac Catalyst, Windows |
| NuGet | Namespace | Purpose |
|---|---|---|
Shiny.Hosting.Maui | Shiny | MAUI hosting integration (UseShiny) |
Shiny.Hosting.Native | Shiny | Native hosting base classes (ShinyAppDelegate, ShinyAndroidApplication, ShinyAndroidActivity) |
Shiny.Support.DeviceMonitoring | Shiny.Net, Shiny.Power | IConnectivity and IBattery |
Shiny.Support.Repositories | Shiny.Support.Repositories | IRepository and IRepositoryEntity |
Shiny.Extensions.Configuration | Shiny.Extensions.Configuration | Remote configuration and platform preferences |
In MauiProgram.cs, call UseShiny() on the MauiAppBuilder. This registers all core infrastructure services and lifecycle wiring automatically:
using Shiny;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseShiny(); // Registers Shiny core services and lifecycle hooks
// Register your own services using AddShinyService for auto-binding
builder.Services.AddShinyService<MySettings>();
// Add device monitoring
builder.Services.AddConnectivity();
builder.Services.AddBattery();
// Add repository
builder.Services.AddDefaultRepository();
return builder.Build();
}
}
For native iOS apps, inherit from ShinyAppDelegate:
[Register("AppDelegate")]
public class AppDelegate : ShinyAppDelegate
{
protected override IHost CreateShinyHost()
{
var builder = HostBuilder.Create();
// Register services on builder.Services
return builder.Build();
}
}
For native Android apps, inherit from ShinyAndroidApplication and use ShinyAndroidActivity:
[Application]
public class MainApplication : ShinyAndroidApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) {}
protected override IHost CreateShinyHost()
{
var builder = HostBuilder.Create();
// Register services on builder.Services
return builder.Build();
}
}
[Activity(MainLauncher = true)]
public class MainActivity : ShinyAndroidActivity { }
When generating code that uses Shiny.Core, follow these conventions:
UseShiny() in MAUI apps or inherit the proper native base classes. This is required before any Shiny module works.AddShinyService<T>() to register singleton services that implement interfaces. It auto-registers all interfaces, binds INotifyPropertyChanged objects to persistent storage, and calls ComponentStart() on IShinyComponentStartup implementations.IShinyStartupTask for code that should run immediately after the DI container is built. Register it with services.AddSingleton<IShinyStartupTask, MyTask>().ShinyLifecycleTask for startup tasks that also need foreground/background lifecycle events. Override OnStateChanged(bool backgrounding) and Start().IAndroidLifecycle.* or IIosLifecycle.* sub-interfaces for platform-specific lifecycle hooks. Register them in DI and the lifecycle executor dispatches to them automatically.IKeyValueStore for simple key-value persistence. Use IKeyValueStoreFactory to retrieve named stores ("settings", "secure", "memory").[ObjectStoreBinder("storeAlias")] to control which store backs an INotifyPropertyChanged object.NotifyPropertyChanged base class for view models and settings objects that should persist through the object store binder. It provides Set<T>() and RaisePropertyChanged().IPlatform to access AppData, Cache, Public directories and InvokeOnMainThread().AccessState enum and state.Assert() extension method to validate permissions before proceeding with platform operations.WhenAnyProperty, SubscribeAsync, SelectSwitch, DisposedBy) for composing observable streams.IConnectivity.WhenChanged() and IBattery.WhenChanged()** for reactive monitoring of device state.IRepository for entity persistence, with entities implementing IRepositoryEntity (must have an Identifier property).NotifyPropertyChanged.Tasks/ or Infrastructure/ folder.Settings/ or Models/ folder.AccessState.Denied, AccessState.Disabled, and AccessState.NotSetup gracefully.System.Reactive (IObservable<T>) for event streams, not C# events.Shiny namespace are available when the appropriate package is referenced.When using Shiny in a MAUI app, several Shiny types collide with MAUI implicit usings. Do NOT add all Shiny namespaces as global usings. Use explicit namespaces or FQNs for these:
| Type | Shiny Namespace | MAUI Namespace | Resolution |
|---|---|---|---|
IConnectivity | Shiny.Net | Microsoft.Maui.Networking | Use Shiny.Net.IConnectivity FQN |
IBattery | Shiny.Power | Microsoft.Maui.Devices | Use Shiny.Power.IBattery FQN |
DeviceInfo | Shiny.BluetoothLE | Microsoft.Maui.Devices | Use FQN for whichever you need |
Safe global usings (won't conflict with MAUI):
global using Shiny;
global using Shiny.Stores;
global using Shiny.Jobs;
global using Shiny.Locations;
global using Shiny.BluetoothLE;
// Do NOT globally use: Shiny.Net, Shiny.Power, Shiny.Notifications, Shiny.Push, Shiny.BluetoothLE.Hosting
UseShiny() must be called in the builder chain before building the MAUI app. For native apps, the host must be created and Run() called in the application startup.AddShinyService<T> over manual DI registration for types that implement interfaces or INotifyPropertyChanged. It handles all the wiring automatically.IShinyStartupTask.Start() runs synchronously on the main thread at startup."settings" for general preferences (backed by SharedPreferences/NSUserDefaults), "secure" for sensitive data (backed by Android Keystore/iOS Keychain).DisposedBy(CompositeDisposable) to manage subscription lifetimes.StoreExtensions.Get<T>() for type-safe retrieval with default values. Use GetRequired<T>() when a missing key should throw.SetOrRemove() to automatically clean up null/default values from the store.Host.IsInitialized before accessing Host.Current in code that may run before initialization.BindingList<T> for thread-safe observable collections that can be bound to UI.ShinySubject<T> instead of raw Subject<T> for error-safe multicasting with logging support.