Build and release an Android app

To test an app, you can use flutter run at the command line, or the Run and Debug options in your IDE.

When you're ready to prepare a release version of your app, for example to publish to the Google Play Store, this page can help. Before publishing, you might want to put some finishing touches on your app. This guide explains how to perform the following tasks:

Add a launcher icon

#

When a new Flutter app is created, it has a default launcher icon. To customize this icon, you might want to check out the flutter_launcher_icons package.

Alternatively, you can do it manually using the following steps:

  1. Review the Material Design product icons guidelines for icon design.

  2. In the [project]/android/app/src/main/res/ directory, place your icon files in folders named using configuration qualifiers. The default mipmap- folders demonstrate the correct naming convention.

  3. In AndroidManifest.xml, update the application tag's android:icon attribute to reference icons from the previous step (for example, <application android:icon="@mipmap/ic_launcher" ...).

  4. To verify that the icon has been replaced, run your app and inspect the app icon in the Launcher.

Enable Material Components

#

If your app uses Platform Views, you might want to enable Material Components by following the steps described in the Getting Started guide for Android.

For example:

  1. Add the dependency on Android's Material in <my-app>/android/app/build.gradle:
groovy
dependencies {
    // ...
    implementation 'com.google.android.material:material:<version>'
    // ...
}

To find out the latest version, visit Google Maven.

  1. Set the light theme in <my-app>/android/app/src/main/res/values/styles.xml:
-<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
+<style name="NormalTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
  1. Set the dark theme in <my-app>/android/app/src/main/res/values-night/styles.xml
-<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
+<style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">

Sign the app

#

To publish on the Play Store, you need to sign your app with a digital certificate.

Android uses two signing keys: upload and app signing.

  • Developers upload an .aab or .apk file signed with an upload key to the Play Store.
  • The end-users download the .apk file signed with an app signing key.

To create your app signing key, use Play App Signing as described in the official Play Store documentation.

To sign your app, use the following instructions.

Create an upload keystore

#

If you have an existing keystore, skip to the next step. If not, create one using one of the following methods:

  1. Follow the Android Studio key generation steps

  2. Run the following command at the command line:

    On macOS or Linux, use the following command:

    keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \
            -keysize 2048 -validity 10000 -alias upload

    On Windows, use the following command in PowerShell:

    powershell
    keytool -genkey -v -keystore %userprofile%\upload-keystore.jks ^
            -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 ^
            -alias upload

    This command stores the upload-keystore.jks file in your home directory. If you want to store it elsewhere, change the argument you pass to the -keystore parameter. However, keep the keystore file private; don't check it into public source control!

Reference the keystore from the app

#

Create a file named [project]/android/key.properties that contains a reference to your keystore. Don't include the angle brackets (< >). They indicate that the text serves as a placeholder for your values.

properties
storePassword=<password-from-previous-step>
keyPassword=<password-from-previous-step>
keyAlias=upload
storeFile=<keystore-file-location>

The storeFile might be located at /Users/<user name>/upload-keystore.jks on macOS or C:\\Users\\<user name>\\upload-keystore.jks on Windows.

Configure signing in gradle

#

When building your app in release mode, configure gradle to use your upload key. To configure gradle, edit the <project>/android/app/build.gradle file.

  1. Add the keystore information from your properties file before the android block:

    +   def keystoreProperties = new Properties()
    +   def keystorePropertiesFile = rootProject.file('key.properties')
    +   if (keystorePropertiesFile.exists()) {
    +       keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    +   }
    +
       android {
          ...
       }
  2. Load the key.properties file into the keystoreProperties object.

  3. Add the signing configuration before the buildTypes block:

    +   signingConfigs {
    +       release {
    +           keyAlias keystoreProperties['keyAlias']
    +           keyPassword keystoreProperties['keyPassword']
    +           storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
    +           storePassword keystoreProperties['storePassword']
    +       }
    +   }
       buildTypes {
          release {
             // TODO: Add your own signing config for the release build.
             // Signing with the debug keys for now,
             // so `flutter run --release` works.
    -           signingConfig signingConfigs.debug
    +           signingConfig signingConfigs.release
          }
       }

Flutter now signs all release builds.

To learn more about signing your app, check out Sign your app on developer.android.com.

Shrink your code with R8

#

R8 is the new code shrinker from Google. It's enabled by default when you build a release APK or AAB. To disable R8, pass the --no-shrink flag to flutter build apk or flutter build appbundle.

Enable multidex support

#

When writing large apps or making use of large plugins, you might encounter Android's dex limit of 64k methods when targeting a minimum API of 20 or below. This might also be encountered when running debug versions of your app using flutter run that does not have shrinking enabled.

Flutter tool supports easily enabling multidex. The simplest way is to opt into multidex support when prompted. The tool detects multidex build errors and asks before making changes to your Android project. Opting in allows Flutter to automatically depend on androidx.multidex:multidex and use a generated FlutterMultiDexApplication as the project's application.

When you try to build and run your app with the Run and Debug options in your IDE, your build might fail with the following message:

screenshot of build failure because Multidex support is required

To enable multidex from the command line, run flutter run --debug and select an Android device:

screenshot of selecting an Android device

When prompted, enter y. The Flutter tool enables multidex support and retries the build:

screenshot of a successful build after adding multidex

You might also choose to manually support multidex by following Android's guides and modifying your project's Android directory configuration. A multidex keep file must be specified to include:

io/flutter/embedding/engine/loader/FlutterLoader.class
io/flutter/util/PathUtils.class

Also, include any other classes used in app startup. For more detailed guidance on adding multidex support manually, check out the official Android documentation.

Review the app manifest

#

Review the default App Manifest file, AndroidManifest.xml. This file is located in [project]/android/app/src/main. Verify the following values:

application
Edit the android:label in the application tag to reflect the final name of the app.
uses-permission
Add the android.permission.INTERNET permission if your application code needs Internet access. The standard template doesn't include this tag but allows Internet access during development to enable communication between Flutter tools and a running app.

Review the Gradle build configuration

#

Review the default Gradle build file (build.gradle, located in [project]/android/app), to verify that the values are correct.

Under the defaultConfig block

#
applicationId
Specify the final, unique application ID.
minSdkVersion
Specify the minimum API level on which you designed the app to run. Defaults to flutter.minSdkVersion.
targetSdkVersion
Specify the target API level on which you designed the app to run. Defaults to flutter.targetSdkVersion.
versionCode
A positive integer used as an internal version number. This number is used only to determine whether one version is more recent than another, with higher numbers indicating more recent versions. This version isn't shown to users.
versionName
A string used as the version number shown to users. This setting can be specified as a raw string or as a reference to a string resource.
buildToolsVersion
The Gradle plugin specifies the default version of the build tools that your project uses. You can use this option to specify a different version of the build tools.

Under the android block

#
compileSdkVersion
Specify the API level Gradle should use to compile your app. Defaults to flutter.compileSdkVersion.

For more information, check out the module-level build section in the Gradle build file.

Build the app for release

#

You have two possible release formats when publishing to the Play Store.

  • App bundle (preferred)
  • APK

Build an app bundle

#

This section describes how to build a release app bundle. If you completed the signing steps, the app bundle will be signed. At this point, you might consider obfuscating your Dart code to make it more difficult to reverse engineer. Obfuscating your code involves adding a couple flags to your build command, and maintaining additional files to de-obfuscate stack traces.

From the command line:

  1. Enter cd [project]
  2. Run flutter build appbundle
    (Running flutter build defaults to a release build.)

The release bundle for your app is created at [project]/build/app/outputs/bundle/release/app.aab.

By default, the app bundle contains your Dart code and the Flutter runtime compiled for armeabi-v7a (ARM 32-bit), arm64-v8a (ARM 64-bit), and x86-64 (x86 64-bit).

Test the app bundle

#

An app bundle can be tested in multiple ways. This section describes two.

Offline using the bundle tool

#
  1. If you haven't done so already, download bundletool from the GitHub repository.
  2. Generate a set of APKs from your app bundle.
  3. Deploy the APKs to connected devices.

Online using Google Play

#
  1. Upload your bundle to Google Play to test it. You can use the internal test track, or the alpha or beta channels to test the bundle before releasing it in production.
  2. Follow these steps to upload your bundle to the Play Store.

Build an APK

#

Although app bundles are preferred over APKs, there are stores that don't yet support app bundles. In this case, build a release APK for each target ABI (Application Binary Interface).

If you completed the signing steps, the APK will be signed. At this point, you might consider obfuscating your Dart code to make it more difficult to reverse engineer. Obfuscating your code involves adding a couple flags to your build command.

From the command line:

  1. Enter cd [project].

  2. Run flutter build apk --split-per-abi. (The flutter build command defaults to --release.)

This command results in three APK files:

  • [project]/build/app/outputs/apk/release/app-armeabi-v7a-release.apk
  • [project]/build/app/outputs/apk/release/app-arm64-v8a-release.apk
  • [project]/build/app/outputs/apk/release/app-x86_64-release.apk

Removing the --split-per-abi flag results in a fat APK that contains your code compiled for all the target ABIs. Such APKs are larger in size than their split counterparts, causing the user to download native binaries that are not applicable to their device's architecture.

Install an APK on a device

#

Follow these steps to install the APK on a connected Android device.

From the command line:

  1. Connect your Android device to your computer with a USB cable.
  2. Enter cd [project].
  3. Run flutter install.

Publish to the Google Play Store

#

For detailed instructions on publishing your app to the Google Play Store, check out the Google Play launch documentation.

Update the app's version number

#

The default version number of the app is 1.0.0. To update it, navigate to the pubspec.yaml file and update the following line:

version: 1.0.0+1

The version number is three numbers separated by dots, such as 1.0.0 in the example above, followed by an optional build number such as 1 in the example above, separated by a +.

Both the version and the build number can be overridden in Flutter's build by specifying --build-name and --build-number, respectively.

In Android, build-name is used as versionName while build-number used as versionCode. For more information, check out Version your app in the Android documentation.

When you rebuild the app for Android, any updates in the version number from the pubspec file will update the versionName and versionCode in the local.properties file.

Android release FAQ

#

Here are some commonly asked questions about deployment for Android apps.

When should I build app bundles versus APKs?

#

The Google Play Store recommends that you deploy app bundles over APKs because they allow a more efficient delivery of the application to your users. However, if you're distributing your application by means other than the Play Store, an APK might be your only option.

What is a fat APK?

#

A fat APK is a single APK that contains binaries for multiple ABIs embedded within it. This has the benefit that the single APK runs on multiple architectures and thus has wider compatibility, but it has the drawback that its file size is much larger, causing users to download and store more bytes when installing your application. When building APKs instead of app bundles, it is strongly recommended to build split APKs, as described in build an APK using the --split-per-abi flag.

What are the supported target architectures?

#

When building your application in release mode, Flutter apps can be compiled for armeabi-v7a (ARM 32-bit), arm64-v8a (ARM 64-bit), and x86-64 (x86 64-bit). Flutter supports building for x86 Android through ARM emulation.

How do I sign the app bundle created by flutter build appbundle?

#

See Signing the app.

How do I build a release from within Android Studio?

#

In Android Studio, open the existing android/ folder under your app's folder. Then, select build.gradle (Module: app) in the project panel:

screenshot of gradle build script menu

Next, select the build variant. Click Build > Select Build Variant in the main menu. Select any of the variants in the Build Variants panel (debug is the default):

screenshot of build variant menu

The resulting app bundle or APK files are located in build/app/outputs within your app's folder.