Platform.Maui.Essentials.TvOS 0.1.0-alpha-0001

This is a prerelease version of Platform.Maui.Essentials.TvOS.
dotnet add package Platform.Maui.Essentials.TvOS --version 0.1.0-alpha-0001
                    
NuGet\Install-Package Platform.Maui.Essentials.TvOS -Version 0.1.0-alpha-0001
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Platform.Maui.Essentials.TvOS" Version="0.1.0-alpha-0001" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Platform.Maui.Essentials.TvOS" Version="0.1.0-alpha-0001" />
                    
Directory.Packages.props
<PackageReference Include="Platform.Maui.Essentials.TvOS" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Platform.Maui.Essentials.TvOS --version 0.1.0-alpha-0001
                    
#r "nuget: Platform.Maui.Essentials.TvOS, 0.1.0-alpha-0001"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Platform.Maui.Essentials.TvOS@0.1.0-alpha-0001
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Platform.Maui.Essentials.TvOS&version=0.1.0-alpha-0001&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Platform.Maui.Essentials.TvOS&version=0.1.0-alpha-0001&prerelease
                    
Install as a Cake Tool

.NET MAUI Backends for Apple TV & macOS (AppKit)

Custom .NET MAUI backends targeting platforms not officially supported by MAUI — Apple TV (tvOS via UIKit) and macOS (native AppKit, not Mac Catalyst).

Both backends use the platform-agnostic MAUI NuGet packages (net10.0 fallback assemblies) and provide custom handler implementations that bridge MAUI's layout/rendering system to the native platform UI frameworks.

Samples

Videos are attached in the repo

Project Structure

src/
  Microsoft.Maui.Platform.TvOS/     # tvOS backend library (net10.0-tvos)
  Microsoft.Maui.Platform.MacOS/    # macOS AppKit backend library (net10.0-macos)
  Microsoft.Maui.Essentials.TvOS/   # tvOS Essentials library
  Microsoft.Maui.Essentials.MacOS/  # macOS Essentials library
samples/
  Sample/                           # Shared sample code (App.cs, MainPage.cs, Platforms/)
  SampleTv/                         # tvOS sample app (links files from Sample/)
  SampleMac/                        # macOS sample app (links files from Sample/)

Note: There is also a Sample/Sample.csproj that multitargets both net10.0-tvos and net10.0-macos, but it is not yet working. Use SampleTv and SampleMac to build and run the individual platform samples.

Handlers Implemented

Both platforms share the same set of control handlers:

Control tvOS (UIKit) macOS (AppKit)
Label UILabel NSTextField (non-editable)
Button UIButton NSButton
Entry UITextField NSTextField (editable)
Editor ❌ Not implemented NSTextView (multiline, in NSScrollView)
Picker UIButton + UIAlertController NSPopUpButton
Slider Custom TvOSSliderView NSSlider
Stepper ❌ Not implemented NSStepper
Switch UIButton (toggle, no native UISwitch on tvOS) NSSwitch
CheckBox ❌ Not available on tvOS NSButton (checkbox style)
RadioButton ❌ Not available on tvOS NSButton (radio style)
SearchBar Custom TvOSSearchBarView NSSearchField
ActivityIndicator UIActivityIndicatorView NSProgressIndicator
ProgressBar UIProgressView NSProgressIndicator (bar mode)
Image UIImageView NSImageView
ScrollView UIScrollView NSScrollView
ShapeView UIView + CAShapeLayer NSView + CAShapeLayer
Border UIView + CAShapeLayer (stroke + mask) NSView + CAShapeLayer (stroke + mask)
DatePicker ❌ No UIDatePicker on tvOS NSDatePicker (date mode)
TimePicker ❌ No UIDatePicker on tvOS NSDatePicker (time mode)
Shadow CALayer shadow properties CALayer shadow properties
Layout (Stack, Grid, etc.) TvOSContainerView MacOSContainerView
CollectionView UIScrollView (item materialization) NSScrollView (item materialization)
CarouselView UIScrollView (horizontal paging, snap-to-item) ❌ Not implemented
ContentPage TvOSContainerView MacOSContainerView
ContentView TvOSContainerView MacOSContainerView
FlyoutPage ❌ Not available on tvOS FlyoutContainerView (NSSplitView sidebar)
Toolbar ❌ Not available on tvOS NSToolbar (via Page.ToolbarItems)
BoxView via ShapeView via ShapeView
GraphicsView ❌ Not implemented MacOSGraphicsView (DirectRenderer + CoreGraphics)
NavigationPage NavigationContainerView (stack navigation) NavigationContainerView (stack navigation)
TabbedPage TabbedContainerView (custom tab bar) TabbedContainerView (NSSegmentedControl)
WebView ❌ Not available on tvOS WKWebView
MapView MKMapView (display-only) MKMapView (interactive)
BlazorWebView ❌ Not available on tvOS MacOSBlazorWebView + WKWebView

Infrastructure

Component tvOS macOS
Application NSObject NSObject
Window UIWindow + UIViewController NSWindow + FlippedNSView
Dispatcher GCD (DispatchQueue.MainQueue) GCD (DispatchQueue.MainQueue)
DispatcherTimer NSTimer NSTimer
Dialogs (Alert, Confirm, Prompt) ❌ Not supported (see below) NSAlert

Handler TODO

Controls

  • ImageButton
  • Stepper — tvOS ❌ (macOS ✅)
  • RadioButton — tvOS ❌ (macOS ✅)
  • Dialogs (Confirm, Prompt, Alert) - macOS ✅, tvOS ❌ (see Dialogs below)

Pages

  • IndicatorView

Collections

  • RefreshView
  • SwipeView

Platform TODO

General

  • Multitarget Sample project (net10.0-tvos;net10.0-macos in a single csproj)
  • XAML Compilation (currently C#-only pages work reliably)
  • Multi-window support
  • Modal page presentation
  • Keyboard/focus management
  • Accessibility support
  • Light/dark mode support (theme detection and dynamic colors) ✅
  • Font management (custom fonts, font families)
  • Gesture recognizers (Tap, Swipe, Pan, Pinch)

tvOS Specific

  • Focus Engine integration (visual focus states on controls)
  • Top Shelf extensions
  • TV remote menu button handling
  • TVUIKit integration (TVPosterView, TVMonogramView)

macOS Specific

  • Menu bar integration (NSMenu)
  • Touch Bar support
  • NSSecureTextField for Entry.IsPassword (currently no-op)
  • File dialogs (Open/Save panels)
  • Drag and drop
  • Multiple windows
  • Window lifecycle (minimize, fullscreen, close) ✅ (active, resign active, hide, unhide, terminate)

Broader Goals

  • WebView — macOS ✅ (WKWebView), tvOS ❌ (not supported by platform)
  • BlazorWebView — macOS ✅ (custom MacOSBlazorWebView control), tvOS ❌ (no WebView support)
  • App Icons (ideally via MAUI build tools / MauiIcon)
  • Essentials (platform-specific API wrappers) — AppInfo ✅, DeviceInfo ✅, Connectivity ✅, Battery ✅ (macOS only), DeviceDisplay ✅, FileSystem ✅, Preferences ✅, SecureStorage ✅, FilePicker ✅ (macOS only), MediaPicker ✅ (macOS only), TextToSpeech ✅, Clipboard ✅, Browser ✅ (macOS only), Share ✅ (macOS only), Launcher ✅ (macOS only) (see Essentials below)
  • NuGet packaging
  • CI/CD pipeline

Prerequisites

Important: JetBrains Rider and Visual Studio will not compile these projects. The net10.0-tvos and net10.0-macos TFMs are not recognized by IDE build systems. All building and running must be done through the CLI using the dotnet command.

.NET 10 SDK

Install the latest .NET 10 preview SDK from dotnet.microsoft.com.

Workloads (macOS only)

The tvOS and macOS workloads must be installed. These are only available on macOS (requires Xcode).

# Install both workloads
dotnet workload install tvos
dotnet workload install macos

# Verify they are installed
dotnet workload list

You should see output similar to:

Installed Workload Id    Manifest Version    Installation Source
-----------------------------------------------------------------
macos                    26.2.10197/10.0.100 SDK 10.0.100
tvos                     26.2.10197/10.0.100 SDK 10.0.100

Xcode

Xcode must be installed (for Apple platform SDKs and the tvOS simulator). Ensure the command-line tools are selected:

sudo xcode-select -s /Applications/Xcode.app

Building

All builds must be done via the CLI:

# Build the backend libraries
dotnet build src/Microsoft.Maui.Platform.TvOS/Microsoft.Maui.Platform.TvOS.csproj
dotnet build src/Microsoft.Maui.Platform.MacOS/Microsoft.Maui.Platform.MacOS.csproj

# Build the sample apps (use SampleTv / SampleMac, not Sample)
dotnet build samples/SampleTv/SampleTv.csproj
dotnet build samples/SampleMac/SampleMac.csproj

Note: Do not use dotnet build "MAUI Platforms.slnx" — the solution-level build may fail due to multitarget issues. Build projects individually instead. The Sample multitarget project is also not yet working — use SampleTv and SampleMac instead.

Running

tvOS (Simulator)

dotnet build samples/SampleTv/SampleTv.csproj -t:Run

This builds, deploys to the tvOS simulator, and launches the app in one step.

macOS

dotnet build samples/SampleMac/SampleMac.csproj
open samples/SampleMac/bin/Debug/net10.0-macos/osx-arm64/MAUI\ macOS.app

Key Technical Notes

  • MAUI NuGet packages resolve to the net10.0 (platform-agnostic) assembly for unsupported TFMs. This means ToPlatform() returns object — custom ViewExtensions casts to the native view type (UIView/NSView).
  • The platform-agnostic ViewHandler has no-op PlatformArrange and returns Size.Zero from GetDesiredSize. Custom base handlers (TvOSViewHandler/MacOSViewHandler) override these to bridge MAUI layout to native view frames.
  • macOS NSView uses bottom-left origin by default. All container views override IsFlipped => true for MAUI's top-left coordinate system.
  • macOS NSView has no SizeThatFits() — the base handler uses IntrinsicContentSize and FittingSize for native controls, and a custom SizeThatFits method on MacOSContainerView.
  • IButton does not have Text or TextColor directly — those are on IText and ITextStyle. Handlers cast via if (button is IText textButton).
  • Sample apps use pure C# pages (no XAML) to avoid XAML compilation issues on unsupported platforms.
  • NavigationPage dispatches navigation requests via Handler.Invoke() (the MAUI command mapper pattern), not direct method calls. The handler must register a CommandMapper entry for RequestNavigation and call NavigationFinished() on the view after completing navigation. The initial page is pushed automatically by MAUI's OnHandlerChangedCore.

Lifecycle Events

Both platforms fire IWindow lifecycle methods and support MAUI's ConfigureLifecycleEvents builder pattern for platform-specific event hooks.

IWindow Lifecycle

The base app delegates (MacOSMauiApplication, TvOSMauiApplication) automatically call the standard IWindow lifecycle methods:

IWindow Method macOS Trigger tvOS Trigger
Created() App launch App launch
Activated() App becomes active App becomes active
Deactivated() App loses active status App resigns activation
Stopped() App hidden (Cmd+H) App enters background
Resumed() App unhidden App enters foreground
Destroying() App terminating App terminating

Subscribe to these via MAUI's standard Window events:

protected override Window CreateWindow(IActivationState? activationState)
{
    var window = new Window(new MainPage());
    window.Activated += (s, e) => Console.WriteLine("Window Activated");
    window.Stopped += (s, e) => Console.WriteLine("Window Stopped");
    return window;
}

ConfigureLifecycleEvents (Platform-Specific)

For platform-specific lifecycle hooks with access to native arguments, use the ConfigureLifecycleEvents builder pattern:

macOS:

builder.ConfigureLifecycleEvents(events =>
{
    events.AddMacOS(macOS => macOS
        .DidFinishLaunching(notification => { /* NSNotification */ })
        .DidBecomeActive(notification => { })
        .DidResignActive(notification => { })
        .DidHide(notification => { })
        .DidUnhide(notification => { })
        .WillTerminate(notification => { })
    );
});

tvOS:

builder.ConfigureLifecycleEvents(events =>
{
    events.AddTvOS(tvOS => tvOS
        .FinishedLaunching(app => { /* UIApplication */ })
        .OnActivated(app => { })
        .OnResignActivation(app => { })
        .DidEnterBackground(app => { })
        .WillEnterForeground(app => { })
        .WillTerminate(app => { })
    );
});

BlazorWebView (macOS only)

The BlazorWebView implementation uses a custom MacOSBlazorWebView control instead of the MAUI package's BlazorWebView — the built-in control internally casts its handler to the iOS/Catalyst BlazorWebViewHandler, which fails on AppKit.

Architecture:

  • MacOSBlazorWebView — a simple View subclass with HostPage, StartPath, and RootComponents properties
  • BlazorWebViewHandler — creates a WKWebView with a custom app:// URL scheme handler and injects the Blazor interop script
  • MacOSWebViewManager — bridges WebViewManager (from Microsoft.AspNetCore.Components.WebView) to the native WKWebView
  • MacOSMauiAssetFileProvider — serves static content from the macOS app bundle's Resources/ directory
  • MacOSBlazorDispatcher — bridges MAUI's IDispatcher to Blazor's abstract Dispatcher

Usage:

using Microsoft.Maui.Platform.MacOS.Controls;

var blazorView = new MacOSBlazorWebView
{
    HostPage = "wwwroot/index.html",
    HeightRequest = 400
};
blazorView.RootComponents.Add(new BlazorRootComponent
{
    Selector = "#app",
    ComponentType = typeof(MyApp.Components.Counter)
});

Static web assets (wwwroot/) must be included as BundleResource items in the project file, and blazor.modules.json (an empty [] array) plus blazor.webview.js must be present under wwwroot/_framework/.

Essentials

Platform-specific implementations of MAUI Essentials APIs for both tvOS and macOS.

Supported APIs

API tvOS macOS Notes
AppInfo Package name, version, build, theme, layout direction
DeviceInfo Model, manufacturer, device name, OS version, platform, idiom, device type
Connectivity Network access status, connection profiles (WiFi), change events
Battery Charge level, state, power source, change events (IOKit). Not available on tvOS.
DeviceDisplay Screen dimensions, density, orientation, rotation, refresh rate, keep screen on
FileSystem Cache directory, app data directory, app package file access
Preferences Key/value storage via NSUserDefaults
SecureStorage Encrypted key/value storage via Keychain
FilePicker Single/multiple file picking via NSOpenPanel. Not available on tvOS.
MediaPicker Photo/video picking via NSOpenPanel (no capture). Not available on tvOS.
TextToSpeech macOS: NSSpeechSynthesizer, tvOS: AVSpeechSynthesizer. GetLocalesAsync unavailable on tvOS (AOT).
Clipboard Copy/paste text. macOS: NSPasteboard, tvOS: in-process (no system pasteboard on tvOS).
Browser Open URLs in default browser via NSWorkspace. Not available on tvOS.
Share Share sheet via NSSharingServicePicker. Not available on tvOS.
Launcher Open files/URIs with default app via NSWorkspace. Not available on tvOS.

Usage

Call the registration method early in your app startup (before MauiApp.CreateBuilder()):

// macOS
Microsoft.Maui.Essentials.MacOS.EssentialsExtensions.UseMacOSEssentials();

// tvOS
Microsoft.Maui.Essentials.TvOS.EssentialsExtensions.UseTvOSEssentials();

Then use the standard MAUI Essentials APIs:

var appName = AppInfo.Name;
var version = AppInfo.VersionString;
var theme = AppInfo.RequestedTheme;
var model = DeviceInfo.Model;
var platform = DeviceInfo.Platform;

Note: MAUI's AppInfo.SetCurrent() and DeviceInfo.SetCurrent() are internal, so the Essentials libraries use reflection to set the backing field. This works with the net10.0 fallback assemblies.

Essentials TODO

  • VersionTracking
  • MainThread

Dialogs

Dialogs (DisplayAlertAsync, DisplayPromptAsync) are supported on macOS via NSAlert, but are not yet supported on tvOS.

MAUI's dialog system is driven by an internal AlertManager class that resolves an IAlertManagerSubscription implementation from DI. On macOS, we register a custom implementation using DispatchProxy to implement the internal interface via reflection. However, tvOS uses AOT compilation which does not support dynamic code generationDispatchProxy throws PlatformNotSupportedException at runtime.

Until IAlertManagerSubscription is made public in MAUI (see the proposal), tvOS dialog support is blocked. The implementation is commented out in src/Microsoft.Maui.Platform.TvOS/Platform/AlertManagerSubscription.cs and the sample uses #if !TVOS compiler directives to exclude dialog UI on Apple TV.

Product Compatible and additional computed target framework versions.
.NET net10.0-tvos26.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-alpha-0001 47 2/19/2026