Skip to content

Instantly share code, notes, and snippets.

@nilium
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nilium/8882334 to your computer and use it in GitHub Desktop.
Save nilium/8882334 to your computer and use it in GitHub Desktop.
#!/bin/sh
#
# sign.sh -- signing utility for Android APKs
# Made by Noel Cower. This file is public domain, or at least I'm not
# going to care what you do with it.
#
RED=''
GREEN=''
YELLOW=''
BLUE=''
NO_COLOR=''
info () { echo "${BLUE}[info]${NO_COLOR} $*" 1>&2 ; }
succ () { echo "${GREEN}[success]${NO_COLOR} $*" 1>&2 ; }
warn () { echo "${YELLOW}[warning]${NO_COLOR} $*" 1>&2 ; }
err () { echo "${RED}[error]${NO_COLOR} $*" 1>&2 ; }
verbose () { if [[ $VERBOSE != 0 ]] ; then echo "$*" ; fi }
usage () {
cat <<EOS
sign.sh alias [-rdh] [-k KEY] [-- title ...]
-r Attempt to sign release APKs. (Default)
-d Attempt to sign debug APKs.
-k KEY Set the keystore to use for all APKs.
-v Enable verbose output.
-h Display this help text.
If no APK title is provided, sign.sh defaults to the basename of the
current git repo root (via 'git rev-parse --show-toplevel').
The signing key is chosen per-APK based on the APK title. Each APK is
assumed to have a signing key under '~/.android/TITLE-key.keystore'.
If this key isn't available, it then falls back to and uses
'~/.android/release.keystore' if it exists. To override either of these,
you may either export an APK_KEY environment variable or pass the -k
option to specify the path to a key. Overriding the per-APK key sets the
key to use for all APKs being signed.
EOS
exit 2
}
KEYALIAS="$1"
shift
ARGS=`getopt 'vhdrk:' $*`
RM='rm -f'
JARSIGNER='jarsigner'
ZIPALIGN='zipalign'
PREFIX=${PREFIX:-}
if [[ $? != 0 ]]; then
usage
fi
IN_DEBUG=0
VERBOSE=0
set -- $ARGS
for arg ; do
case "$arg"
in
'-h')
usage;;
'-d')
IN_DEBUG=1
shift;;
'-r')
IN_DEBUG=0
shift;;
'-v')
VERBOSE=1
RM='rm -vf'
JARSIGNER='jarsigner -verbose'
ZIPALIGN='zipalign -v'
shift;;
'-k')
APK_KEY="$2"; shift;
info "Using key: '$APK_KEY'"
shift;;
'--')
shift; break;;
esac
done
FILES="$*"
if [[ -z "$FILES" ]] ; then
info "No APK titles specified, using APK_TITLE variable or repo root directory name"
FILES="${APK_TITLE:-"$(basename "`git rev-parse --show-toplevel`")"}"
if [[ -z "$FILES" ]] ; then
usage
fi
fi
APK_QUALIFIER="release"
if [[ $IN_DEBUG != 0 ]] ; then
APK_QUALIFIER='debug'
warn "Attempting to sign debug release"
fi
HAD_ERRORS=0
for APK_TITLE in $FILES ; do
APK_SOURCE_FILE="target/android-bin/${APK_TITLE}-${APK_QUALIFIER}-unsigned.apk"
APK_BASE="${APK_TITLE}-${APK_QUALIFIER}"
APK_SIGNED_UNALIGNED="${APK_BASE}-unaligned.apk"
APK_SIGNED_ALIGNED="${APK_BASE}.apk"
SEL_APK_KEY="${APK_KEY:-$HOME/.android/${APK_TITLE}-key.keystore}"
verbose "Source APK: $APK_SOURCE_FILE"
verbose "Signed unaligned APK: $APK_SIGNED_UNALIGNED"
verbose "Signed aligned APK: $APK_SIGNED_ALIGNED"
if [[ -z "$APK_KEY" ]] ; then
verbose "Trying default APK key: '$SEL_APK_KEY'"
fi
if [[ ! -e "$APK_SOURCE_FILE" ]] ; then
err "'$APK_SOURCE_FILE' does not exist -- skipping '$APK_TITLE'"
HAD_ERRORS=1
continue
elif [[ ! -e "$SEL_APK_KEY" ]] ; then
LAST_KEY="$SEL_APK_KEY"
SEL_APK_KEY="$HOME/.android/release-key.keystore"
if [[ "$SEL_APK_KEY" != "$LAST_KEY" ]] ; then
warn "'$LAST_KEY' does not exist, falling back to default '$SEL_APK_KEY' for signing"
fi
if [[ ! -e "$SEL_APK_KEY" ]] ; then
if [[ "$SEL_APK_KEY" == "$LAST_KEY" ]] ; then
err "'$SEL_APK_KEY' does not exist -- skipping '$APK_TITLE'"
else
err "Neither '$LAST_KEY' nor '$SEL_APK_KEY' exist -- skipping '$APK_TITLE'"
fi
HAD_ERRORS=1
continue
fi
fi
info "Signing $APK_SOURCE_FILE with $SEL_APK_KEY"
$RM "$APK_SIGNED_UNALIGNED" "$APK_SIGNED_ALIGNED"
$JARSIGNER -sigalg SHA1withRSA -digestalg SHA1 -keystore "$SEL_APK_KEY" -signedjar "$APK_SIGNED_UNALIGNED" "$APK_SOURCE_FILE" "$KEYALIAS"
if [[ $? != 0 ]] ; then
err "Failed to sign '$APK_SOURCE_FILE' -- skipping '$APK_TITLE'"
HAD_ERRORS=1
continue
fi
$ZIPALIGN 4 "$APK_SIGNED_UNALIGNED" "$APK_SIGNED_ALIGNED"
done
exit $HAD_ERRORS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment