Skip to content

Instantly share code, notes, and snippets.

@IsmailAlamKhan
Last active April 10, 2025 09:59
Show Gist options
  • Save IsmailAlamKhan/c13fde81044ac8930f328b98272e9d97 to your computer and use it in GitHub Desktop.
Save IsmailAlamKhan/c13fde81044ac8930f328b98272e9d97 to your computer and use it in GitHub Desktop.
Building and distribute a flutter macos app without App Store

To build and distribute a flutter MacOS app without App Store its a quite tedious proccess. There are 2 ways to do this one is using .pkg file and another one using dmg or zip file. Lets start the proccess. I explain both ways step by step.

(Make sure to change AppName to your app name and to your apple id and to your app specific password and $TEAM_ID to your team id. You can find your team id on your apple developer account. Quick-tip You can give chat-gpt/ bard the command and give the relevant information and they will do the changes for you 😉.)

  1. First step is Building the app.

    • flutter build macos
  2. Using dmg or a zip file(Need to notorize the app for this)

    • Notarizing the app. To distribute your app using a dmg/ zip you need to first notarize it.

      • With XCode
        • Open XCode
        • Go to Window -> Organizer
        • Select the archive you want to notarize
        • Click on Distribute App
        • Select Developer ID
        • Click on Next
        • Click on Upload
        • Click on Next
        • Click on Done
        • Wait a few mins till you get that the status of the archive is ready then just follow the previous proccess again and after selecting Developer ID you will be able to export the archive
      • With Commandline
        • Signing the app codesign --options=runtime --deep --force --verbose --sign "Developer ID Application: Team Name (Team Id)" "build/macos/Build/Products/Release/AppName.app"
        • Optional step but better for easy access mv "build/macos/Build/Products/Release/AppName.app" "build/AppName.app"
        • Archiving the zip ditto -c -k --sequesterRsrc --keepParent "build/AppName.app" "build/AppName.zip"
        • Notarizing the app xcrun notarytool submit "build/AppName.zip" --apple-id "<your-apple-id>"--password "<app-speicifc-password>" --team-id "$TEAM_ID" --wait
        • Stapling the notarizing token to the app xcrun stapler staple "build/AppName.app"
    • Build the dmg. Make sure you have appdmg installed on your mac if you don't run npm install -g appdmg.

      • appdmg "<path-to-dmg-config.json> "<path-where-you-want-the-output>"
    • Or if you prefer zip run.

      • zip -r "<path-to-zip-file>" "build/macos/Build/Products/Release/AppName.app"
  3. Building the Package(No need for the app to be notarized)

    • Lets build the pkg first and sign it

      • Building the package xcrun productbuild --component "build/macos/Build/Products/Release/AppName.app" /Applications "AppName-unsigned.pkg"
      • Signing the package xcrun productsign --sign "Developer ID Installer: Team Name (Team Id)" "AppName-unsigned.pkg" "AppName.pkg"
      • Removing the unsigned pkg rm "AppName-unsigned.pkg".
    • Verifying the package

      • spctl -a -t install --verbose "AppName.pkg"
    • Notarizing the package

      • Submit for notarize xcrun notarytool submit "AppName.pkg" --apple-id "<your-apple-id>"--password "<app-speicifc-password>" --team-id "$TEAM_ID"
      • From the previous step get the request uuid and run the following to check the status of the notrization proccess. xcrun notarytool info "$REQUEST_ID" --apple-id ""--password "" --team-id "$TEAM_ID""FU6FJ4RU5Z"
    • Stapling the package

      • xcrun stapler staple "AppName.pkg"

To generate app specific password go to https://appleid.apple.com/account/manage and click on generate password and give it a name and click create. Copy the password and use it in the above commands.

An example of dmg-config.json is provided as all

Also I added another script to build the app icons as well appicon.sh, enjoy.

mkdir AppIcon.iconset
sips -z 16 16 appicon.png --out AppIcon.iconset/icon_16x16.png
sips -z 32 32 appicon.png --out AppIcon.iconset/[email protected]
sips -z 32 32 appicon.png --out AppIcon.iconset/icon_32x32.png
sips -z 64 64 appicon.png --out AppIcon.iconset/[email protected]
sips -z 128 128 appicon.png --out AppIcon.iconset/icon_128x128.png
sips -z 256 256 appicon.png --out AppIcon.iconset/[email protected]
sips -z 256 256 appicon.png --out AppIcon.iconset/icon_256x256.png
sips -z 512 512 appicon.png --out AppIcon.iconset/[email protected]
sips -z 512 512 appicon.png --out AppIcon.iconset/icon_512x512.png
sips -z 1024 1024 appicon.png --out AppIcon.iconset/[email protected]
iconutil -c icns AppIcon.iconset
rm -R AppIcon.iconset
{
"title": "AppIcons",
"icon": "AppIcon.icns",
"background-color": "#FFFFFF",
"contents": [
{
"x": 448,
"y": 344,
"type": "link",
"path": "/Applications"
},
{
"x": 192,
"y": 344,
"type": "file",
"path": "<path-to-app-file>"
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment