Loading... Search articles

Search for articles

Sorry, but we couldn't find any matches...

But perhaps we can interest you in one of our more popular articles?
Flutter macOS desktop publishing with Codemagic

Flutter macOS desktop publishing with Codemagic

May 14, 2021

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. Take a look at the sample project here:

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 Flutter 2.0.X.

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.
  • Run flutter devices and 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_app or 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 git@github.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 https://github.com/GIT_USERNAME/my_macos_app.

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, same as for iOS code signing. 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:

  1. Log in to App Store Connect and navigate to Users and Access > Keys.
  2. Click on the + sign to generate a new API key.
  3. Enter the name for the key and select an access level. We recommend choosing either Developer or App Manager, read more about Apple Developer Program role permissions here.
  4. Click Generate.
  5. 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 com.craastad.myMacosApp.

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 +, select 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 +, select 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:

  1. Navigate to your settings and integrations page.
  2. In the list of available integrations, click the Connect button for Developer Portal.
  3. 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.
  4. 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.
  5. Enter the Key ID of the key to be used for code signing.
  6. In the API key field, upload the private API key downloaded from App Store Connect.
  7. 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 my_macos_app in 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.

  1. Select macOS in Build for platforms
  2. Make sure macOS Standard VM is selected on Run build on. These are free build minutes.
  3. 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.
  4. No changes needed for Environment variables and Dependency caching. These are useful for more complicated use cases.
  5. No changes needed for Test. You may want to add arguments to the Flutter test and analyze commands down the road.
  6. 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_NUMBER which will update our build number and build number on every build of our application in Codemagic using the handy PROJECT_BUILD_NUMBER environment variable. You can read more about build versioning in the docs or our Build Versioning Best Practices blogpost.
  7. In the Distribution » 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.
  8. In the Distribution » App Store Connect section, select Enable App Store Connect publishing, enter your Apple ID username, and the app-specific password you created earlier.
  9. Click Save in the upper right corner and now macOS codesigning and App Store Connect should be enabled.
  10. Under Workflow Settings click on Default Workflow to give our workflow a descriptive name, such as macOS Publishing.

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 common 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:
          - email@example.com

Here you’ll need to make a few changes to add your project specific configuration and credentials.

  • Set APP_STORE_CONNECT_ISSUER_ID to the encrypted value of Issuer ID we created when setting up the App Store Connect API key.

  • Set APP_STORE_CONNECT_KEY_IDENTIFIER to the encrypted value of Key ID we created when setting up the App Store Connect API key.

  • Set APP_STORE_CONNECT_PRIVATE_KEY to the encrypted contents of the file that was downloaded after creating the App Store Connect API key. Mine ends with the .p8 extension. You’ll want to encrypt the contents of this file, not the file itself, using pbcopy < AuthKey_XXXXX.p8 and pasting this into the UI encryption tool.

  • SetCERTIFICATE_PRIVATE_KEY to the encrypted contents of the private key of a Mac Installer Distribution certificate. 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_key and pasting this into the UI encryption tool.

  • You’ll need to set BUNDLE_ID to the Bundle ID of your app that was added to the App Store.

  • You’ll need to set APPLE_ID to the encrypted value of your Apple Developer Account login email.

  • You’ll need to set APPLE_APP_SPECIFIC_PASSWORD to the encrypted value of your Apple Developer Portal app specific password. Mine was in the form of wwww-xxxx-yyyy-zzzz before encryption.

  • Finally, in order to receive build notifications emails, set the email address in recipients.

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!

What’s next?

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.

How did you like this article?

Oops, your feedback wasn't sent

Latest articles

Show more posts