Avalonia for macOS

A native macOS backend written and maintained by us, universal binaries for Apple silicon and Intel, and no Mac needed to compile.

Platform support

A backend we wrote, not a workload we borrowed.

Avalonia ships its own native Objective-C++ macOS backend rather than depending on the .NET macOS workload. That’s why the Mac build behaves like the Windows and Linux builds, and why it doesn’t inherit anyone else’s deprecation schedule.

Windowing

Native Objective-C++ backend

Written and maintained by us, not the .NET macOS workload.

Rendering

Skia

GPU accelerated, with a software fallback.

Architectures

Apple silicon and Intel

ARM64 and x64, shippable as one universal binary.

Runtime

.NET 8.0 or later

No Xamarin.Mac, and no Mac required to compile.

Shipping today

Tools built for people who notice.

Designers and profiler users are among the least forgiving audiences a desktop application can have. These are the Mac builds those teams ship.

Your build pipeline

Compile on Windows. Run on the Mac.

Avalonia’s macOS backend has no Xamarin.Mac dependency. Your existing Windows or Linux build agents can produce the Mac build, which keeps macOS out of the “we’d need to buy hardware first” column when a team is deciding whether to support it at all.

Signing and notarisation travel too. Apple’s own command line tooling needs a Mac to run on, which is why most teams assume the release still has to end on one. Parcel signs with your Apple identity and submits to Apple’s notary service as part of the packaging run, from whichever machine is doing the packaging, so the Mac leaves the pipeline as well as the build.

A build running on a Windows machine producing an application bundle that launches on macOS
No Xamarin.Mac dependency, so a Windows or Linux agent can produce the macOS build.

How it feels

Blend in, or don’t. Both are one codebase.

Because Avalonia draws its own controls instead of wrapping AppKit, resembling a stock Mac application (vibrancy, traffic-light window controls and all) is a decision you make, not one the toolkit makes for you.

A Cupertino-flavoured theme makes it blend in. A brand theme makes it unmistakably yours, at full strength: swap the style resource and every platform picks it up, with no separate override step per OS. Neither choice forks the codebase, because a theme is a style resource rather than a platform target, and the same resources are already producing your Windows and Linux builds.

Retina scaling, full-screen behaviour and the light or dark appearance the user chose in System Settings are handled underneath either choice.

Avalonia rendering macOS style controls including a segmented control, switch, slider and date picker
Avalonia controls under a macOS-oriented theme, with no platform-specific code behind them.

Native to the Mac

Mac users can tell within about four seconds.

The tells are always the same ones: where the menus are, whether the Dock icon does anything, and whether Command does what Control does elsewhere. Avalonia gets all three right on macOS.

<NativeMenu.Menu>
  <NativeMenu>
    <NativeMenuItem Header="File">
      <NativeMenu>
        <NativeMenuItem Header="Open…" Gesture="Cmd+O"
                        Command="{Binding OpenCommand}" />
      </NativeMenu>
    </NativeMenuItem>
  </NativeMenu>
</NativeMenu.Menu>

A real menu bar, at the top of the screen

Not a menu strip drawn inside your window. NativeMenu builds the macOS application menu where macOS puts it, generates the Quit item for you, and gives the Edit menu the special handling the system expects so text services keep working.

Command, not Control

PlatformHotkeyConfiguration maps the standard gestures per platform, so ⌘Q, ⌘W, ⌘M, ⌘H and ⌘A behave the way a Mac user expects without a per-platform shortcut table in your code.

The Dock icon does something

NativeDock.Menu gives the Dock icon a right-click menu, which is one of the small things whose absence makes an application feel like it was built somewhere else and shipped here.

<key>CFBundleURLTypes</key>
<array><dict>
  <key>CFBundleURLSchemes</key>
  <array><string>contoso</string></array>
</dict></array>

Open your files, answer your links

Register URL schemes and document types in Info.plist and macOS routes them to your app, so a contoso:// link or a double-clicked document lands where you expect.

<key>CFBundleName</key>
<string>Contoso</string>
<!-- 15 characters max: this is what the menu bar
     and the Quit item will say -->

The name macOS actually shows

CFBundleName is capped at fifteen characters by the system and is what the menu bar and Quit item display; CFBundleDisplayName is what Finder and the Dock show. Getting these wrong is the most common reason a Mac build looks unfinished.

Our own Objective-C++ backend

macOS support is libAvaloniaNative.dylib talking to .NET through MicroCom, written and maintained by us. That’s why the Mac build doesn’t track anyone else’s workload lifecycle, and why it compiles from Windows.

Down to NSView, when you need it

NativeControlHost embeds NSView subclasses inside an Avalonia layout on their own compositing layer, and a net10.0-macos target opens the full macOS API surface for Mac-only builds.

Every API above is documented, with the macOS caveats spelled out.

macOS platform guide

Getting it installed

Notarised before Gatekeeper ever sees it.

Avalonia produces a standard .app bundle, so the distribution path is the one Apple documents. Parcel is the part that runs it for you.

Build the Mac release without a Mac

On the Plus edition, the same run also signs the bundle with your Apple identity and submits it to Apple’s notary service, so notarisation happens without a Mac too, not only the build. Parcel packages every target from one machine in parallel, and the DMG comes out alongside the Windows and Linux installers.

Gatekeeper says yes

macOS blocks applications that aren’t signed and notarised, and most users stop at that dialog. Both happen inside the packaging run rather than as a separate ritual somebody has to remember.

Universal binaries

Publish for Apple silicon and Intel and join them with lipo, so users get one download and no Rosetta prompt.

Mac App Store

Sandbox entitlements, universal purchase and receipt validation are handled by Apple’s tooling against the same bundle you already produced.

The Info.plist plumbing

Declare permissions with their usage descriptions, URL handlers and uninstallers once, and the native plumbing gets written for you rather than by hand into a file nobody wants to own.

Icons from one SVG

Point Parcel at a single vector file and it produces the icon formats macOS wants, for the app bundle and the installer alike.

NativeAOT

Publish ahead of time for a smaller bundle and a faster launch, with no .NET runtime for the user to install first.

Nobody ships from a laptop

The Parcel CLI runs your saved configuration headlessly, so a release builds in CI exactly as it does on your desk, and the signing identity lives there rather than on one machine.

Parcel also signs and notarises the macOS build in the same run, so the DMG and the Windows installer come out together.

See Parcel

Every target

Add the Mac without forking the team.

None of the tooling above (the Objective-C++ backend, the notarisation pipeline) is a macOS-only investment. The same project produces every other target Avalonia supports.

Build the Mac target without buying a Mac.

Install the templates, add the macOS target, and build it from the machine you’re sitting at. The framework is MIT licensed, and signing and notarisation run in the same pipeline, so the Mac stays out of it end to end.