Skip to content

Instantly share code, notes, and snippets.

@osipxd
Last active August 13, 2022 21:23
Show Gist options
  • Save osipxd/4894ecabe8427e352f92f6c5743034af to your computer and use it in GitHub Desktop.
Save osipxd/4894ecabe8427e352f92f6c5743034af to your computer and use it in GitHub Desktop.
Script to sign APK and AAB from command line
#!/usr/bin/env bash
#
# Script for APK and AAB signing.
#
# Usage: ./sign-app.sh <format> <path_to_app> <keystore_base64> <properties_base64>
#
# format - should be one of: apk or aab
# path_to_app - path to apk/aab file or '--auto' to automatically detect path
# keystore_base64 - Base64 encoded keystore file
# properties_base64 - Base64 encoded properties file. This file should contain:
# store_password, key_alias, key_password
#
set -euo pipefail
# Script can be run from any directory.
DIR=$(cd "$(dirname "$0")" && pwd)
source "$DIR"/formatting.sh
# Validate arguments
tmp=$(mktemp -d)
keystore="$tmp/sign.keystore"
properties="$tmp/sign.properties"
# Remove tmp directory before exit if it exists
function cleanup() {
result=$?
if [[ -d ${tmp} ]]; then
log_trace_progress "Removing temporary data"
rm -rf "$tmp"
log_trace "OK."
fi
exit $result
}
trap cleanup EXIT
if [[ "$#" -eq 4 ]]; then
echo "$3" | base64 --decode >"$keystore"
echo "$4" | base64 --decode >"$properties"
else
log_error "Usage: ./sign-app.sh <format> <path_to_app> <keystore_base64> <properties_base64>"
exit 1
fi
format=$1
if ! [[ ${format} =~ ^(apk|aab)$ ]]; then
log_error "Unknown format. Available formats are: apk, aab"
exit 1
fi
app_path=$2
if [[ ${app_path} == "--auto" ]]; then
log_trace "Trying to find .$format file..."
app_path=$(find ./*/build/outputs -type f -name "*.$format" | head -n 1)
if [[ -z "$app_path" ]]; then
log_error "No .$format file found. Specify path to .$format manually"
exit 1
fi
app_path=$(realpath "$app_path")
fi
log_info "Input file: $app_path"
log_trace_progress "Reading keystore properties"
source "$properties"
function report_missing_field() { log_error "Field '$1' is not set"; exit 1; }
[[ -n "${store_password:=}" ]] || report_missing_field "store_password"
[[ -n "${key_password:=}" ]] || report_missing_field "key_password"
[[ -n "${key_alias:=}" ]] || report_missing_field "key_alias"
log_trace "OK."
case $format in
aab)
# Remove old signature if exists
zip -dq "$app_path" 'META-INF/*' 2>/dev/null && log_info "Old signature removed"
new_line
# Sign App Bundle
jarsigner -sigalg SHA256withRSA -digestalg SHA-256 \
-keystore "$keystore" -storepass "$store_password" -keypass "$key_password" \
"$app_path" "$key_alias" >/dev/null
# Print certificate info
keytool -printcert -jarfile "$app_path"
;;
apk)
tmp_apk="$tmp/$(basename "$app_path").tmp"
rm -f "$tmp_apk"
# Check if APK is aligned
if zipalign -c 4 "$app_path"; then
# APK is aligned. Just copy it "as is"
cp "$app_path" "$tmp_apk"
else
# APK is not aligned. Align it!
zipalign -v -p -f 4 "$app_path" "$tmp_apk" | grep -v "(OK.*)"
fi
# Sign APK
apksigner sign --verbose --ks "$keystore" --ks-pass pass:"$store_password" \
--ks-key-alias "$key_alias" --key-pass pass:"$key_password" \
--in "$tmp_apk" --out "$app_path" >/dev/null
rm -f "$tmp_apk"
# Print certificate info
new_line
apksigner verify --print-certs "$app_path"
;;
esac
log_success "SIGNED SUCCESSFULLY."
#
# Colors to use in scripts.
# Usage: source formatting.sh
#
# List of available colors and effects:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
RESET="\033[0m"
F_BOLD="\033[1m"
F_BOLD_RESET="\033[22m"
C_RED="\033[31m"
C_GREEN="\033[32m"
C_YELLOW="\033[33m"
C_GRAY="\033[37m"
function new_line() { printf -- '\n'; }
function log_info() { printf -- "%s\n" "$*"; }
function log_trace_progress() { printf -- "${C_GRAY}%s... ${RESET}" "$*"; }
function log_trace() { printf -- "${C_GRAY}%s${RESET}\n" "$*"; }
function log_success() { printf -- "\n${F_BOLD}${C_GREEN}%s${RESET}\n" "$*"; }
function log_warning() { printf -- "\n${F_BOLD}${C_YELLOW}WARNING:${F_BOLD_RESET} %s${RESET}\n" "$*"; }
function log_error() { printf -- "\n${F_BOLD}${C_RED}ERROR:${F_BOLD_RESET} %s${RESET}\n" "$*"; }
function log_mode_error() { printf -- "$C_RED"; }
function log_mode_normal() { printf -- "$RESET"; }
# Sample properties file
key_alias=androiddebugkey
key_password=android
store_password=android
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment