App Signing and AAB Basics for Your First Google Play Release

For your first Google Play release you need to upload a signed Android App Bundle (.aab), not an APK. Google holds the final app signing key through Play App Signing, and you sign your upload with a separate upload key. Get those two ideas straight and most first-release errors go away.
This post covers what you need to know, what to back up, and the mistakes that tend to cost indie developers an afternoon. Requirements change, so check Play Console Help for current details such as the minimum target API level.
AAB vs APK: what's the difference?
An APK is a finished, installable package. An AAB is a publishing format. You upload it, and Google Play generates optimized APKs for each device (screen density, CPU architecture, language) from it.
- You cannot install an .aab file directly on a phone.
- New apps on Google Play are expected to be published as AABs. Check Play Console Help for the current rule.
- Users download less than a universal APK would give them, because they only get the parts their device needs.
The official overview is on developer.android.com.
Two keys, two jobs
This is where most confusion comes from. With Play App Signing there are two keys:
- App signing key: the key that signs the APKs users actually install. Google stores and protects it.
- Upload key: the key you keep. You use it to sign the AAB you upload, so Google can check the upload came from you.
Because Google holds the app signing key, losing your upload key is recoverable. You can request an upload key reset in Play Console. Losing a key you managed entirely yourself, with no Play App Signing, was far worse. That is a good reason to use the default.
Treat the upload key like a password to your app's publishing pipeline. It is recoverable, but a reset is slower than a backup.
Create your upload keystore
In Android Studio, go to Build > Generate Signed App Bundle / APK, choose Android App Bundle, and create a new keystore. Or use the command line:
keytool -genkeypair -v -keystore upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
Then:
- Choose a strong keystore password and a key password.
- Note the alias (
uploadin the example). - Store the .jks file and both passwords in a password manager.
- Keep a second copy somewhere separate, such as an encrypted backup drive.
Keep it out of your repository
Do not commit the keystore or passwords to Git, even a private repo. A common pattern is a keystore.properties file listed in .gitignore, which your build.gradle reads for the signingConfigs block. Your CI, if you have one, can inject the same values as secrets.
The Android documentation on app signing walks through the Gradle setup.
Build the bundle
From Android Studio, finish the signed bundle wizard and pick the release build type. From the terminal, run ./gradlew bundleRelease. If your signing config is wired up, the output lands at app/build/outputs/bundle/release/app-release.aab.
Before you upload, check these:
- It is a release build, not debug. Debug-signed bundles are rejected.
- The applicationId is final. The package name identifies your app on Google Play permanently. You cannot change it later on the same listing.
- versionCode is a positive integer and higher than any build you've uploaded before.
- The target API level meets Google's current requirement. This changes over time, so look it up in Play Console Help.
Version codes: the small rule that bites
Every upload to your app, on any track, needs a versionCode that has not been used before. If you upload build 1 to a closed test and then fix a bug, the fixed build must be 2 or higher. Play Console will reject a repeated number.
versionName is just the label users see, like "1.0.3". It can be anything, and it doesn't affect ordering.
A simple habit is to bump versionCode by one every time you build something you intend to upload. Some developers derive it from a CI build number so they never think about it.
Uploading to Play Console
When you create the first release, Play Console asks you to use Play App Signing. For new apps this is the standard path, and it is what you want. Upload your signed .aab to your closed testing track (or internal testing first, if you want a fast sanity check), add release notes, and roll it out.
If you have not set up the track yet, see our post on creating a closed testing track step by step in the blog archive.
What Play Console does with your bundle
- Checks the signature against your upload key.
- Checks the package name, version code and target API level.
- Generates the APKs users will install, signed with the app signing key.
- Flags warnings, such as missing native debug symbols or permissions that need a declaration.
Read the warnings. Some are harmless, and some become policy problems later.
Test the bundle before real people do
Since you cannot sideload an AAB, you have three options:
- Internal app sharing in Play Console, which gives you a link to install an uploaded build quickly. Check Play Console Help for how to enable it.
- Internal testing track, which is slower to set up but closer to the real flow.
bundletool, Google's command-line tool, which turns your .aab into APKs you can install on a device or emulator.
Whichever you choose, install the build the way a user would, on a real phone, and open it cold. Release builds can behave differently from debug builds, especially if you enabled code shrinking with R8. Crashes caused by missing ProGuard/R8 keep rules often show up only here.
The SHA-1 gotcha with Google Sign-In, Firebase and Maps
If your app uses Google Sign-In, Firebase Auth, or a restricted Maps API key, you registered a SHA-1 fingerprint during development. That was probably your debug key or your upload key.
Users, however, install APKs signed by Google's app signing key, which has a different fingerprint. In Play Console, find the app signing key certificate fingerprints under the app integrity or app signing settings (the exact menu location may change), and add them to Firebase or Google Cloud. Otherwise sign-in works for you and fails for everyone else, which is a miserable thing to discover during a closed test.
Common first-release errors
- "You uploaded a debug APK or AAB." Build the release variant.
- "Version code has already been used." Increase
versionCode. - "Your APK or bundle is signed with the wrong key." You signed with a key other than the upload key registered for this app. Use the same keystore each time.
- Target API level too low. Raise
targetSdkand retest. - Uploaded an APK to a bundle-only flow. Build an AAB instead.
Why this matters before a closed test
A closed test is the stage where new personal accounts need 12 testers opted in for 14 days in a row before applying for production. A messy signing setup is an annoying thing to untangle in the middle of that. Fix the key and versioning habits first, then invite testers.
When your signed AAB is in the closed track, TesterMob can supply real testers on their own Android phones for a one-time $9.99 per app, paid in USDT. See pricing for details. We can't guarantee production approval, since that decision belongs to Google, but a stable, correctly signed build gives your testers something that installs and runs.
Quick checklist
- Generate an upload keystore and back it up in two places.
- Keep keystore and passwords out of version control.
- Confirm the applicationId is final.
- Build a release AAB with
bundleRelease. - Increase
versionCodefor every upload. - Enroll in Play App Signing when prompted.
- Test the release build on a real device.
- Add the app signing key's SHA-1 to Firebase, Google Cloud or any API that checks it.
For more on how testing and our process work, the FAQ is a good next stop.