Skip to content

Android Signing Configuration

To publish your Android app on the Google Play Store, you must sign it with a release keystore. This ensures the app comes from a trusted source and enables app updates.

The project includes conditional signing configuration that:

  • Uses your release keystore when key.properties is configured
  • Falls back to debug signing if no keystore is present (for development)
  • Never breaks the build
  • Android SDK installed
  • Java JDK (for keytool command)
  • Google Play Developer account ($25 one-time fee)

Create a new keystore file:

macOS / Linux:

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

Windows:

Terminal window
keytool -genkey -v -keystore %userprofile%\upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload

You will be prompted for:

  • Keystore password
  • Key password (can be same as keystore)
  • Your name, organization, location

Copy the template file and fill in your details:

Terminal window
cp android/key.properties.template android/key.properties

Then edit android/key.properties:

storePassword=your_keystore_password
keyPassword=your_key_password
keyAlias=upload
storeFile=../app/upload-keystore.jks

Tip: The template file is already included at android/key.properties.template for your convenience.

Place your .jks file in the android/app/ directory:

Terminal window
mv ~/upload-keystore.jks android/app/

The build.gradle.kts is already configured with conditional signing. It will automatically detect your key.properties file and use it for release builds.

The configuration works like this:

  • If key.properties exists → Uses release signing with your keystore
  • If no key.properties → Uses debug signing (for development)

This means the app will build successfully whether or not you’ve configured signing yet.

After configuring signing:

Terminal window
# APK
flutter build apk --release
# App Bundle (recommended for Play Store)
flutter build appbundle --release

Output locations:

  • APK: build/app/outputs/flutter-apk/app-release.apk
  • AAB: build/app/outputs/bundle/release/app-release.aab

The following are already excluded in .gitignore:

  • android/key.properties
  • *.jks
  • *.keystore

Always keep your keystore file backed up securely (e.g., in a password manager or secure cloud storage).

  1. Use strong passwords - Minimum 8 characters with mixed case, numbers, and symbols
  2. Back up your keystore - If you lose it, you cannot update your app
  3. Store passwords securely - Use a password manager
  4. Different keystores for different apps - Don’t reuse keystores
  1. Log in to Google Play Console
  2. Create a new app
  3. Upload your signed AAB file
  4. Complete store listing information
  5. Submit for review

Cause: File doesn’t exist or path is wrong

Solution:

Terminal window
# Verify file exists
ls android/key.properties
# Verify path in key.properties points to correct location
# Should be: storeFile=../app/your-keystore.jks

Cause: .jks file not in correct location

Solution:

Terminal window
# Move keystore to android/app/
mv your-keystore.jks android/app/

Cause: Password in key.properties doesn’t match the keystore

Solution:

  1. Double-check the password in key.properties
  2. If you forgot the password, you cannot recover the keystore
  3. Create a new keystore and update your Play Store listing

Cause: key.properties not found or misconfigured

Solution:

Terminal window
# Check if file exists
ls -la android/key.properties
# Check contents (don't share this output!)
cat android/key.properties

If you need to customize the signing configuration, edit android/app/build.gradle.kts:

// Located near the top of the file
import java.util.Properties
// Load keystore properties if they exist
val keystorePropertiesFile = rootProject.file("key.properties")
val hasKeyProperties = keystorePropertiesFile.exists()
android {
// ... existing configuration ...
signingConfigs {
create("release") {
if (hasKeyProperties) {
val keystoreProperties = Properties()
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
storeFile = file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
}
}
}
buildTypes {
release {
// Uses release signing if key.properties exists, otherwise debug
signingConfig = if (hasKeyProperties) {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
}
}
}
}