Skip to content

Instantly share code, notes, and snippets.

@markusfisch
Last active January 21, 2023 15:15
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save markusfisch/3982948 to your computer and use it in GitHub Desktop.
Save markusfisch/3982948 to your computer and use it in GitHub Desktop.
Handy shell script that eases building and running Android apps from the command line with ant and adb

Handy Android shortcuts

This little script eases building, running, testing and analyzing Android apps with ant and adb.

You may also see it as interactive dictionary of useful adb commands.

How to use

Assuming your path includes android-sdk/tools and android-sdk/platform-tools, just put the bash script somewhere in your path (i.e. ~/bin/) and give it a proper name, say 'and'.

Configuring your app

Go to the root of your Android project (i.e. the folder that contains AndroidManifest.xml) and type

$ and update

Now you should have a file called build.xml and can build your project from the command line.

Build, install and run

Since that's probably the most used command, it's the default command:

$ and

Create new projects

To create a fresh new project in the current directory run:

$ and create com.example.android.yourapp

Stress test your app

Have a monkey walking over your touch screen:

$ and stress

May be it does produce something from Shakespeare.

Check memory usage of your app

$ and mem

Overview

Type

$ and help

and you'll see the full list of available functions:

manifest - Parse manifest for given patterns and print first argument value
package - Print package
activity - Print first activity
clean - Clean builds & resources
build - Build
install - Build & install
uninstall - Uninstall package
stress - Stress test given application
start - Start given activity
run - Build, install & run
release - Run release, needs key.store & key.name to be set in ant.properties
debug - Run debug
emus - List available emulators or only the requested one
emu - Fire up given (or last used) emulator
wearable - Set up a debugging session for a Android Wear device
mem - Print memory info
stats - Print process statistics (starting with Android 4.4)
broadcast - Broadcast action
battery - Broadcast new battery status
power - Broadcast new power status
screencap - Make a screen capture and fetch image file
screenrecord - Record screen and fetch video file
services - Dump services of given package
latest_target - Echo latest target identifier
update - Update existing sources with a build.xml file
create - Create a new android project
view - Start intent to view given data
apk - Get APK from a device
help - Print help

Type

$ and help view

and you'll see the available parameters:

view - Start intent to view given data
    1 - data
#!/usr/bin/env bash
# Parse manifest for given patterns and print first argument value
#
# @param ... - patterns to find in order
manifest()
{
while read -r
do
for (( ;; ))
do
case $REPLY in
*$1*)
REPLY=${REPLY##*$1}
shift
(( $# > 0 )) && continue
REPLY=${REPLY%%\"*}
echo "${REPLY#.}"
return
;;
esac
break
done
done < AndroidManifest.xml
}
# Print package
package()
{
manifest 'package=\"'
}
# Print first activity
activity()
{
manifest '<activity' 'android:name=\"'
}
# Clean builds & resources
clean()
{
ant clean
}
# Build
#
# @param ... - additional build arguments
build()
{
ant "${TARGET:-debug}" "$@"
}
# Build & install
install()
{
build install
}
# Uninstall package
#
# @param ... - package name (optional)
uninstall()
{
adb uninstall "${@:-$(package)}"
}
# Stress test given application
#
# @param 1 - number of pseudo-random events to send (optional)
# @param 2 - package name of application to test (optional)
stress()
{
adb shell monkey -p "${2:-$(package)}" -v "${1:-1000}"
}
# Start given activity
#
# @param 1 - full package and activity name (optional)
start()
{
adb shell "am start -n ${1:-$(package)/.$(activity)}"
}
# Build, install & run
run()
{
local PACKAGE
PACKAGE=$(package) &&
[ "$PACKAGE" ] &&
install &&
start "${PACKAGE}/.$(activity)"
}
# Run release, needs key.store & key.name to be set in ant.properties
release()
{
TARGET=release "${@:-run}"
}
# Run debug
debug()
{
TARGET=debug "${@:-run}"
}
# List available emulators or only the requested one
#
# @param 1 - index of emulator to echo (optional)
emus()
{
local AVD N=1 I=${1:-0}
for AVD in ~/.android/avd/*.ini
do
[ -r "$AVD" ] || continue
AVD=${AVD##*/}
AVD=${AVD%.ini}
if (( !I ))
then
printf "%3d %s\n" "$N" "$AVD"
elif (( N == I ))
then
echo "$AVD"
break
fi
(( ++N ))
done
}
# Fire up given (or last used) emulator
#
# @param 1 - name or number of avd (optional)
# @param ... - arguments for emulator (optional)
emu()
{
local AVD=$1
if [ -z "$AVD" ] || (( AVD > 0 )) &>/dev/null
then
AVD=$(emus "${AVD:-1}" | head -n 1)
fi
shift
emulator -avd "${AVD%.avd}" "$@" &
}
# Set up a debugging session for a Android Wear device
wearable()
{
adb forward tcp:4444 localabstract:/adb-hub
adb connect localhost:4444
}
# Print memory info
#
# @param 1 - package name (optional)
mem()
{
adb shell dumpsys meminfo "${1:-$(package)}"
}
# Print process statistics (starting with Android 4.4)
#
# @param 1 - package name (optional)
stats()
{
adb shell dumpsys procstats "${1:-$(package)}"
}
# Broadcast action
#
# @param 1 - full action name
broadcast()
{
adb shell am broadcast -a "$1"
}
# Broadcast new battery status
#
# @param 1 - "low" or "okay"
battery()
{
broadcast "android.intent.action.BATTERY_$(echo "$1" |
tr '[:lower:]' '[:upper:]')"
}
# Broadcast new power status
#
# @param 1 - "connected" or "disconnected"
power()
{
broadcast "android.intent.action.ACTION_POWER_$(echo "$1" |
tr '[:lower:]' '[:upper:]')"
}
# Make a screen capture and fetch image file
#
# @param 1 - file name of output image (optional)
screencap()
{
local FILE
FILE="/sdcard/${1:-screencap-$(date +%Y%m%d%H%M%S).png}"
adb shell screencap -p "$FILE" &&
adb pull "$FILE" &&
adb shell rm "$FILE"
}
# Record screen and fetch video file
#
# @param 1 - file name of output video (optional)
# @param 2 - wait time in seconds before pull (optional)
screenrecord()
{
local FILE
FILE="/sdcard/${1:-screenrecord-$(date +%Y%m%d%H%M%S).mp4}"
fetch_screenrecord()
{
echo "Fetching $FILE"
sleep "${2:-1}"
adb pull "$FILE" && adb shell rm "$FILE"
}
echo 'Press Ctrl+C to stop recording'
trap fetch_screenrecord INT
adb shell screenrecord --verbose "$FILE"
trap - INT
unset fetch_screenrecord
}
# Dump services of given package
#
# @param 1 - package name (optional)
services()
{
local PACKAGE FOUND=''
PACKAGE=${1:-$(package)}
adb shell dumpsys activity services | while read -r
do
if [ $FOUND ]
then
case "$REPLY" in
' *'*)
FOUND=
;;
*)
echo "$REPLY"
;;
esac
else
case "$REPLY" in
*$PACKAGE*)
echo "$REPLY"
FOUND=1
;;
esac
fi
done
}
# Echo latest target identifier
latest_target()
{
android list target -c | grep android | tail -n 1
}
# Update existing sources with a build.xml file
update()
{
[ -r project.properties ] ||
if [ -r default.properties ]
then
mv default.properties project.properties
else
cat <<EOF > project.properties
target=$(latest_target)
EOF
fi
android update project --path . -s
}
# Create a new android project
#
# @param 1 - full namespace with default activity
# @param 2 - SDK target version (optional)
create()
{
local P=${1%.} A=
if (( $# < 1 )) || [[ $P != *.* ]]
then
echo 'error: missing namespace and/or main activity' >&2
return 1
fi
A=${P##*.}
if [[ $A != [A-Z]* ]]
then
A=MainActivity
else
P=${P%.*}
fi
android create project \
--target "${2:-$(latest_target)}" \
--package "$P" \
--activity "$A" \
--path .
}
# Start intent to view given data
#
# @param 1 - data
view()
{
adb shell am start \
-a android.intent.action.VIEW \
-d "${1:-http://www.google.com}"
}
# Get APK from a device
#
# @param 1 - application id
apk()
{
local APK_PATH
APK_PATH=$(adb shell pm path "$1")
APK_PATH=${APK_PATH#*:}
APK_PATH=${APK_PATH%$'\r'}
adb pull "$APK_PATH"
}
# Print help
#
# @param 1 - name of command
help()
{
local DESC='' NAME=''
while read -r
do
case $REPLY in
'')
DESC=
;;
\#\ *)
if [ "$DESC" ]
then
[ "$1" ] && DESC=$DESC${DESC:+$'\n'}$' '${REPLY#*# @param }
else
DESC=${REPLY#*# }
fi
;;
*\(\))
[ "$DESC" ] || continue
NAME=${REPLY%(*}
[ "$1" ] && [ "$NAME" != "$1" ] && continue
echo "$NAME - $DESC"
DESC=
;;
esac
done < "$0"
}
if [ "${BASH_SOURCE[0]}" == "$0" ]
then
"${@:-debug}"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment