Skip to main content

flutter_release 0.3.7 copy "flutter_release: ^0.3.7" to clipboard
flutter_release: ^0.3.7 copied to clipboard

A tool for building and publishing Flutter apps, e.g. on GitHub, the Google Play Store and Apple's App Store.

flutter_release #

A tool for building and publishing Flutter apps, e.g. on GitHub, the Google Play Store and Apple's App Store. See also the according GitHub action.

Example #

Build:

flutter_release build apk \
 --app-name example \ # Using name in pubspec by default
 --app-version v0.0.1-alpha.1 \ # Using version in pubspec by default
 --build-arg=--dart-define=API_URL=https://example.com \
 --build-arg=--dart-define=API_KEY=12345678

Publish:

flutter_release publish android-google-play \
 --dry-run \
 --stage internal \
 --app-name example \
 --app-version v0.0.1-alpha.1 \
 --build-arg=--dart-define=API_URL=https://example.com \
 --build-arg=--dart-define=API_KEY=12345678 \
 --fastlane-secrets-json-base64=$(base64 --wrap=0 android/fastlane-secrets.json) \
 --keystore-file-base64=$(base64 --wrap=0 android/keystore.jks) \
 --keystore-password=<mykeystorepassword> \
 --key-alias=<mykeyalias> \
 --key-password=<mykeypassword>

If the command is not found (in the PATH), try: dart pub global run flutter_release ....

Note that you have to pass the base64 arguments without any newline characters:

MY_BASE_64=$(base64 --wrap=0 /myfile)

Or remove them afterward:

MY_BASE_64="${MY_BASE_64//$'\n'/}"

Options & Flags #

Options:

  • app-name: The name of the app executable
  • app-version: Semantic version of the release (like v1.2.3), see https://semver.org/
  • build-metadata: Specify the build number (also used as version code for Android, but is handled automatically)
  • build-type: Release one of the following options: apk, web, ipk, macos, windows, msix, debian
  • build-arg: Add options such as --dart-define to the flutter build command

Flags:

  • verbose: Enable verbose logging

Supported Features #

Platform Android iOS web Windows macOS Linux
Build apk ✓ aab ✓ ipa ❌ web ✓ windows ✓ msix ✓ macos ✓ linux ✓ debian ✓
Publish Google Play ✓ iOS App Store ✓ Web Server ✓ Microsoft Store ✓ Mac App Store ❌ Snap ❌ Ubuntu ❌

Support for other app distributors is planned.

Setup #

Android - Google Play Store (via Debian only) #

  1. Create an App in your Google Play Console.
  2. Make sure you have these files ignored in your ./android/.gitignore:
    key.properties
    **/*.keystore
    **/*.jks
    
    # Google Play Store credentials
    fastlane-*.json
    play-store-credentials.json
    
  3. Configure signing in gradle. This is needed to be able to execute the build via Flutter and not via Gradle. Convert the keystore to a base64 string e.g. base64 --wrap=0 android/keystore.jks
  4. Follow the guide of fastlane for setting up supply. No need to add the path to the Fastlane AppFile (as it should not exist at this point).
  5. Convert the Google Play Store credentials json (downloaded from cloud.google.com) to base64 e.g. base64 --wrap=0 android/fastlane-secrets.json
  6. Manually build a signed app bundle and publish it on the Google Play Store at least once to be able to automate the process, e.g.:
    flutter build appbundle \
     --release
    
  7. Run flutter_release
    flutter_release publish android-google-play \
     --dry-run \
     --stage internal \
     --fastlane-secrets-json-base64=$(base64 --wrap=0 android/fastlane-secrets.json) \
     --keystore-file-base64=$(base64 --wrap=0 android/keystore.jks) \
     --keystore-password=<mykeystorepassword> \
     --key-alias=<mykeyalias> \
     --key-password=<mykeypassword>
    
    For flavor support, add:
     --flavor=prod \
     --main-path lib/main_prod.dart # Using "lib/main.dart" by default
    
    To set the release status (default draft), add:
     --release-status=completed
    
    You need to have released an alpha version for completed status to work: https://github.com/fastlane/fastlane/discussions/18293

iOS - App Store #

  1. Make sure you have these files ignored in your ./ios/.gitignore:
    *.cer
    *.certSigningRequest
    *.mobileprovision
    *.p12
    *.p8
    
  2. Create an App Store connect API Team key with App Manager permissions. Copy the key into your ios folder. Also copy the Key ID and the Issuer ID for later.
  3. Execute flutter_release prepare ios. Follow the steps. To delete existing certificates, visit: https://developer.apple.com/account/resources/certificates/list
  4. Make sure the certificate is selected in the App Store provisioning profile
  5. Extract the information from the ios/fastlane/Appfile file.
  6. Run flutter_release
    flutter_release publish ios-app-store \
     --dry-run \
     --apple-username=<apple_id> \
     --api-key-id=<api-key-id> \
     --api-issuer-id=<api-issuer-id> \
     --api-private-key-base64=<api-private-key> \
     --content-provider-id=<itc_team_id> \
     --team-id=<team_id> \
     --distribution-private-key-base64=<distribution-private-key> \
     --distribution-cert-base64=<distribution-cert>
    
    Optionally add the --team-enterprise flag, if your team is in the Apple Developer Enterprise Program. For flavor support add:
     --flavor=prod \
     --main-path lib/main_prod.dart \ # Using "lib/main.dart" by default
     --xcode-scheme prod # Optional, uses flavor if set, or "Runner" by default
    

To force renew the certificates run:

flutter_release prepare ios cert

To create additional provisioning profiles, run in the ios directory:

fastlane sigh -a com.example.ios.to.be.added --api_key_path ApiAuth.json

Windows - MSIX installer #

The MSIX installer is created via the msix package. Configure it in the msix_config section of your pubspec.yaml, e.g.:

msix_config:
  display_name: Example
  logo_path: assets/images/logo.png

The version is derived from the app version (a.b.c.0), the architecture from the build machine. To sign the installer, pass your certificate:

flutter_release build msix `
  --certificate-file-base64=$([Convert]::ToBase64String([IO.File]::ReadAllBytes((Resolve-Path certificate.pfx)))) `
  --certificate-password=<mycertificatepassword>

Otherwise, the installer is signed with the test certificate of the msix package, which users have to trust manually.

For the Microsoft Store, build an unsigned installer with the --store flag, as the store signs it on submission. Take the identity name, the publisher and the publisher display name from the Partner Center (Product identity) of your app:

flutter_release build msix --store `
  --identity-name=Example.ExampleApp `
  --publisher="CN=00000000-0000-0000-0000-000000000000" `
  --publisher-display-name="Example Publisher"

Alternatively, set them via identity_name, publisher and publisher_display_name in the msix_config.

Windows - Microsoft Store (via Windows only) #

  1. Reserve the app name in the Partner Center and submit the app manually at least once, e.g. with an installer built via flutter_release build msix --store (see above).
  2. In Account settings > Organization profile > Tenants, associate a Microsoft Entra tenant with your account. If you don't have one, create a new tenant there at no charge.
  3. In Account settings > User management > Microsoft Entra applications, create a new Microsoft Entra application (see Microsoft Store submission API):
    • Name: e.g. flutter_release
    • Reply URL: e.g. http://localhost (not used, but required)
    • Role: Developer
  4. Select the created application and copy the Tenant ID and the Client ID. Then select Add new key and copy the Key (as client secret), as it is only shown once. Keys expire, so renew them there in time.
  5. Copy the Seller ID from Account settings > Organization profile > Legal info > Developer.
  6. Copy the Store ID (as product id) from Product management > Product identity of your app.
  7. Install the Microsoft Store Developer CLI (msstore).
  8. Build the installers via flutter_release build msix --store (see above), e.g. one per architecture on the respective machine. The publish command does not build the app.
  9. Run flutter_release
    flutter_release publish windows-ms-store `
     --dry-run `
     --tenant-id=<tenant-id> `
     --client-id=<client-id> `
     --client-secret=<key> `
     --seller-id=<seller-id> `
     --product-id=<store-id>
    
    By default, the packages of the app version (--app-version or from the pubspec.yaml) are taken from build/releases. Alternatively, pass them via --package=<path> (repeatable). Multiple packages are published at once as .msixbundle, using the app version as bundle version. To publish to a package flight, add --flight-id=<flight-id>. The submission is kept as draft by default (--release-status=draft). To submit it for certification, add --release-status=completed. For a gradual rollout, add --rollout-percentage=<0-100>.

Web - Server (via Debian only) #

  1. Generate a key pair on your client ssh-keygen -t ed25519 -f $HOME/.ssh/id_ed25519_flutter_release -C flutter_release without a passphrase
  2. Add the output of cat $HOME/.ssh/id_ed25519_flutter_release.pub to your servers $HOME/.ssh/authorized_keys
  3. Convert the private key to a base64 string e.g. base64 --wrap=0 $HOME/.ssh/id_ed25519_flutter_release
  4. Run flutter_release
    flutter_release publish web-server \
     --dry-run \
     --host=host.example.com \
     --path=/var/www/html \
     --ssh-port=22 \
     --ssh-user=<user> \
     --ssh-private-key-base64=<private-key>
    
2
likes
160
points
427
downloads

Documentation

API reference

Publisher

verified publisheroberhauser.dev

Weekly Downloads

A tool for building and publishing Flutter apps, e.g. on GitHub, the Google Play Store and Apple's App Store.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

args, collection, dart_release, flutter_to_debian, logging, msix, path, pub_semver, pubspec_parse

More

Packages that depend on flutter_release