Packaging and Distributing Flutter Desktop Apps: The Missing Guide for Open Source & Indie Developers — Creating macOS .app & .dmg [Part 1 of 3]

Flutter Gems
9 min readJan 15, 2024

by Ashita Prasad (LinkedIn, Twitter), fluttergems.dev

Articles in this series:

In today’s rapidly advancing tech landscape where it seems like everything is moving to the cloud and mobile, you might think that desktop apps have become a thing of the past. However, don’t be too quick to dismiss the relevance of desktop apps just yet! While mobile apps and web-based applications offer convenience and portability, desktop applications provide a level of functionality and performance that is difficult to match. From providing exceptional computing capabilities to delivering a seamless user experience coupled with security & the capability of running offline, desktop applications often thrive and adapt to meet the ever-evolving needs of users and businesses alike which makes them an indispensable tool for countless industries and users. Take, for example, the unparalleled power of Microsoft Excel, the most robust spreadsheet application available on desktop. Despite attempts by Microsoft to replicate its success on the web, the desktop app remains unmatched.

Flutter, with its unwavering commitment to reach a wide array of devices, can help you build desktop apps targeting all three platforms - macOS, Windows & Linux, all from a single codebase. It provides impeccable and seamless native compilation, a mature third party package ecosystem to build for desktop, combined with the support to build stunning visual UIs that is leading to its wide adoption for building Desktop apps.

In this series, we will delve into the world of Flutter Desktop and learn how you can package, publish and distribute your desktop apps the “indie way” or the open source way.

Why this “indie” or Open Source guide to publishing Flutter Desktop apps?

When I was preparing the first release of API Dash — an open source alternative to Postman which helps developers tests and integrate APIs, built completely from scratch using Flutter (repo below 👇), little did I know that I would be facing a major hurdle while preparing my app for distribution.

As I was building an open source Flutter app, I wanted to distribute it the way the open source community does, through downloadable package installers available on GitHub like .app or .dmg for macOS, .exe file for Windows, .rpm bundle for Redhat based Linux & .deb package for Debian based Linux systems.

The official Flutter docs cover packaging & distribution in detail for official stores — App Store (macOS), Microsoft Store (Windows) & Snap Store (Ubuntu/Linux). But, like other developers, I felt the need of a step-by-step guide on packaging and distributing my app across multiple platforms with more distribution freedom & no fees.

Today, API Dash is distributed solely via GitHub and is available for macOS (universal build targeting both Intel and Apple Silicon ships), Windows (64 bit exe), and Linux (debian and rpm packages for both Intel and ARM based chips).

API Dash available across multiple desktop platforms — Link

And, through this guide, I want to share my learnings so that you can also package and distribute Flutter apps the open source way.

This is the first article in the three-part series where we will go through the step-by-step process of creating and distributing a macOS Flutter app.

Packaging & Publishing Flutter Desktop App for macOS

Pre-requisite Reads — Official docs on macOS integration & deployment.

We can build and distribute a universal package for macOS which works for both Intel chips & Apple Silicon chips (like M1, M2, ..).

Step 1

Execute flutter build command and open the workspace in Xcode.

Step 1: Run flutter build & open in Xcode

Step 2

The next step is to click on Runner and select the Signing & Capabilities tab.

Now, fill in the signing details as shown below.

Fill in the signing details

macOS includes a security technology called Gatekeeper, which is designed to help ensure that only trusted software runs on a user’s Mac. So, if you do not sign your builds, Gatekeeper will not allow your app to run.

There are two ways to obtain a signing certificate —

  1. By purchasing an Apple Developer ID which costs US $99/year for individuals & US $299/year for enterprises.
  2. By using the free development certificate provided by Apple in case you are a registered Apple user that can be used for signing your app. This free certificate does not come with notorization feature hence you cannot upload your app in app store, but you can distribute it freely via Github or your website.

Step 3

Add relevant entitlements/permissions and enable hardened runtime (an Apple requirement) which prevents any unauthorized code modifications and prevents access to sensitive resources. Also, in order to receive notarization from Apple, macOS apps must have the Hardened Runtime capability enabled.

Add relevant entitlements and enable hardened runtime.

Step 4 (Skip if you don’t have paid developer account)

In case you have paid developer account go ahead and create an archive via Product > Archive menu option.

Create an archive

After creating an archive, you can notorize your application to avoid showing any malicious software warning when the user opens the app for the first time.

Visit Window > Organizer,

and click on Validate App to notorize.

Once validated, you can distribute your app by clicking on Distribute App.

But, as an “indie” or open source developer you might not have a paid account which is expensive.

So you can follow the below steps:

Step 5

Execute flutter build command for macos in release mode. It will build the app and place it in the macos > Build > Products > Release folder as shown below.

Run flutter build macos in release mode

Step 6

Verify if the app has been properly signed using the codesign command as shown below.

Verify if app is signed.

Step 7

In case the app is not signed, you can sign the app yourself.

First, you need to find the valid signatures using the security command.

Finding available signing certificates

Then you can code sign your app using the below codesign command and verify it.

Signing the app.

Step 8

You are now free to distribute this file and people can drop it in their applications folder and run it as macOS allows side-loading.

The app users will be shown malicious software message when they run the app for the first time as we have not notorized the app. This is common as most freely distributed macOS apps throw this message and the installation instructions can include how users can open the app for the first time.

First-time app open warning message.

The sample installation instructions that you can provide is as follows:

  1. Right click on the app & click open.

2. Click on open to open the app.

This has to be done only once and going forward it opens like any other regular application.

Step 9

In Apple community, usually .app files are distributed via .dmg disk images which allows user to easily install applications.

You might have seen a dialog like the one provided below when installing macOS applications.

Install via dmg window

Let us go through the below steps to learn how to create a .dmg file.

Step 10

To create a .dmg disk image file we will be using the appdmg nodejs package.

Install nodejs and install appdmg package using the npm command as shown below.

Step 11

Create a folder installers > macos in your project and add a background image, icon and create a config.json file.

The disk image installation dialog (below) has various components like icon, title, background and contents that can be specified in the config.json file.

.dmg installation window

Specify the path of release version of app, background and icon image, the location of contents, and other specs in the config.json file as mentioned below.

{
"title": "API Dash",
"icon": "AppIcon.icns",
"background": "background.png",
"contents": [
{
"x": 445,
"y": 260,
"type": "link",
"path": "/Applications"
},
{
"x": 155,
"y": 270,
"type": "file",
"path": "../../build/macos/Build/Products/Release/API Dash.app"
}
],
"code-sign": {
"signing-identity": "PQR"
}
}

Note: Don’t forget to add the code signing identity (highlighted in the image below) which we can obtain using the security command as shown in Step 7. The .dmg also needs to be signed even if u have signed the .app file.

code-sign credentials in config.json

Step 12

Now traverse to the installers > macos folder using

$ cd installers/macos

and run the following appdmg command

appdmg config.json "App name.dmg"
Create dmg file

The .dmg file is now generated in the current folder and it is ready to distribute. You can check out the sample installation instructions (link) that can be provided to the users.

Step 13

To distribute the app, you can create a new GitHub release and attach the .dmg file as shown below.

Once the release is published, the app will be available for download to all users.

Closing Notes

In this article, we learnt how you can create .app and .dmg files and distribute your Flutter apps the “indie” or open source way. You can check out the other article in this series to learn how to do the same for other desktop platforms.

In case you have any doubts or queries please feel free to comment below or drop in our Discord Server.

This article is brought to you by Flutter Gems, a curated list of top Dart and Flutter packages that are categorized based on functionality. Do check it out below 👇

--

--

Flutter Gems

Maintained by Ashita Prasad, Flutter Gems is a curated package guide for Flutter ecosystem. Visit https://fluttergems.dev