APK signing
Android development
app release
unsigned APK
mobile app security

app-release-unsigned.apk is not signed

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If your build output is named app-release-unsigned.apk, the filename is telling you exactly what happened: Gradle produced a release artifact, but no release signing configuration was applied. That APK is useful as an intermediate build product, but it is not the final package you should ship to users.

Android requires release artifacts to be signed. The fix is usually not a mysterious SDK issue; it is almost always a missing or misconfigured signing setup in Gradle or in the Android Studio release wizard.

Why the APK Is Unsigned

Android differentiates between building and signing. Compilation turns your source code and resources into an APK. Signing adds the cryptographic identity that Android uses for installation, updates, and distribution.

If you run a task such as assembleRelease without a valid signingConfig for the release build type, Android Gradle Plugin can still build the package, but it names the output app-release-unsigned.apk to make it clear that the signing step has not happened.

That distinction matters because:

  • devices expect installed release apps to be signed
  • updates must be signed with the same key as earlier releases
  • app stores require signed release artifacts

Configure Signing in Gradle

The normal fix is to define a release signing configuration and attach it to the release build type. In Kotlin DSL, it looks like this:

kotlin
1android {
2    signingConfigs {
3        create("release") {
4            storeFile = file("release-keystore.jks")
5            storePassword = providers.gradleProperty("KEYSTORE_PASSWORD").get()
6            keyAlias = providers.gradleProperty("KEY_ALIAS").get()
7            keyPassword = providers.gradleProperty("KEY_PASSWORD").get()
8        }
9    }
10
11    buildTypes {
12        getByName("release") {
13            isMinifyEnabled = true
14            signingConfig = signingConfigs.getByName("release")
15            proguardFiles(
16                getDefaultProguardFile("proguard-android-optimize.txt"),
17                "proguard-rules.pro"
18            )
19        }
20    }
21}

Put the secrets in ~/.gradle/gradle.properties or another secure local source instead of committing them to version control:

properties
KEYSTORE_PASSWORD=change-me
KEY_ALIAS=release
KEY_PASSWORD=change-me

Once that configuration exists, running ./gradlew assembleRelease should produce a signed release APK in the module's build/outputs/apk/release/ directory.

Signing Manually When Needed

If you already have an unsigned APK and need to sign it outside Gradle, the usual command-line flow is:

  1. align the APK with zipalign
  2. sign it with apksigner
  3. verify the signature

Example:

bash
1zipalign -v -p 4 app-release-unsigned.apk app-release-aligned.apk
2
3apksigner sign \
4  --ks release-keystore.jks \
5  --out app-release.apk \
6  app-release-aligned.apk
7
8apksigner verify --verbose --print-certs app-release.apk

This is mainly useful for custom build pipelines or debugging. In a normal Android project, Gradle should do the signing for you.

Android Studio and App Bundles

If you build from Android Studio, the menu item Build > Generate Signed Bundle / APK walks you through the same signing configuration. That is often the fastest way to confirm whether the problem is your Gradle file or your keystore setup.

Also note that many teams now publish an .aab app bundle rather than a raw APK. The same idea still applies: release artifacts must be signed. If you use Play App Signing, you still sign what you upload, usually with an upload key, and Google manages the distribution signing key after upload.

Generate a Keystore

If you do not yet have a release key, create one with keytool:

bash
1keytool -genkeypair \
2  -v \
3  -keystore release-keystore.jks \
4  -alias release \
5  -keyalg RSA \
6  -keysize 2048 \
7  -validity 10000

Back that file up securely. Losing the release key or upload key can turn a routine release process into an account recovery problem.

Common Pitfalls

The most common mistake is assuming assembleRelease automatically means "signed release build." It only does so if signingConfig is set for the release build type.

Another common issue is putting keystore passwords directly into build.gradle. That works locally, but it is a security problem and tends to leak into source control. Use Gradle properties, environment variables, or your CI secret store instead.

Teams also forget that zipalign must happen before apksigner when signing an APK manually. If you modify the APK after signing it, the signature becomes invalid.

Finally, do not confuse debug signing with release signing. Android Studio can install debug builds because they are signed with a debug key, but that does not make them appropriate for production or for publishing updates.

Summary

  • 'app-release-unsigned.apk means the build succeeded but release signing did not run.'
  • The usual fix is to define a signingConfig and attach it to the release build type.
  • Manual signing uses zipalign, then apksigner, then signature verification.
  • App bundles also require signing, even when Play App Signing is enabled.
  • Keep keystores and passwords secure because future updates depend on the same signing identity.

Course illustration
Course illustration

All Rights Reserved.