Shiny.ScreenRecorder
5.6.0-beta-0072
Prefix Reserved
dotnet add package Shiny.ScreenRecorder --version 5.6.0-beta-0072
NuGet\Install-Package Shiny.ScreenRecorder -Version 5.6.0-beta-0072
<PackageReference Include="Shiny.ScreenRecorder" Version="5.6.0-beta-0072" />
<PackageVersion Include="Shiny.ScreenRecorder" Version="5.6.0-beta-0072" />
<PackageReference Include="Shiny.ScreenRecorder" />
paket add Shiny.ScreenRecorder --version 5.6.0-beta-0072
#r "nuget: Shiny.ScreenRecorder, 5.6.0-beta-0072"
#:package Shiny.ScreenRecorder@5.6.0-beta-0072
#addin nuget:?package=Shiny.ScreenRecorder&version=5.6.0-beta-0072&prerelease
#tool nuget:?package=Shiny.ScreenRecorder&version=5.6.0-beta-0072&prerelease
Shiny Client for .NET
<img src="https://github.com/shinyorg/shiny/raw/master/art/logo.png" width="100" />
Shiny is a cross-platform framework designed to make working with device services and background processes easy, testable, and consistent while bringing things like dependency injection & logging in a structured way to your code!
Features
- Handles all of the cruft like Permissions, main thread traversal, persistent storage and app restarts
- Brings your infrastructure to the background
- Provides logging to ensure you know when your services fail in the background
- Gives a clean & testable API surface for your code
- Native AOT & trim-friendly across all modules
- Cross-platform: iOS, Android, Mac Catalyst, macOS, Windows, Linux, and Blazor WebAssembly (where the platform allows)
Modules
- Background Jobs - periodic background work backed by
BGTaskScheduler(iOS),WorkManager(Android), COM-activated background tasks (Windows), and an in-process managed runner for Linux/macOS/Blazor WASM - HTTP Transfers - resumable background uploads/downloads on
NSURLSession(iOS), anHttpClient-driven managed loop with Range-based resume (Android, Windows, Linux, macOS, .NET base), and Service Worker Background Sync (Blazor WASM). Pause/resume support - pause stops a transfer without cancelling it (downloads continue from where they left off, uploads restart). First-class Azure Blob Storage and AWS S3 (SigV4) request builders included - Data Sync - bidirectional JSON record sync over HTTP with the same platform tiers as HTTP Transfers: outbox + inbox on
NSURLSession(iOS/Mac Catalyst), Foreground Service + HttpClient (Android),HttpClient+ connectivity loop (Windows/Linux/macOS), and LocalStorage-backed HttpClient (Blazor WASM). Includes batched outbox, tombstones, conflict resolution, retry with exponential backoff, and AOT-safe serialization throughShiny.Json - Network Discovery - three local-network discovery protocols in one package, each with browse, resolve, and publish
- mDNS/DNS-SD (Bonjour/Zeroconf) - backed by
NSNetServiceon iOS/Mac Catalyst/macOS (so nocom.apple.developer.networking.multicastentitlement is needed),NsdManageron Android (no multicast lock), and a dependency-free managed responder on UDP 5353 for Windows, Linux, macOS console, and server .NET.await foreach (var r in mdns.Browse("_http._tcp", ct))for live discovery,BrowseOnce(...)for a one-shot scan, andPublish(...)to advertise your own service with TXT metadata - SSDP/UPnP - find routers, media servers, Sonos, Roku, and smart TVs.
ssdp.SearchAll()for a one-shot sweep,Browse(...)for a live list keyed on UDN withssdp:alive/byebyetracking and BOOTID-aware expiry,GetDescription(...)to fetch and parse the device description (friendly name, model, icons, service list), andPublish(...)to advertise your own root device. Discovery and description only - no SOAP action invocation, no GENA eventing - WS-Discovery - find ONVIF cameras, WSD printers/scanners, and Windows machines. Probe/Resolve/Hello/Bye on both the 2005 (ONVIF/Windows) and 2009 (OASIS) profiles, with correct QName-prefix resolution for
Types, RFC 3986 segment-prefix scope matching, andProbeOnvifCameras(...)as a shortcut - Platform requirements differ by protocol. mDNS needs no entitlement anywhere. SSDP and WS-Discovery have no OS-level API on any platform, so they use raw multicast: iOS requires the Apple-approved
com.apple.developer.networking.multicastentitlement, Android needsCHANGE_WIFI_MULTICAST_STATE(the multicast lock is acquired for you) plusACCESS_LOCAL_NETWORKfrom Android 17. Sandboxed hosts still need their usual network permission -com.apple.security.network.client/.serveron Mac Catalyst & macOS,privateNetworkClientServerfor packaged Windows apps. A missing one throwsDiscoveryPermissionExceptionnaming exactly what to add, rather than silently finding nothing
- mDNS/DNS-SD (Bonjour/Zeroconf) - backed by
- Wi-Fi - scan for access points, join and leave networks, manage the networks the device has saved, watch the current network's SSID/signal/IP/DNS, and host a hotspot
- Platform reach is genuinely uneven, and the API says so rather than pretending otherwise. Every manager publishes a
WifiCapabilitiesflags property; anything unavailable throwsWifiNotSupportedExceptionnaming the specific limit (an Apple entitlement, an Android API level that revoked the call, a platform with no such concept). Check the flag to branch, catch the exception as a backstop IWifiManager-Scan(ct)returns oneWifiNetworkper BSSID with SSID, security scheme, dBm + 0-100 signal, frequency, band and channel.Connect(new WifiConnectionRequest(ssid) { Passphrase = ... })joins and waits for DHCP rather than returning on association, and withRememberleft on also persists the network for later (aWifiNetworkSuggestionon Android 11+, an ordinary profile elsewhere).await GetCurrentNetwork(ct)reports the joined network - SSID, BSSID, security, signal, plus every IP, DNS resolver, gateway and mask - andChangedfires with the newWifiNetworkInfo?(null when Wi-Fi drops), de-duplicated so the chatty native watchers behind it do not leak through, delivering the current network once on subscribe. Reading the SSID is asynchronous because both phone platforms stopped answering synchronously: iOS 14 replacedCNCopyCurrentNetworkInfowithNEHotspotNetwork.fetchCurrent, and Android 12 redacts the SSID and BSSID out of every pull-style read no matter what permissions are held, handing them out only through aNetworkCallbackregistered withFLAG_INCLUDE_LOCATION_INFO- Known networks -
GetKnownNetworks()lists what the device has saved asKnownWifiNetwork(opaque platformId, SSID, security, hidden),Forget(id)deletes one, andConnect(id)rejoins one without handing the passphrase over again. The scope differs and the API says which: iOS/Mac Catalyst and Android only ever disclose your own app's entries (NEHotspotConfigurationManager.getConfiguredSSIDs, network suggestions), while Windows, macOS and Linux hand back every profile on the machine.Connect(id)works on Windows, macOS, Linux and Android below API 29 - iOS and modern Android treat a saved network as a standing hint the OS acts on, with no call to force it. TheIdis the platform's own handle: a NetworkManager connection UUID on Linux, a numeric network id on legacy Android, the SSID everywhere else IWifiHotspot-Start(...)returns anIHotspotSessioncarrying the SSID and passphrase actually in use; dispose it to bring the access point down.GetClients()lists joined devices with MAC and address on Windows and Linux. Android raises a local-only hotspot (clients reach the device, not the internet) and picks the SSID/passphrase itself, Windows shares the machine's internet connection, Linux runs NetworkManager AP mode with DHCP + NAT, and iOS/macOS have no hotspot API at all- Backends -
WifiManager+ConnectivityManageron Android (specifier-based joins from API 29, legacyWifiConfigurationbelow),NEHotspotConfiguration+ CaptiveNetwork on iOS/Mac Catalyst, CoreWLAN on macOS,WiFiAdapter+NetworkOperatorTetheringManager+Radioon Windows, and NetworkManager over D-Bus on Linux (separateShiny.Net.Wifi.Linuxpackage). Saved profiles are outside WinRT entirely, so Windows reacheswlanapi.dlldirectly for those three calls. The plain .NET target still reports IP/DNS off the wireless interface and raisesChanged; the Wi-Fi-specific calls throw - Permissions - Android needs
ACCESS_WIFI_STATE,CHANGE_WIFI_STATE,ACCESS_FINE_LOCATIONandNEARBY_WIFI_DEVICES(API 33+); iOS needs the Hotspot Configuration and Access WiFi Information capabilities plusNSLocationWhenInUseUsageDescription; macOS needs the location usage description; Windows needswiFiControlandradios; Linux gates the mutating calls behind polkit. A scan that comes back empty because location was refused throwsWifiPermissionExceptioninstead of looking like an empty neighbourhood
- Platform reach is genuinely uneven, and the API says so rather than pretending otherwise. Every manager publishes a
- Screen Recording - record the screen to an MP4 with optional microphone and system audio
- What "the screen" means is not the same everywhere, and the API says so rather than pretending otherwise. Android, macOS, Windows and Linux record the system screen, so other apps end up in the file. iOS and Mac Catalyst record your own app's UI only - that is all ReplayKit offers without a Broadcast Upload Extension, which a NuGet package cannot deliver. Every recorder publishes a
ScreenRecorderCapabilitiesflags property; anything unavailable throwsScreenRecorderNotSupportedExceptionnaming the specific limit. The flags are read off the instance because they differ within a platform: macOS 15 gains microphone capture and loses pause (SCRecordingOutputwrites the file itself and cannot be detached mid-recording) where macOS 12.3-14 has it the other way round IScreenRecorder-await recorder.Start(new ScreenRecordingRequest { IncludeMicrophone = true, MaxWidth = 1280 })returns anIScreenRecordingthat does not come back until frames are genuinely being written - so a consent dialog, a compositor picker or an Android foreground-service promotion all complete first.Pause()/Resume()close the gap in the timeline rather than leaving a frozen stretch,Stop()returns aScreenRecordingResultwith the path, duration, size and theMimeTypeactually produced (browsers disagree - Safari and Chrome give MP4, Firefox gives WebM), and disposing without stopping cancels and deletes the partial file. A request asking for something outsideCapabilitiesthrows before any native call, because a recording that silently came out without the microphone is worse than one that refused to startGetTargets()lists displays, windows and applications on macOS and Windows, so an app can offer its own picker. Linux and the browser hand selection to the compositor and throw here - their picker appears duringStartinstead- The OS ending it on its own is a first-class outcome.
IScreenRecording.Faultedfires with a reason - the user hit Android's cast notification or the browser's "Stop sharing" bar, iOS took the screen for an incoming call, a monitor was unplugged, the encoder failed - and carries whatever was salvaged, so a recording cut short still yields a playable file rather than a silent truncation.MaxDurationstops cleanly and reports the same way - Backends - MediaProjection + MediaCodec/MediaMuxer on Android (MediaRecorder takes a single audio source and playback capture is not one of them, so app audio forces the whole pipeline down to MediaCodec), ReplayKit
startCaptureinto anAVAssetWriteron iOS/Mac Catalyst (startRecordingonly surrenders its file through a share sheet, which is no use to a library), ScreenCaptureKit on macOS -SCRecordingOutputon 15+ and the sameAVAssetWriterbelow it - Windows.Graphics.Capture into aMediaStreamSourcetranscoded by Media Foundation on Windows, and the xdg-desktop-portal ScreenCast API drivinggst-launch-1.0orffmpegon Linux (separateShiny.ScreenRecorder.Linuxpackage). Blazor WebAssembly usesgetDisplayMedia+MediaRecorder(separateShiny.ScreenRecorder.Blazorpackage) and is the only platform where pause is native and the result has no file path - there is no filesystem, soOpenRead()is the portable accessor - Permissions - Android needs
FOREGROUND_SERVICE,FOREGROUND_SERVICE_MEDIA_PROJECTIONandRECORD_AUDIOfor audio, plus a per-recording consent dialog that cannot be pre-granted; iOS needsNSMicrophoneUsageDescriptionand the app in the foreground; macOS needs the Screen Recording grant (and a relaunch after it is first given); Windows needs 1903+ and thegraphicsCapturecapability when packaged; Linux needs a portal plus GStreamer or FFmpeg, all probed at runtime so a machine missing them reportsNonerather than failing at record time. Windows has no audio at all -Windows.Graphics.Capturecaptures pixels only
- What "the screen" means is not the same everywhere, and the API says so rather than pretending otherwise. Android, macOS, Windows and Linux record the system screen, so other apps end up in the file. iOS and Mac Catalyst record your own app's UI only - that is all ReplayKit offers without a Broadcast Upload Extension, which a NuGet package cannot deliver. Every recorder publishes a
- BluetoothLE Client - scan, connect, GATT, and L2CAP CoC on iOS/macOS, Android, Windows, Linux (BlueZ), and Blazor WebAssembly (Web Bluetooth). L2CAP file transfers in both directions -
await peripheral.UploadFile(psm, path, onProgress: ...)/DownloadFile(...)- with the same transfer metrics as HTTP Transfers (percent complete, bytes/sec, ETA), plus Rx*WithProgressvariants.IPeripheral.Mtureports the usable payload per GATT operation (the negotiated ATT MTU minus the 3-byte ATT header) on every platform - fragment writes to it directly.ConnectionConfig(AutoConnect: true)- the default - keeps the link up on every platform, re-establishing it after a peripheral drops out of range or is power-cycled, whileCancelConnection()stays final - BluetoothLE Hosting - GATT server, advertising, iBeacon broadcasting, and L2CAP CoC listeners on iOS/macOS, Android, Windows, and Linux (BlueZ AF_BLUETOOTH sockets).
OpenL2CapFileServer(rootDirectory)turns a PSM into a file server that connected centrals can push to and pull from, with size limits, per-request authorization, path-traversal protection, and progress callbacks. A bundled source generator turns[BleService]/[L2CapService]partial classes into the imperative registrations for you - handler signatures bind by type, GATT status and offset handling is generated, and each connected central gets a partial{Service}Contextyou can stamp your own properties onto (all reflection-free, so it stays AOT-safe) - Locations - foreground/background GPS, geofence monitoring, and motion-activity recognition (CMMotionActivity / ActivityRecognition)
- iOS authorization escalates, and
RequestAccessnow escalates with it. ACLServiceSessionis bound to the requirement it was opened under, so the when-in-use session a foreground request creates is replaced (not reused) when a background request later needs always - an existing always session still covers a foreground request, so a background grant is never torn down to ask for less. Ask from the feature that needs it: the system presents the "always" upgrade prompt once, and that moment is the only one where you can say why.AccessState.Restrictedis what when-in-use reports as when a background request asks about it - "granted, but not for what you asked for", not "blocked"
- iOS authorization escalates, and
- Contacts - cross-platform device contact access with CRUD and a fluent async query builder (iOS/Android):
await store.Query().Search(text).OrderBy(ContactSortField.FamilyName).ToListAsync(ct) - Calendar - cross-platform calendar & event access with CRUD and a fluent async query builder on iOS/Mac Catalyst/macOS (EventKit), Android (CalendarContract), and Windows (
AppointmentStore, best-effort - system events are read-only, writes go to an app-owned calendar).await store.Query().ForCalendar(id).Between(from, to).OrderBy(CalendarEventSortField.Start).ToListAsync(ct)- the calendar id and date window are pushed down to the native fetch, which runs off the calling thread.DeleteEvent(id, deleteSeries)chooses between removing one occurrence of a recurring event or the rest of the series - Local Notifications - scheduled, repeating, and geofence-triggered notifications on iOS/macOS, Android, Windows, and Linux (
org.freedesktop.NotificationsD-Bus) - Push Notifications - native APNs/FCM, Firebase Cloud Messaging, Azure Notification Hubs, and Blazor (Web Push)
- Core - hosting, DI, key/value stores, object-store binding, lifecycle hooks, connectivity & battery monitoring, and the platform abstractions every Shiny module builds on
AI Tools
Optional *.Extensions.AI packages expose Shiny modules as Microsoft.Extensions.AI tool functions (AIFunctions) for LLM agents. You opt-in exactly which operations the model can see - a read/write allow-list you control on behalf of the agent (this is not an OS permission prompt; the underlying platform permissions must already be granted). Resolve the generated *AITools bundle from DI and pass .Tools to any IChatClient. All are AOT-compatible (hand-built schemas, no reflection).
- Shiny.Contacts.Extensions.AI -
AddContactsAITools(...)→search_contacts,get_contact, and (write)create_contact,update_contact,delete_contact - Shiny.Calendar.Extensions.AI -
AddCalendarAITools(...)→list_calendars,search_events,get_event, and independently opt-increate_event,update_event,delete_event(per-operationRead/Create/Update/Deletecapability flags). Capabilities apply to every calendar by default, or per calendar id -AddCalendar(workId, All)alongside a globalReadgives the agent read-only access everywhere but read/write on one calendar, andNonehides a calendar entirely - Shiny.Notifications.Extensions.AI -
AddNotificationAITools(...)→ reminder-framedlist_reminders, and (write)create_reminder(one-time or daily),cancel_reminder - Shiny.Locations.Extensions.AI -
AddLocationAITool()→ read-onlyget_current_location,get_distance_to,estimate_travel_time
builder.Services.AddContactStore();
builder.Services.AddContactsAITools(b => b.AddContacts(ContactAICapabilities.ReadWrite));
builder.Services.AddNotifications();
builder.Services.AddNotificationAITools(b => b.AddReminders(ReminderAICapabilities.ReadWrite));
builder.Services.AddGps();
builder.Services.AddLocationAITool();
// later, hand the tools to a chat client
var tools = sp.GetRequiredService<ContactAITools>().Tools;
var response = await chatClient.GetResponseAsync(messages, new ChatOptions { Tools = [.. tools] });
Links
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-android36.0 is compatible. net10.0-browser was computed. net10.0-ios was computed. net10.0-ios26.0 is compatible. net10.0-maccatalyst was computed. net10.0-maccatalyst26.0 is compatible. net10.0-macos was computed. net10.0-macos26.0 is compatible. net10.0-tvos was computed. net10.0-windows was computed. net10.0-windows10.0.19041 is compatible. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.7)
- Microsoft.Extensions.Logging (>= 10.0.7)
- Shiny.Core (>= 5.6.0-beta-0072)
- Shiny.Extensions.DependencyInjection (>= 5.1.5)
- Shiny.Extensions.Serialization (>= 5.1.5)
- Shiny.Extensions.Stores (>= 5.1.5)
-
net10.0-android36.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.7)
- Microsoft.Extensions.Logging (>= 10.0.7)
- Shiny.Core (>= 5.6.0-beta-0072)
- Shiny.Extensions.DependencyInjection (>= 5.1.5)
- Shiny.Extensions.Serialization (>= 5.1.5)
- Shiny.Extensions.Stores (>= 5.1.5)
- Xamarin.AndroidX.Core (>= 1.19.0.1)
- Xamarin.AndroidX.Lifecycle.Common (>= 2.11.0.1)
- Xamarin.AndroidX.Lifecycle.Process (>= 2.11.0.1)
- Xamarin.AndroidX.Lifecycle.Runtime (>= 2.11.0.1)
- Xamarin.AndroidX.Lifecycle.Runtime.Android (>= 2.11.0.1)
-
net10.0-ios26.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.7)
- Microsoft.Extensions.Logging (>= 10.0.7)
- Shiny.Core (>= 5.6.0-beta-0072)
- Shiny.Extensions.DependencyInjection (>= 5.1.5)
- Shiny.Extensions.Serialization (>= 5.1.5)
- Shiny.Extensions.Stores (>= 5.1.5)
-
net10.0-maccatalyst26.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.7)
- Microsoft.Extensions.Logging (>= 10.0.7)
- Shiny.Core (>= 5.6.0-beta-0072)
- Shiny.Extensions.DependencyInjection (>= 5.1.5)
- Shiny.Extensions.Serialization (>= 5.1.5)
- Shiny.Extensions.Stores (>= 5.1.5)
-
net10.0-macos26.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.7)
- Microsoft.Extensions.Logging (>= 10.0.7)
- Shiny.Core (>= 5.6.0-beta-0072)
- Shiny.Extensions.DependencyInjection (>= 5.1.5)
- Shiny.Extensions.Serialization (>= 5.1.5)
- Shiny.Extensions.Stores (>= 5.1.5)
-
net10.0-windows10.0.19041
- Microsoft.Extensions.DependencyInjection (>= 10.0.7)
- Microsoft.Extensions.Logging (>= 10.0.7)
- Shiny.Core (>= 5.6.0-beta-0072)
- Shiny.Extensions.DependencyInjection (>= 5.1.5)
- Shiny.Extensions.Serialization (>= 5.1.5)
- Shiny.Extensions.Stores (>= 5.1.5)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Shiny.ScreenRecorder:
| Package | Downloads |
|---|---|
|
Shiny.ScreenRecorder.Blazor
Shiny Screen Recorder for Blazor WebAssembly - records the screen through getDisplayMedia and MediaRecorder, with optional microphone and tab audio |
|
|
Shiny.ScreenRecorder.Linux
Shiny Screen Recorder for Linux - records the screen through the xdg-desktop-portal ScreenCast API (Wayland and X11), encoding with GStreamer or FFmpeg |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.6.0-beta-0072 | 0 | 8/31/2026 |