.app
application bundle. To make .NET Core and Avalonia projects work in a .app
bundle, some extra legwork has to be done after your application has gone through the publishing process..app
folder structure that looks like this:.app
file/folder structure. You can do this on any operating system, since a .app
file is just a set of folders laid out in a specific format and the tooling isn't specific to one operating system. However, if you build on Windows outside of WSL, the executable may not have the right attributes for execution on macOS -- you may have to run chmod +x
on the published binary output (the output generated by dotnet publish
) from a Unix machine. This is the binary output that ends up in the folder MyApp.app/Contents/MacOS/
, and the name should match CFBundleExecutable
..app
structure relies on the Info.plist
file being properly formatted and containing the right information. Use Xcode to edit Info.plist
, it has auto-completion for all properties. Make sure that:CFBundleExecutable
matches the binary name generated by dotnet publish
-- typically this is the same as your .dll
assembly name without .dll
.CFBundleName
is set to the display name for your application. If this is longer than 15 characters, set CFBundleDisplayName
too.CFBundleIdentifier
is set to a unique identifier, typically in reverse-DNS format -- e.g. com.myapp.macos
.CFBundleShortVersionString
is set to the user-visible string for your application's version, e.g. Major.Minor.Patch
.osx-64
, add the following runtime identifiers to the top <PropertyGroup>
in your .csproj
:.app
executable file.app
bundle will not have the standard .dll
extension. If your publish folder contents, which go inside the .app
bundle, do not have both a MyApp
(exectuable) and a MyApp.dll
, things are probably not generating properly, and macOS will probably not be able to start your .app
properly.MyApp
executable (also called the "app host" in the linked documentation) to not be generated. You need this file to be generated in order for your .app
to function properly. To make sure this gets generated, do one of the following:.csproj
file:-p:UseAppHost=true
to your dotnet publish
command..app
file for you.PackageReference
in your project. Add it to your project via NuGet package manager or by adding the following line to your .csproj
file:.app
by executing the following on the command line:dotnet msbuild
command. For instance, if you want to publish in release mode:CFBundleDisplayName
, etc., on the command line, you can also specify them in your project file:dotnet-bundle
will put the .app
file in the same place as the publish
output: [project directory]/bin/{Configuration}/netcoreapp3.1/osx-x64/publish/MyBestThingEver.app
..app
on Windows, make sure to run chmod +x MyApp.app/Contents/MacOS/AppName
from a Unix machine. Otherwise, the app will not start on macOS.Info.plist
file, adding or modifying keys as necessary:.app
folder structure as outlined at the top of this page. If you want a script to do it for you, you can use something like this (macOS/Unix):.app
on Windows, make sure to run chmod +x MyApp.app/Contents/MacOS/AppName
from a Unix machine. Otherwise, the app will not start on macOS..app
file created, you'll probably want to sign your app so that it can be notarized and distributed to your users without Gatekeeper giving you a hassle. Notarization is required for apps distributed outside the app store starting in macOS 10.15 (Catalina), and you'll have to enable hardened runtime and run codesign
on your .app
in order to notarize it successfully.codesign
command line tool that comes with Xcode..app
bundle under the Contents/MacOS
folder, which is easiest to do with a script since there are a lot of files. In order to sign your files, you need an Apple developer account. In order to notarize your app, you'll need to do the following steps with a Developer ID certificate, which requires a paid Apple developer subscription.xcode-select --install
on the command line and following the prompts to install the tools--options=runtime
part of the codesign
line is what enables the hardened runtime with your app. Because .NET Core may not be fully compatible with hardened runtime, we add some exceptions to use JIT-compiled code and allow for Apple Events to be sent. The JIT-compiled code exception is required to run Avalonia apps under hardened runtime. We add the second exception for Apple Events to fix an error that shows up in Console.app.com.apple.security.cs.allow-jit
. The others may impose security risks with your application. Use with caution.xcrun altool
, check out Apple's documentation..app
is code signed properly.app
in a .zip
file, e.g. MyApp.zip
.xcrun altool --notarize-app -f MyApp.zip --primary-bundle-id com.unique-identifier-for-this-upload -u username -p password
. You can use a password in your keychain by passing -p "@keychain:AC_PASSWORD"
, where AC_PASSWORD is the key. The account has to be registered as an Apple Developer.28fad4c5-68b3-4dbf-a0d4-fbde8e6a078f
xcrun altool --notarization-info 28fad4c5-68b3-4dbf-a0d4-fbde8e6a078f -u username -p password
. This could take some time -- eventually it will succeed or fail.xcrun stapler staple MyApp.app
. You can validate this by running xcrun stapler validate MyApp.app
..dmg
, you will want to modify the steps slightly:.app
as normal (in a .zip
file)xcrun stapler
) app into the DMG (the DMG now has the notarized/stapled .app
file inside of it)..dmg
file (same basic xcrun altool
command, just with the .dmg
file for the -f
flag instead of the .zip
).dmg
file: xcrun stapler staple MyApp.dmg
3rd Party Mac Developer Installer
for signing .pkg
file and 3rd Party Mac Developer Application
for signing a bundle..app
and other for signing app helpers..dylib
files doesn't contain any non-ARM/x64 architectures. You can remove these by using lipo
command line tool.3rd Party Mac Developer Installer
and Apple Distribution
. If cert names are started with another strings - you've created a wrong certificate. Try again.Allow all applications to access this item
in case you don't want to enter a mac profile password for every file sign.dotnet publish src/MyApp.csproj -c Release -f net6.0 -r osx-x64 --self-contained true -p:PublishSingleFile=true
.dll
files are not concidered as a code by Apple. So it should be placed inside /Resources
folder and can be not signed./MacOS
files should contain only executable mach-o - you app executable and any other helper executables.dylib
files shoul be inside Frameworks/
folder.MacOS/
folder to Resources/
and Frameworks/
folders. As an example:ln -s fromFile toFile
Resources/
folder without using any symlinks, because over symlinks you might get I/O access issues in sandbox..app/Content/MacOS/
folder. It should look like this..app
into Applications folder and launch it. If it launches correctly - you did everything right. If it crashes - open Console app and check a crash report.