Skip to content

Instantly share code, notes, and snippets.

@RussellCollins
Created April 16, 2017 04:18
Show Gist options
  • Save RussellCollins/e2bc551b7ffe40724cf483d12eb1a7b0 to your computer and use it in GitHub Desktop.
Save RussellCollins/e2bc551b7ffe40724cf483d12eb1a7b0 to your computer and use it in GitHub Desktop.
A convenience script for automatically pulling Android builds from a static URL and distributing them to connected devices. Assumes AAPT and adb are in your PATH variable already.
#!/bin/sh
APK_URL="" ###### UPDATE THIS WITH THE URL TO THE ARCHIVED LAST SUCCESSFUL BUILD ARTIFACT ON JENKINS FOR EXAMPLE
FILEPATH=""
## MAKE SURE ADB IS RUNNING ##
adb version
## DEFAULTS ##
LAUNCH_ENABLED="false"
appVersionName=""
appPackageName=""
appVersionCode=""
appLaunchActivity=""
## USAGE ##
usage(){
echo
echo
echo
echo "#################### USAGE ####################"
echo
echo " -i: Install. This uninstalls the current app and carries out an install based on the supplied"
echo " parameters. Valid args include 'new', which will download the latest build, 'saved' which"
echo " will install the current locally saved build, and 'upgrade' which will install over the top of"
echo " the current build using install -r."
echo
echo " -l: Launch app. This launches the app with its first listed launchable-activity"
echo
echo " -h: Help. Displays script usage."
echo
echo "#################### /USAGE ####################"
echo
echo
echo
}
## DEVICEINFO ##
getConnectedDeviceInfo(){
rm -f actiontmpfile.txt
rm -f deviceInfoFile.txt
adb devices | grep device | grep -v attached | cut -f 1 > actiontmpfile.txt
if [ -s actiontmpfile.txt ]; then
while read deviceId;
do
DEVICE_OS_VERSION=`adb -s $deviceId shell getprop ro.build.version.release`
DEVICE_OS_SDK=`adb -s $deviceId shell getprop ro.build.version.sdk`
DEVICE_CARRIER=`adb -s $deviceId shell getprop ro.carrier`
DEVICE_BRAND=`adb -s $deviceId shell getprop ro.product.brand`
DEVICE_MODEL=`adb -s $deviceId shell getprop ro.product.model`
DEVICE_SIM_STATE=`adb -s $deviceId shell getprop gsm.sim.state`
DEVICE_SCREEN_DENSITY=`adb -s $deviceId shell getprop ro.sf.lcd_density`
DEVICE_SCREEN_RES=`adb -s $deviceId shell dumpsys window policy | grep mUnrestrictedScreen | cut -d' ' -f6`
echo "## device - $deviceId ###################" >> deviceInfoFile.txt
echo "Device OS:" >> deviceInfoFile.txt
echo " release version: $DEVICE_OS_VERSION" >> deviceInfoFile.txt
echo " SDK: $DEVICE_OS_SDK" >> deviceInfoFile.txt
echo "Device Build:" >> deviceInfoFile.txt
echo " brand: $DEVICE_BRAND" >> deviceInfoFile.txt
echo " model: $DEVICE_MODEL" >> deviceInfoFile.txt
echo " carrier: $DEVICE_CARRIER" >> deviceInfoFile.txt
echo " GSM SIM state: $DEVICE_SIM_STATE" >> deviceInfoFile.txt
echo "Device Screen:" >> deviceInfoFile.txt
echo " screen density: $DEVICE_SCREEN_DENSITY" >> deviceInfoFile.txt
echo " screen resolution: $DEVICE_SCREEN_RES" >> deviceInfoFile.txt
echo "" >> deviceInfoFile.txt
done < actiontmpfile.txt
else
echo ""
echo "NO attached devices found. Exiting."
echo ""
rm -f actiontmpfile.txt
exit 1
fi
rm actiontmpfile.txt
}
## FILEPATH ##
# looks for APKs in directory.
# if there are none, it offers y/n for downloading a new one.
# if there is one, it outputs the value of that relative filepath
# if there are more than one, it offers to clear them and download/install a new one, or install one from a list by numerical index
getFilePath(){
rm -f ./apklist.txt
ls *.apk > apklist.txt
apkArray=( $( cat ./apklist.txt ) )
arraySize=${#apkArray[@]}
if [ "$arraySize" -lt "1" ]; then
echo ""
echo "Sorry, it looks like you didn't download an APK yet, would you like me to? y/n"
read downloadRequest
case $downloadRequest in
y)
echo ""
echo "You entered 'y' for Yes. Okay, downloading a new one now"
download
FILEPATH=$( ls *.apk )
echo "$FILEPATH"
;;
n)
echo ""
echo "You entered 'n' for No. Well come back when you figure out what you want to do today."
exit 0
;;
*)
echo ""
echo "Seems like you misread. Let's see those instructions again."
usage
exit 0
;;
esac
elif [ "$arraySize" -gt "1" ]; then
echo ""
echo ""
echo "There are $arraySize APKs in this folder."
echo ""
echo "Type 'list' to choose from these or 'new' to delete them and download a new one."
read handleMultiples
case $handleMultiples in
new)
echo ""
echo "You entered 'new'. Let's clear the slate and grab a fresh APK."
rm -f ./*.apk
download
FILEPATH=$( ls *.apk )
;;
list)
echo ""
echo "You entered 'list'. Let's pick from among your existing files."
arrayIndex="0"
echo "### These are your choices. Enter the index for the desired APK. ###"
for i in "${apkArray[@]}"
do
versionName=$( getVersionName "$i" )
versionCode=$( getVersionCode "$i" )
echo " [$arrayIndex] - $i - versionName: $versionName - versionCode: $versionCode"
arrayIndex=$(( arrayIndex+=1 ))
done
read inputIndex
if [ "$inputIndex" -gt $(( arraySize-1 )) ]; then
echo ""
echo "Your selection of index '$inputIndex' exceeded the bounds of the array size $arraySize."
exit 0
elif [ "$inputIndex" -lt "$arraySize" ]; then
FILEPATH=${apkArray[$inputIndex]}
echo ""
echo "You selected $FILEPATH at index $inputIndex"
else
echo ""
echo "your input of '$inputIndex' was invalid."
usage
exit 0
fi
;;
*)
echo ""
echo "Seems like you misread. Let's see those instructions again."
usage
exit 0
;;
esac
elif [ "$arraySize" -eq "1" ]; then
FILEPATH=${apkArray[0]}
else
echo ""
echo "Something went horribly wrong with getFilePath() in this script."
exit 1
fi
}
## VERSIONNAME ##
getVersionName(){ # takes $FILEPATH as a parameter and gets versionName by dumping the apk badging
appVersionName=`aapt dump badging $1 | grep package | awk '{print $4}' | sed s/versionName=//g | sed s/\'//g`
}
## PACKAGENAME ##
getPackageName(){ # takes $FILEPATH as a parameter and gets packageName by dumping the apk badging
appPackageName=`aapt dump badging $1 | grep package | awk '{print $2}' | sed s/name=//g | sed s/\'//g`
}
## VERSIONCODE ##
getVersionCode(){ # takes $FILEPATH as a parameter and gets versionCode by dumping the apk badging
appVersionCode=`aapt dump badging $1 | grep package | awk '{print $3}' | sed s/versionCode=//g | sed s/\'//g`
}
## LAUNCHABLEACTIVITY ##
getLaunchActivity(){ # takes $FILEPATH as a parameter and gets launchable-activity by dumping the apk badging
appLaunchActivity=`aapt dump badging $1 | grep launchable-activity | awk '{print $2}' | sed s/name=//g | sed s/\'//g`
}
## INSTALL ##
installApp(){ # where the first parameter is the $FILEPATH and the second is the $deviceId. Uninstall always happens first.
echo "Uninstalling $appPackageName from $2"
adb -s $2 uninstall $appPackageName
echo "Installing $1 on $2"
adb -s $2 install $1
}
## UPGRADE ##
upgradeApp(){ # where the first parameter is the $FILEPATH and the second is the $deviceId.
echo "upgradeApp called with params $1 and $2..."
adb -s $2 install -r $i
}
## DOWNLOAD ##
download(){
#### Using --insecure option because the old Jenkins instance which is currently handling builds has a bad SSL cert ####
echo "## Downloading using $APK_URL ##"
curl -O --insecure $APK_URL
}
## LAUNCH ##
launch(){
LAUNCH_ENABLED=$1
rm -f launchConfig.txt
if [[ "$LAUNCH_ENABLED" = "true" ]] ; then
LAUNCH_CONFIG="shell am start -n $appPackageName/$appLaunchActivity -f 0x14000000"
echo $LAUNCH_CONFIG > launchConfig.txt
adb devices | grep device | grep -v attached | cut -f 1 > launchtmpfile
while read deviceId;
do
echo "My launch config is: $LAUNCH_CONFIG"
adb -s $deviceId $LAUNCH_CONFIG
done < launchtmpfile
rm launchtmpfile
fi
}
## ACTION ##
installAction(){
#I've separated these checks in case I want to do anything differently with upgrade paths in the future
if [[ "$1" = "install_new" ]] ; then
echo "Clearing all local APKs and downloading a new one"
rm -f ./*.apk
download
elif [[ "$1" = "upgrade" ]] ; then
echo "Clearing all local APKs and downloading a new one"
rm -f ./*.apk
download
else # call getVersionName directly since we're not sure whether the file has been updated manually
getFilePath
getVersionName $FILEPATH
fi
#identify app to install
getFilePath
#set app variables
getVersionName $FILEPATH
getVersionCode $FILEPATH
getPackageName $FILEPATH
getLaunchActivity $FILEPATH
adb devices | grep device | grep -v attached | cut -f 1 > actiontmpfile
while read deviceId;
do
case $1 in
install_new)
echo "installAction $1"
installApp $FILEPATH $deviceId
;;
reinstall) #identical to install_new for now because download logic is handled elsewhere
echo "installAction $1"
installApp $FILEPATH $deviceId
;;
upgrade) #for cases where you wish to upgrade the app without nuking app data
echo "installAction $1"
upgradeApp $FILEPATH $deviceId
;;
esac
done < actiontmpfile
rm actiontmpfile
}
########################################################################
########################## MAIN FUNCTIONALITY ##########################
# Start by gathering information about the connected devices
getConnectedDeviceInfo
# Default behavior - If no arguments are provided the script will uninstall and reinstall
# the app at the hardcoded $FILEPATH values without launching it afterwards
if (( $# < 1 )) ; then
installAction reinstall
fi
# Set option index to 1
OPTIND=1
while getopts "hli:" VALUE "$@" ; do
if [ "$VALUE" = "h" ] ; then
usage
exit 0
fi
if [ "$VALUE" = "l" ] ; then
LAUNCH_ENABLED="true"
fi
if [ "$VALUE" = "i" ] ; then
case $OPTARG in
new)
echo "user wants to install the newest build"
ACTION="install_new"
;;
saved)
echo "user wants to reinstall without a download"
ACTION="reinstall"
;;
upgrade)
echo "user wants to upgrade the current installation"
ACTION="upgrade"
;;
*)
echo "invalid -i parameter"
usage
exit 1
;;
esac
fi
if [ "$VALUE" = "?" ] ; then
usage
exit 1
fi
if [ "$VALUE" = ":" ] ; then
usage
exit 1
fi
done
## call installAction after gathering inputs
installAction $ACTION
## call launch after gathering inputs and installs complete
launch $LAUNCH_ENABLED
########################################################################
########################## JIRA FUNCTIONALITY ##########################
## JIRA new bug template output
rm -f jira_new_bug_template.txt
echo "Collecting build, device, and launch info for JIRA template."
echo ""
echo "h1. Issue" >> jira_new_bug_template.txt
echo "<< enter your description of the nature of the issue here >>" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "h1. Impact" >> jira_new_bug_template.txt
echo "<< enter your description of the impact of this issue on the users here >>" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "h1. Repro Steps" >> jira_new_bug_template.txt
echo "# enter your.." >> jira_new_bug_template.txt
echo "# steps to reproduce.." >> jira_new_bug_template.txt
echo "# the issue as observed here." >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "h1. App Details" >> jira_new_bug_template.txt
echo "* Source: $APK_URL" >> jira_new_bug_template.txt
echo "* File: $FILEPATH" >> jira_new_bug_template.txt
echo "* Release Version: $appVersionName" >> jira_new_bug_template.txt
echo "* Build Number/versionCode: $appVersionCode" >> jira_new_bug_template.txt
echo "* Launched Activity: $appLaunchActivity" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "h1. Device(s)" >> jira_new_bug_template.txt
echo "{noformat}" >> jira_new_bug_template.txt
cat deviceInfoFile.txt >> jira_new_bug_template.txt
echo "{noformat}" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "" >> jira_new_bug_template.txt
echo "h1. LogCat Snippet" >> jira_new_bug_template.txt
echo "{noformat}" >> jira_new_bug_template.txt
echo "replace this text with a copy of the relevant lines from the device(s) LogCat output" >> jira_new_bug_template.txt
echo "{noformat}" >> jira_new_bug_template.txt
## JIRA close bug template output
rm -f jira_close_bug_template.txt
echo ""
echo "h1. Scope of Work Tested" >> jira_close_bug_template.txt
echo "<< enter your description of the scope of work tested here >>" >> jira_close_bug_template.txt
echo "" >> jira_close_bug_template.txt
echo "" >> jira_close_bug_template.txt
echo "h1. Validation Steps" >> jira_close_bug_template.txt
echo "# enter your.." >> jira_close_bug_template.txt
echo "# steps to validate.." >> jira_close_bug_template.txt
echo "# the fix as tested here." >> jira_close_bug_template.txt
echo "" >> jira_close_bug_template.txt
echo "" >> jira_close_bug_template.txt
echo "h1. App Details" >> jira_close_bug_template.txt
echo "* Source: $APK_URL" >> jira_close_bug_template.txt
echo "* File: $FILEPATH" >> jira_close_bug_template.txt
echo "* Release Version: $appVersionName" >> jira_close_bug_template.txt
echo "* Build Number/versionCode: $appVersionCode" >> jira_close_bug_template.txt
echo "* Launched Activity: $appLaunchActivity" >> jira_close_bug_template.txt
echo "" >> jira_close_bug_template.txt
echo "" >> jira_close_bug_template.txt
echo "h1. Device(s)" >> jira_close_bug_template.txt
echo "{noformat}" >> jira_close_bug_template.txt
cat deviceInfoFile.txt >> jira_close_bug_template.txt
echo "{noformat}" >> jira_close_bug_template.txt
@RussellCollins
Copy link
Author

Looks like I borked the formatting when I uploaded it. I think all my tabbing is off now. Sorry about that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment