DEV3 Technologies home

DEV3 Developer Forum

How do I sign a Flutter Android release (keystore, key.properties) for the Play Store?

Flutter helpSolved0 views
dev3 ·

flutter build appbundle works but Play Console says the bundle is signed with the debug key. How do I create a keystore and configure Gradle without committing secrets?

#flutter#android#signing

0

1 reply

dev3 · Accepted answer

1. Create an upload keystore (once)

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

Store the file and passwords somewhere safe (password manager, backup). Outside the repository.

2. Reference it from android/key.properties

storePassword=YOUR_STORE_PASSWORD
keyPassword=YOUR_KEY_PASSWORD
keyAlias=upload
storeFile=/Users/you/upload-keystore.jks

Add key.properties, *.jks and *.keystore to .gitignore.

3. Configure android/app/build.gradle (Groovy)

def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
    }
}

Newer Flutter templates use the Kotlin DSL (android/app/build.gradle.kts). The same setup there looks like this:

import java.io.FileInputStream
import java.util.Properties

val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}

android {
    signingConfigs {
        create("release") {
            keyAlias = keystoreProperties["keyAlias"] as String
            keyPassword = keystoreProperties["keyPassword"] as String
            storeFile = keystoreProperties["storeFile"]?.let { file(it) }
            storePassword = keystoreProperties["storePassword"] as String
        }
    }
    buildTypes {
        release {
            signingConfig = signingConfigs.getByName("release")
        }
    }
}

4. Build

flutter build appbundle --release

The output is build/app/outputs/bundle/release/app-release.aab.

Play App Signing

Enroll in Play App Signing (default for new apps). Google holds the app signing key and your keystore is only the upload key, so a lost upload key can be reset through support instead of ending the app.

CI

Store the keystore base64-encoded as a secret, decode it in the pipeline and write key.properties there.

Pitfalls

  • Wrong alias or password gives "Keystore was tampered with, or password was incorrect".
  • Never lose the keystore of an app not using Play App Signing, you cannot publish updates without it.
0

Your reply

Every post is reviewed by DEV3 before it appears. Usually reviewed within 24 hours.

Markdown supported. Use ``` for code blocks. Images are not allowed.