Why Android Apps Must Be Signed
Every Android app must be digitally signed with a certificate before it can be installed on a device or published to Google Play. The signature serves as the developer's identity and ensures the app has not been tampered with. Unsigned APKs/AABs simply will not install.
Unlike iOS, where Apple manages much of the signing infrastructure, Android signing is largely self-managed through keystores that you create and maintain.
Key Concepts
Keystore
A keystore is a file (.jks or .keystore) that contains one or more cryptographic key pairs. Each key pair has:
- Private key: Used to sign the app (keep this secret)
- Public key: Embedded in the certificate that Android uses to verify the signature
Signing Key vs. Upload Key
Google Play App Signing (enabled by default for new apps) separates two concepts:
- App signing key: The key Google uses to sign the final APK delivered to users. Google manages this key.
- Upload key: The key you use to sign your AAB before uploading to Google Play. Google verifies this signature, strips it, and re-signs with the app signing key.
This separation means if your upload key is compromised, you can contact Google to reset it. If you managed the signing key yourself and lost it, you would lose the ability to update your app forever.
Setting Up Signing
Generate a Keystore
Use the keytool command (included with the Java SDK):
The command creates a keystore file with an alias (name) for your key. Store the keystore file and passwords securely. If you lose the keystore and are not using Play App Signing, you lose the ability to update your app.
Configure Gradle
In your app's build.gradle, define signing configurations:
- Reference the keystore path, alias, and passwords
- Apply the signing config to your release build type
- Never hardcode passwords in build.gradle. Use environment variables or a local properties file excluded from version control.
Enroll in Play App Signing
When you upload your first AAB to Google Play Console:
- Google generates and stores the app signing key (or you can upload an existing one)
- You download the upload key certificate from Play Console
- All subsequent uploads use your upload key
- Google re-signs with the app signing key for distribution
Signing in CI/CD
For automated builds, you need the keystore and credentials available to the build machine:
- Store the keystore as a Base64-encoded CI secret
- Store passwords as separate CI secrets
- Decode the keystore during the build step
- Reference environment variables in your Gradle signing config
Fastlane
Fastlane's supply action handles the upload to Google Play. Signing still happens through Gradle. Fastlane does not manage Android keystores the way Match manages iOS certificates.
GitHub Actions Example Flow
- Decode the keystore from a Base64 secret to a file
- Set environment variables for keystore path, alias, and passwords
- Run ./gradlew bundleRelease (Gradle uses the signing config)
- Upload the signed AAB to Google Play using Fastlane or the Google Play API
Key Rotation
Android supports key rotation through APK Signature Scheme v3+ and Play App Signing:
- If using Play App Signing, Google handles key rotation when needed
- For self-signed apps, Android 9+ supports proof-of-rotation, allowing you to rotate to a new key while maintaining update compatibility
- Upload keys can be reset through Google Play Console support if compromised
Common Mistakes
Lost keystore: Without Play App Signing, losing your keystore means creating a new app listing. Enable Play App Signing from the start to avoid this.
Wrong keystore in release build: Using the debug keystore for release builds. Google Play will reject it since the debug keystore is not the enrolled upload key.
Hardcoded credentials: Committing keystore passwords to Git. Use environment variables or .properties files in .gitignore.
Ignoring backup: Store your keystore in a secure, backed-up location (password manager, encrypted cloud storage). Do not keep it only on one developer's machine.
Debug vs. Release Signing
Android Studio automatically creates a debug keystore for development. It is shared across all apps on that machine and is not suitable for production:
- Debug keystore: Auto-generated, shared, no security
- Release keystore: You create it, unique to your app, must be secured
Some services (Google Maps, OAuth) require your signing certificate's SHA-1/SHA-256 fingerprint. Make sure you register both debug and release fingerprints during development.
Best Practices
- Enable Google Play App Signing for every new app
- Back up your keystore in at least two secure locations
- Use strong, unique passwords for the keystore and key alias
- Never commit keystores or passwords to version control
- Document your signing setup so the team is not dependent on one person
- Test release builds locally before uploading to verify signing works