Written by Chris Raastad (Product Manager at Codemagic)
Flutter is a growing UI framework, gaining lots of love by developers to publish Android and iOS apps with a single codebase. Now with the release of Flutter 2.0, desktop support has moved to early release on the stable channel and ready for you to try out with your Flutter apps! With Codemagic, you can easily get a head start and publish your applications to the macOS App Store! You won’t need any paid tools or subscriptions to get started.
This article will guide you through creating a Flutter macOS desktop app, setting up code signing, and publishing to the App Store with Codemagic. You can see the sample project on Codemagic GitHub. Stay tuned for a similar guide to publishing to the Linux Snap Store and Windows.
Creating a Flutter macOS Desktop App
To create a Flutter app, you’ll need to get Flutter installed on your system. This is easy by following the steps for your operating system on the Flutter Install guide. Now if you open up a command line terminal, if everything is working, executing
flutter --version should print out a version of at least
Next enable Flutter desktop support by running the command:
flutter config --enable-macos-desktop
Next create your Flutter app by running the command:
flutter create --org YOUR_ORG_NAME my_macos_app
Make sure you specify an organization name that makes sense for your project, for example I chose
com.craastad. The org name and app name must be unique to your app in order to publish to the app store! You should now see the
my_macos_app/macos folder in your sample Flutter project.
Next, for macOS apps we need to add an Application Category value to our Info.plist file. You can see the full list of possible categories in Apple’s documentation. Open up
my_macos_app/macos/Runner/Info.plist file and add the following key to the list.
<dict> ... <key>LSApplicationCategoryType</key> <string>public.app-category.business</string> </dict>
If you are using a mac, you can already run your new desktop app with the following steps:
- Check everything is green in when you run
flutter doctor. You’ll need to install Xcode if you have not already.
flutter devicesand make sure you have macOS device available.
- Run your desktop application with
flutter run -d macos.
Next we need to get this sample Flutter application to Git version control in order for Codemagic to publish to the macOS App Store. I’ll work through the steps with GitHub, but you can also use GitLab, BitBucket, or any other Git provider.
- Signup to GitHub and make a new repository, call it
my_macos_appor anything else, it can be private or public.
- Now run the commands in your sample Flutter app to create the git repo, commit, and push it to GitHub
cd my_macos_app git init git add . git commit -m "Created sample macOS Flutter app" git branch -M main git remote add origin email@example.com:GIT_USERNAME/my_macos_app.git git push -u origin main
- Refresh the new repository page, and you should now see your sample Flutter app files at
It’s up to you at this point to make your desktop application awesome! We’ll continue working through the rest of this guide with the sample Flutter app.
Getting ready for code signing
Arguably the most difficult part of mobile app development is working through Apple App Store and Google Play code signing and publishing requirements. This is also the case for publishing desktop apps to the macOS App Store. Codemagic’s automatic code signing can do all the heavy lifting for macOS code signing and publishing by using Apple’s App Store Connect API. When this is all set up, you never have to touch a code signing certificate and provisioning profile! Codemagic also supports manual code signing, where you supply the certificates and provisioning profiles, but we’ll focus on automatic code signing in this guide.
Here I’ll go through the preparation before you can start using Codemagic for macOS code signing and publishing.
Signing and publishing macOS applications requires Apple Developer Program membership. If you haven’t yet enrolled in the Apple Developer Program, you will need to do so before continuing on with macOS publishing.
Creating an App Store Connect API key for Codemagic
Codemagic needs credentials to access to the App Store Connect API to do its code signing magic. It is recommended to create a dedicated API key for Codemagic in App Store Connect. To do so:
- Log in to App Store Connect and navigate to Users and Access > Keys.
- Click on the + sign to generate a new API key.
- Enter the name for the key and select an access level. We recommend choosing either
App Manager, read more about Apple Developer Program role permissions here.
- Click Generate.
- As soon as the key is generated, you can see it added in the list of active keys. Click Download API Key to save the private key for later. Note that the key can only be downloaded once.
Next, you will need to save the of the Issuer ID above the table of active keys and the Key ID of the generated key. You will need these later for setting up the Apple Developer Portal integration in Codemagic to macOS code signing and publishing.
Creating an App Specific Password in App Store Connect
In order to publish our macOS app to App Store Connect we’ll need to create an app-specific password. Navigate to the Apple account management. Click
Security >> App-Specific Passwords >> Generate Password..., make sure to give it a name like
Codemagic Test MacOS App Publishing. Hold on to this password (advisably in a password manager), as you’ll need to use it later.
Creating a Bundle ID and Application in Apple Developer Portal
You’ll need to set up a new unique identifier for your application in order to publish to the macOS App Store, this is called a Bundle ID. Flutter actually automatically created this for us when we specified
--org argument when creating our app. You can find Flutter generated Bundle ID by running
grep -R PRODUCT_BUNDLE_IDENTIFIER . in your app project directory
my_macos_app/. For me this is
Once you found your Bundle ID from your FLutter app, you can add it in the Apple Developer Portal. Navigate to the Identifiers page, click
App IDs, select
App type, then add a description and the Bundle ID. You can come back and edit the Capabilities later when needed in your application.
Finally, we need to create an application in App Store Connect. Head over to the Apps page, click
macOS platform, add a name, select a language, and select your newly added Bundle ID from the dropdown list. SKU is a legacy value that just needs to be unique, so you can use Bundle ID. Full access is fine for User Access.
Connecting App Store Connect API with Codemagic
If you’re new to Codemagic, you’ll need to create a new account at https://codemagic.io/signup. The easiest way to signup is directly with GitHub!
Once you have an account, we can connect the Apple Store Connect API integration in User settings > Integrations for personal projects and in Team settings > Team integrations for teams (if you’re the team owner). This allows you to conveniently use the same credentials for automatic code signing across different apps and workflows.
To set this up with a new Codemagic account:
- Navigate to your settings and integrations page.
- In the list of available integrations, click the Connect button for Developer Portal.
- In the App Store Connect API key name, provide a name for the key you are going to set up the integration with. This is for identifying the key in Codemagic.
- Enter the Issuer ID related to your Apple Developer account. You can find it above the table of active keys on the Keys tab of the Users and Access page.
- Enter the Key ID of the key to be used for code signing.
- In the API key field, upload the private API key downloaded from App Store Connect.
- Click Save to finish the setup.
If you work with multiple Apple Developer teams, you can add additional keys by clicking Manage Keys » Add another key after adding the first key.
Once you’ve linked your Apple Developer Account, Codemagic will take care of the rest. Let’s move on to building, code signing, and publishing our macOS app with Codemagic!
Publishing macOS with Codemagic
There are two ways to build and publish macOS apps with Codemagic: Flutter workflow editor and codemagic.yaml. Flutter workflow editor gives you an easy-to-use UI for configuring your builds with the common use-cases, and a little room for customization. The codemagic.yaml gives you full control with your shell command build steps in a file that you can commit directly to version control. I’ll cover both approaches to Codemagic for building and publishing a macOS app.
Adding our macOS app to Codemagic
For either approach to build configuration, we’ll need to set up our macOS app in Codemagic. The easiest way is directly through your Git provider. I’ll walk through the steps for GitHub. Head over to your Codemagic integrations and click
Manage Integration >> Configure for the GitHub App. You’ll need to make sure to give the Codemagic Github app permission to the
my_macos_app repository in Github’s UI, either by selecting
All Repositories or granting access to
Only select repositories.
Next head over to the applications page and select
Set up build next to
my_macos_app and select
Flutter App in the project selection screen.
Publishing macOS with Flutter Workflow Editor
In order to build macOS with Flutter Workflow Editor you’ll need to enable billing (don’t worry, you won’t be charged!), which you can do on the billing page. Once your billing information is entered and everything head back to the applications page and click Finish build setup for
my_macos_app and make sure Workflow Editor tab is enabled.
Once you’re back on the Workflow Editor, we’re ready to configure our build. Here are the steps.
macOSin Build for platforms
- Make sure
macOS Standard VMis selected on Run build on. These are free build minutes.
- We’ll keep Build triggers as is for now and trigger our builds manually. You may want to add these later to trigger builds automatically for commits or PR merges.
- No changes needed for Environment variables and Dependency caching. These are useful for more complicated use cases.
- No changes needed for Test. You may want to add arguments to the Flutter test and analyze commands down the road.
- In the Build section keep Flutter Version, Xcode version, Cocoapods Version, and Project path to the defaults. Set Mode to
Release. For the Build arguments » macOS, we will need to tell Flutter how to set the build version and number of our application. Set this value to
--build-name=1.0.$PROJECT_BUILD_NUMBER --build-number=$PROJECT_BUILD_NUMBERwhich will update our build number and build number on every build of our application in Codemagic using the handy
PROJECT_BUILD_NUMBERenvironment variable. You can read more about build versioning in the docs or our Build Versioning Best Practices blogpost.
- In the Publish » macOS code signing section, select
Automatic. Next for App Store Connect API key select the key you created earlier from the dropdown. Leave Provisioning profile type and Project type setting to the defaults. In the Bundle identifier dropdown select the Bundle ID you created earlier in Apple Developer Portal.
- In the Publish » App Store Connect section, select
Enable App Store Connect publishing, enter your Apple ID username, and the app-specific password you created earlier.
Savein the upper right corner and now macOS codesigning and App Store Connect should be enabled.
- Under Workflow Settings click on Default Workflow to give our workflow a descriptive name, such as
Once you click Start your first build and Start new build Codemagic will begin to build, code sign, and publish your app! If all is successful, check your app in App Store Connect, and see the build in the
Build + popup. Congratulations! You successfully published a macOS build to App Store Connect without opening Xcode!
Publishing macOS with codemagic.yaml
You can use codemagic.yaml to be in full control of your build steps and commit your build configuration to version control. Head over to the Codemagic Apps page and click Set up build for your application, and select codemagic.yaml from the tab. In the codemagic.yaml editor you’ll find the lock sign, that will open up the section to encrypt environment variables. You will need to use this tool for encrypting environment variables in your build configuration.
Now you’ll need to go to your project root directory,
my_macos_app, and create a
codemagic.yaml file. In this file we’ll add the following template:
workflows: macOS-publishing-yaml: name: macOS Publishing instance_type: mac_mini max_build_duration: 60 environment: flutter: 2.0.6 xcode: 12.5 cocoapods: default vars: APP_STORE_CONNECT_ISSUER_ID: Encrypted(...) APP_STORE_CONNECT_KEY_IDENTIFIER: Encrypted(...) APP_STORE_CONNECT_PRIVATE_KEY: Encrypted(...) CERTIFICATE_PRIVATE_KEY: Encrypted(...) BUNDLE_ID: "your.bundle.id" APPLE_ID: Encrypted(...) APPLE_APP_SPECIFIC_PASSWORD: Encrypted(...) scripts: - name: Set up keychain to be used for codesigning using Codemagic CLI 'keychain' command script: | keychain initialize - name: Fetch Mac App Distribution certificate and Mac App Store profile script: | app-store-connect fetch-signing-files \ $BUNDLE_ID \ --platform MAC_OS \ --type MAC_APP_STORE \ --create - name: Fetch Mac Installer Distribution certificates script: | app-store-connect create-certificate --type MAC_INSTALLER_DISTRIBUTION --save || \ app-store-connect list-certificates --type MAC_INSTALLER_DISTRIBUTION --save - name: Set up signing certificate script: | keychain add-certificates - name: Set up code signing settings on Xcode project script: | xcode-project use-profiles - name: Get Flutter packages script: | flutter packages pub get - name: Flutter analyze script: | flutter analyze - name: Install pods script: | find . -name "Podfile" -execdir pod install \; - name: Build Flutter macOS script: | flutter config --enable-macos-desktop && \ flutter build macos --release --build-name=1.0.$PROJECT_BUILD_NUMBER --build-number=$PROJECT_BUILD_NUMBER - name: Package macOS application script: | set -x # Command to find the path to your generated app APP_NAME=$(find $(pwd) -name "*.app") cd $(dirname "$APP_NAME") PACKAGE_NAME=$(basename "$APP_NAME" .app).pkg # Create an unsigned package xcrun productbuild --component "$APP_NAME" /Applications/ unsigned.pkg # Find the installer certificate commmon name in keychain INSTALLER_CERT_NAME=$(keychain list-certificates \ | jq '. | select(.common_name | contains("Mac Developer Installer")) | .common_name' \ | xargs) # Sign the package xcrun productsign --sign "$INSTALLER_CERT_NAME" unsigned.pkg "$PACKAGE_NAME" artifacts: - build/macos/**/*.pkg publishing: app_store_connect: apple_id: $APPLE_ID password: $APPLE_APP_SPECIFIC_PASSWORD email: recipients: - firstname.lastname@example.org
Here you’ll need to make a few changes to add your project specific configuration and credentials.
APP_STORE_CONNECT_ISSUER_IDto the encrypted value of Issuer ID we created when setting up the App Store Connect API key.
APP_STORE_CONNECT_KEY_IDENTIFIERto the encrypted value of Key ID we created when setting up the App Store Connect API key.
APP_STORE_CONNECT_PRIVATE_KEYto the encrypted contents of the file that was downloaded after creating the App Store Connect API key. Mine ends with the
.p8extension. You’ll want to encrypt the contents of this file, not the file itself, using
pbcopy < AuthKey_XXXXX.p8and pasting this into the UI encryption tool.
CERTIFICATE_PRIVATE_KEYto the encrypted contents of the private key of a
Mac Installer Distributioncertificate. You will need to create a new certificate or use an existing one. See the Codemagic docs for more details. You can view these certificates in Apple Developer Portal. I created one by running
ssh-keygen -t rsa -b 2048 -m PEM -f ~/codemagic_private_key -q -N "". Remember to encrypt the contents of the file, not the file itself, using
pbcopy < codemagic_private_keyand pasting this into the UI encryption tool.
You’ll need to set
BUNDLE_IDto the Bundle ID of your app that was added to the App Store.
You’ll need to set
APPLE_IDto the encrypted value of your Apple Developer Account login email.
You’ll need to set
APPLE_APP_SPECIFIC_PASSWORDto the encrypted value of your Apple Developer Portal app specific password. Mine was in the form of
Finally, in order to receive build notifications emails, set the email address in
Now commit this file to your project, push the change to your git provider, and click Check for configuration file in the Codemagic UI. You should now see your committed configuration file in the codemagic.yaml UI editor.
Now click Start your first build, select your workflow from Select Workflow, and click Start new build to start a build. If everything is set up correctly, after a successful build, check your app in App Store Connect and see the build in the Build + popup. Congratulations! You successfully published a macOS build to App Store Connect without opening Xcode!
Once you’ve worked on your app a little, and your ready to release it to the masses on the App Store, go to your app page in App Store Connect, fill out all the build information, select your build uploaded by Codemagic, and hit Submit for Review!
You can now put a tick next to the box of the hardest part of Flutter macOS app development: signing and publishing a build for App Store distribution. Codemagic handles all the heavy lifting of setting up a pristine mac build environment, so you can focus on building and shipping.
Stay tuned for Linux Snap Store desktop publishing and give us a shout on Twitter if you’re excited for Flutter Windows publishing!
Was this article useful? 🤔 Let us know on Twitter.