apksigner: Sign and Verify Android APKs in CI
apksigner sign applies a v1/v2/v3 signature to an APK using a keystore, and apksigner verify checks an APK is validly signed.
apksigner is the modern APK signer that replaced jarsigner for Android, adding the v2+ signature schemes. It must run after zipalign, and its password flags are what make it CI-friendly.
What it does
apksigner sign signs an APK with a key from a keystore, producing v1 (JAR), v2, v3, and v4 signatures as configured. apksigner verify checks the signatures and can report which schemes are present. It lives in build-tools and requires the APK to already be zipaligned.
Common usage
# align first, then sign
zipalign -p 4 app-unsigned.apk app-aligned.apk
$ANDROID_HOME/build-tools/34.0.0/apksigner sign \
--ks release.keystore --ks-key-alias upload \
--ks-pass env:KS_PASS --key-pass env:KEY_PASS \
--out app-release.apk app-aligned.apk
apksigner verify --verbose app-release.apkOptions
| Flag | What it does |
|---|---|
| sign / verify | Sign an APK or verify its signatures |
| --ks <file> | Keystore containing the signing key |
| --ks-key-alias <alias> | Key alias inside the keystore |
| --ks-pass env:VAR / pass:x | Keystore password source |
| --key-pass env:VAR | Key password source (if different) |
| --out <file> | Output signed APK |
| --verbose | On verify, list signature scheme details |
In CI
Pass passwords with env:VAR (or file:...) sourced from secrets, never on the command line where they leak into logs. zipalign must run before apksigner, not after, because aligning after signing invalidates the v2 signature. Decode a base64 keystore secret to a temp file at job start.
Common errors in CI
"Keystore was tampered with, or password was incorrect" means a wrong --ks-pass. "No key with alias 'x' found in keystore" means the --ks-key-alias is wrong; list aliases with keytool -list. "APK Signature Scheme v2 signature ... did not verify" often means zipalign ran after signing. "DOES NOT VERIFY ... not signed" means the APK is unsigned. On JDK issues, apksigner needs a JDK on PATH.