Before I publish an Android app or an update, I check three things in this order: that the build targets the API level Google Play currently accepts, that I am uploading an Android App Bundle and not an APK, and that the bundle is signed with the upload key Play Console has on file. Each one can stop an upload cold, and none of them has anything to do with whether the app works.
Most write-ups about shipping a side project skip the Play Console part. In my experience that is where releases stall, usually on a project I have not opened in six months. These are the three checks in the order they have cost me time, with every claim checked against Google's documentation as of October 2026.
What target API level does Google Play require right now?
Since August 31, 2026, new apps and app updates must target Android 16 (API level 36) or higher to be submitted to Google Play. Wear OS and Android Automotive OS apps must target API level 35, and Android TV and Android XR apps must target API level 34. Developers can request an extension to November 1, 2026.
That comes from the Play Console Help page Target API level requirements for Google Play apps. The same page shows the pattern: the submission floor was API level 35 from August 31, 2025, and it moved to 36 exactly a year later. A build that uploaded cleanly in spring can be refused in autumn with no code change on your side.
There is a second rule that people merge with the first. Existing apps must target API level 35 or higher to stay available to new users on devices running a newer Android version than the app targets. That one is about who can find an app you leave alone. The first one is about whether you can ship anything at all.
The check itself takes ten seconds. Open the module-level build file:
// app/build.gradle.kts
android {
compileSdk = 36
defaultConfig {
minSdk = 24
targetSdk = 36
}
}
Raising targetSdk does not change which devices can install the app. That is still governed by minSdk. What it changes is how the newest Android versions treat your app, so a bump is a behavior change and not just a number. Run a smoke test on an Android 16 device or emulator before you build the release. My guide to the Android 16 target API deadline covers what breaks at API 36 and how the extension request works.
Do you still need to upload an AAB instead of an APK?
Yes, for any app created since August 2021. Google Play requires new apps to publish with the Android App Bundle. Apps created before August 2021 can still add either app bundles or APKs to a release, and TV apps have had to use app bundles for updates since June 2023.
The Android App Bundle documentation states the August 2021 requirement, and the Play Console Help page on preparing a release confirms the exception for what it calls legacy apps. So my old shorthand, that Play expects an .aab for any new submission, was slightly too broad. An older app may still be allowed to upload an APK. I would switch anyway, because the bundle is what Play uses to generate optimized APKs for each device.
If your release habit is still the APK task, change it. Android's command line build guide says to run the bundle task for your variant on the app's base module:
# macOS and Linux, from the project root
./gradlew :app:bundleRelease
# Windows
gradlew.bat :app:bundleRelease
Gradle signs the bundle if the release build type has a signing configuration, and writes it under the module's build/outputs/ directory. Keep the passwords out of the build file:
// app/build.gradle.kts
android {
signingConfigs {
create("release") {
storeFile = file("upload-keystore.jks")
storePassword = System.getenv("UPLOAD_STORE_PASSWORD")
keyAlias = "upload"
keyPassword = System.getenv("UPLOAD_KEY_PASSWORD")
}
}
buildTypes {
getByName("release") {
signingConfig = signingConfigs.getByName("release")
}
}
}
Confirm the file you are about to upload ends in .aab. Three details from the documentation are worth knowing here. You cannot install an app bundle directly on a device, so the .aab is for upload only. You must be enrolled in Play App Signing to upload one. And the versionCode must increase with every update while staying at or below 2,100,000,000. That last rule produces its own upload error, covered in my post on version codes that have already been used.
How does Play App Signing separate the upload key from the app signing key?
With Play App Signing you sign each bundle with an upload key that you hold, and Google uses it to verify that the upload came from you. Google then signs the APKs delivered to devices with a separate app signing key that it stores. The two certificates have different fingerprints.
The Play Console Help page Use Play App Signing lays the two out side by side:
| Key | Who holds it | What it does | If it is lost |
|---|---|---|---|
| Upload key | You, in a .jks or .keystore file | Signs the bundle before upload so Google can verify your identity. Must be RSA, 2048 bits or more. | Google can reset it for you. |
| App signing key | Google Play | Signs the final APKs delivered to users' devices. | Held by Google, so there is nothing for you to lose. |
New apps are enrolled automatically, with Google generating the app signing key. As of this writing the help page also says new apps get quantum-ready hybrid signing, which means Google signs with more than one app signing key depending on the Android version of the device. Your side does not change: you still hold exactly one upload key.
I used to describe the returning-developer problem as "signing key rotation". That was the wrong name for it. What actually happens is simpler. If you opted an older app in to Play App Signing and created a new upload key at that point, the original keystore stopped being the one Play expects for uploads. If you did not create a new upload key, Android's app signing documentation says you keep using the original app signing key as your upload key. Two years later, with three keystore files in a backup folder, you will not remember which case you are in.
Where does Play Console show the upload and app signing certificates?
Open your app in Play Console and go to Protected with Play, then Play Store distribution, then Go to Play app signing. The page has an App signing key section and an Upload key certificate section, each with fingerprints you can copy. Older documentation calls this location Setup, then App signing or App integrity.
My original note for this check said "Setup, App integrity". The current help page uses the Protected with Play path, while some Android documentation pages still give the older one. Whichever label your console shows, you are looking for the page that lists both certificates.
Then compare the upload key certificate against what you have locally:
# Fingerprints of the key inside your keystore
keytool -list -v -keystore upload-keystore.jks -alias upload
# Fingerprints of whatever signed the bundle you just built
keytool -printcert -jarfile app-release.aab
# Or let Gradle print the signing details for every variant
./gradlew signingReport
The SHA-1 or SHA-256 that keytool prints for your bundle must match the upload key certificate in Play Console. If it matches the app signing key instead, or matches nothing, you have the wrong keystore, and Play will not accept the bundle.
If the right keystore is gone, you are not locked out. The help page describes an upload key reset: create a new upload key, export its certificate as a PEM file, and submit the request from the Play app signing page.
keytool -export -rfc -keystore upload-keystore.jks -alias upload -file upload_certificate.pem
One more thing lives on that page. The app signing key fingerprint, not the upload one, is what third-party APIs need, which is half of why a release build can work locally but fail from Google Play.
What these three checks do not cover
Passing all three gets your bundle accepted. It does not get your app published. A release still goes through review, and how long Google Play app review takes varies more than most people expect. If you opened a personal developer account after November 13, 2023, Play Console also requires you to meet its testing requirements before production access, which I explain in the post on the 12 testers closed testing requirement.
The three checks are also not a substitute for running the build. They are the things that fail before anyone runs it.
Where IOn Emit fits
IOn Emit is the Windows desktop app I built for the publishing side of this. Its 9-step Pre-Flight Wizard walks through the Play Console setup questions in plain English, its AAB analyzer detects permissions and maps them to Data Safety, and Quick Push lets you drop in a bundle and pick the track and rollout percentage. The free tier includes the publishing suite. The three checks above still happen in your Gradle files and in Play Console.
The checklist before you publish
- Target API level:
targetSdkis 36 or higher (35 for Wear OS and Android Automotive OS, 34 for Android TV and Android XR). - Smoke test: the app launches and its main flow works on an Android 16 device or emulator.
- Version code:
versionCodeis higher than every build you have uploaded before. - Bundle: you built with
bundleReleaseand the file ends in.aab. - Signature:
keytool -printcert -jarfileon the bundle prints the same SHA-1 as the upload key certificate in Play Console. - First stop: upload to the internal testing track before production.
This post is part of our app publishing guides for indie Android developers.