Shiny .NET Framework

repository·v5·Indexed 23 days ago

https://github.com/shinyorg/shiny

A cross-platform framework for .NET designed to simplify device services and background processes. Shiny provides modules for Background Jobs, HTTP Transfers, Data Sync, BluetoothLE (Client & Hosting), Locations, Contacts, Calendar, and Notifications. It is Native AOT and trim-friendly, supporting iOS, Android, macOS, Windows, Linux, and Blazor WebAssembly. It also includes optional extensions to expose module operations as AI tools for LLM agents via Microsoft.Extensions.AI.

Tokens
71.3K
Snippets
155
Records
273
Agent score
81%

What's inside Shiny

  1. Overview of Shiny Client for .NET

    v5

    Shiny is a cross-platform framework designed to simplify working with device services and background processes. It provides a structured way to implement dependency injection, logging, and platform-specific features while handling complex tasks like permissions, main thread traversal, persistent storage, and app restarts.

    Shiny is designed to be Native AOT and trim-friendly. It supports a wide range of platforms including iOS, Android, Mac Catalyst, macOS, Windows, Linux, and Blazor WebAssembly (where platform capabilities allow).

  2. Available Shiny Modules

    v5

    Shiny is composed of several specialized modules that provide access to device capabilities:

    • Background Jobs: Periodic background work using platform-native schedulers (e.g., BGTaskScheduler on iOS, WorkManager on Android).
    • HTTP Transfers: Resumable background uploads/downloads with pause/resume support. Includes builders for Azure Blob Storage and AWS S3 (SigV4).
    • Data Sync: Bidirectional JSON record sync over HTTP with outbox/inbox patterns, conflict resolution, and exponential backoff.
    • BluetoothLE Client & Hosting: Support for scanning, connecting, GATT, L2CAP CoC, and advertising across multiple platforms.
    • Locations: Foreground/background GPS, geofence monitoring, and motion-activity recognition.
    • Contacts: Cross-platform CRUD access to device contacts with a fluent async query builder.
    • Calendar: Cross-platform calendar and event access with a fluent async query builder.
    • Local Notifications: Scheduled, repeating, and geofence-triggered notifications.
    • Push Notifications: Support for APNs, FCM, Azure Notification Hubs, and Web Push.
    • Core: The foundation providing hosting, DI, key/value stores, object-store binding, lifecycle hooks, and connectivity/battery monitoring.
  3. What is Shiny Data Sync and when to use it

    v5

    Shiny Data Sync provides reliable, background-capable bidirectional JSON synchronization between a mobile/desktop app and an HTTP backend. It is designed for structured records rather than large files.

    Use this skill for:

    • Syncing app entities to a REST backend reliably (even offline or in the background).
    • Building offline-first features with eventual consistency.
    • Queuing Create/Update/Delete operations that must survive app kills or device reboots.
    • Pulling server-side changes on a schedule (delta sync).
    • Resolving sync conflicts (HTTP 409 / 412) with custom logic.
    • Batching multiple queued operations into a single server round-trip.
    • Persisting per-endpoint cursors for delta pulls.

    Do NOT use this skill for:

    • Large file uploads/downloads (use shiny-http-transfers).
    • Realtime data streams (use SignalR/MQTT).
    • Push-driven sync (use shiny-push to trigger PullNow).
  4. Understand RegistrationToken vs NativeRegistrationToken

    v5

    When communicating with your backend server, it is important to distinguish between the two types of tokens available on IPushManager:

    • RegistrationToken: The provider-level token (e.g., the Azure Notification Hubs InstallationId). Use this for your backend.
    • NativeRegistrationToken: The raw OS-level token (e.g., the FCM token on Android or the APNs device token on iOS).
  5. Platform-specific Behavior and Limitations

    v5

    The behavior of ICalendarStore varies significantly depending on the underlying operating system:

    • Apple (EventKit):
      • Attendees cannot be written: Any Attendees set during creation or updates are ignored.
      • Reminders use a relative lead-time.
    • Android (CalendarContract):
      • Event CRUD works with permissions.
      • Creating or modifying calendars uses sync-adapter semantics and may behave differently depending on the device manufacturer (OEM).
    • Windows (AppointmentStore):
      • Best-effort support: Reads and queries cover all calendars.
      • Write restrictions: Create, update, and delete operations only work within an app-owned calendar. Attempting to write to a system calendar will throw a NotSupportedException.
      • Requires the appointments capability.
  6. How IBleHostingManager works

    v5

    The IBleHostingManager is the primary service for BLE peripheral hosting, typically injected via Dependency Injection as a singleton. It manages advertising, GATT server services, and L2CAP channels.

    Key workflows include:

    1. Requesting Access: Use RequestAccess(bool advertise, bool connect) to ensure the app has permissions for advertising and GATT connections.
    2. Advertising: Use StartAdvertising(AdvertisementOptions?) to begin broadcasting or AdvertiseBeacon(...) to act as an iBeacon.
    3. GATT Server Management: Use AddService(...) to define services and their characteristics, or AttachRegisteredServices() to attach services configured via DI.
  7. Understand the Sample.Api storage layout

    v5

    The API uses Shiny.DocumentDb.Sqlite for persistence. The following files and structures are used:

    • app.db: The SQLite document store containing three tables: todos, sync_changes, and files.
    • uploads/{id}: A directory containing the raw bytes for each uploaded file. The metadata for these files is stored in the files table.

    To completely reset the application state, delete both the app.db file and the uploads/ directory.

  8. How Shiny.Jobs works on different platforms

    v5

    Shiny.Jobs behaves differently depending on the target platform:

    • iOS & Android: Uses native OS schedulers (BGTaskScheduler on iOS and AndroidX WorkManager on Android).
    • Windows: Uses COM-activated in-process background tasks.
    • Plain .NET (Linux, macOS, Console, Blazor WASM): Runs an in-process managed JobManager driven by a recurring timer (default 30s, configurable via JobManager.Interval between 15s and 5 minutes). Jobs only run while the host process is alive.

    Blazor WASM Warning: Background jobs only run while the browser tab is open and foregrounded. Service Workers cannot invoke C# jobs because they lack access to the Blazor WASM runtime. For true background HTTP work in Blazor, use Shiny.Net.Http.Blazor.

  9. Configure ConnectionConfig and AndroidConnectionConfig

    v5

    Use ConnectionConfig to manage connection behavior.

    • On Android, setting AutoConnect to false can speed up the initial connection at the cost of disabling auto-reconnect.
    • On iOS, AutoConnect controls whether the system reconnects automatically.

    AndroidConnectionConfig adds ConnectionPriority (e.g., GattConnectionPriority.Balanced) for Android devices.

    // Android: false disables auto-reconnect but speeds up initial connection
    // iOS: controls whether to reconnect automatically
    public record ConnectionConfig(bool AutoConnect = true);
    
    public record AndroidConnectionConfig(
        bool AutoConnect = true,
        GattConnectionPriority ConnectionPriority = GattConnectionPriority.Balanced
    ) : ConnectionConfig(AutoConnect);
  10. PushAccessState and AccessState

    v5

    The PushAccessState record describes the current status of push notification permissions and provides the registration token.

    AccessState Values

    • Available: Permission granted and ready.
    • Denied: Permission explicitly denied.
    • Restricted: Permission restricted by OS settings.
    • Disabled: Push is disabled.
    • NotSetup: Push is not configured.
    • NotSupported: Platform does not support push.
    • Unknown: State is unknown.

    Usage

    You can call PushAccessState.Assert() to throw a PermissionException if the status is not Available.

    public record PushAccessState(
        AccessState Status,
        string? RegistrationToken
    )
    {
        public static PushAccessState Denied { get; }
        public void Assert(); // Throws PermissionException if Status != Available
    }
  11. Register services using Shiny DI attributes

    v5

    Shiny provides source-generated dependency injection via Shiny.Extensions.DependencyInjection. Instead of manual registration, decorate your classes with attributes. The source generator will then pick them up when you call AddGeneratedServices() during host construction.

    Supported attributes:

    • [Service(ServiceLifetime.Singleton)] (or the shortcut [Singleton])
    • [Scoped]
    • [Transient]

    This approach supports multiple interfaces, keyed services, and open generics automatically.

  12. Configure GpsRequest for background modes

    v5

    Use GpsRequest to define how the GPS listener should behave, specifically regarding background execution.

    GpsBackgroundMode options:

    • None: No background mode.
    • Standard:
      • iOS: Significant Location Changes.
      • Android: BACKGROUND mode (receives 3-4 updates per hour).
    • Realtime:
      • iOS: Full background request (updates every 1 second).
      • Android: Foreground Service (updates every 1 second).

    Factory Methods:

    • GpsRequest.Foreground: Creates a request with GpsBackgroundMode.None and RequestPreciseAccuracy = false.
    • GpsRequest.Background: Creates a request with GpsBackgroundMode.None and RequestPreciseAccuracy = false.
    • GpsRequest.Realtime(bool requestPreciseAccuracy): Creates a request with GpsBackgroundMode.Realtime.