How can I adb install an apk to multiple connected devices?

JavaAndroidEclipseAdbAdt

Java Problem Overview


I have 7 devices plugged into my development machine.

Normally I do adb install <path to apk> and can install to just a single device.

Now I would like to install my apk on all of my 7 connected devices. How can I do this in a single command? I'd like to run a script perhaps.

Java Solutions


Solution 1 - Java

You can use adb devices to get a list of connected devices and then run adb -s DEVICE_SERIAL_NUM install... for every device listed.

Something like (bash):

adb devices | tail -n +3 | cut -sf 1 -d " " | xargs -iX adb -s X install ...

Comments suggest this might work better for newer versions:

adb devices | tail -n +2 | cut -sf 1 | xargs -iX adb -s X install ...

For Mac OSX(not tested on Linux):

adb devices | tail -n +2 | cut -sf 1 | xargs -I {} adb -s {} install ...

Solution 2 - Java

The other answers were very useful however didn't quite do what I needed. I thought I'd post my solution (a shell script) in case it provides more clarity for other readers. It installs multiple apks and any mp4s

echo "Installatron"

for SERIAL in $(adb devices | tail -n +2 | cut -sf 1);
do 
  for APKLIST in $(ls *.apk);
  do
  echo "Installatroning $APKLIST on $SERIAL"
  adb -s $SERIAL install $APKLIST
  done

  for MP4LIST in $(ls *.mp4);
  do
  echo "Installatroning $MP4LIST to $SERIAL"
  adb -s $SERIAL push $MP4LIST sdcard/
  done
done

echo "Installatron has left the building"

Thank you for all the other answers that got me to this point.

Solution 3 - Java

Here's a functional one line command tailored from kichik's response (thanks!):

>adb devices | tail -n +2 | cut -sf 1 | xargs -iX adb -s X install -r *.apk

But if you happen to be using Maven it's even simpler:

>mvn android:deploy

Solution 4 - Java

Another short option... I stumbled on this page to learn that the -s $SERIAL has to come before the actual adb command! Thanks stackoverflow!

for SERIAL in $(adb devices | grep -v List | cut -f 1);
do `adb -s $SERIAL install -r /path/to/product.apk`;
done

Solution 5 - Java

Generalized solution from Dave Owens to run any command on all devices:

for SERIAL in $(adb devices | grep -v List | cut -f 1);
do echo adb -s $SERIAL $@;
done

Put it in some script like "adb_all" and use same way as adb for single device.

Another good thing i've found is to fork background processes for each command, and wait for their completion:

for SERIAL in $(adb devices | grep -v List | cut -f 1);
do adb -s $SERIAL $@ &
done

for job in `jobs -p`
do wait $job
done

Then you can easily create a script to install app and start the activity

./adb_all_fork install myApp.apk
./adb_all_fork shell am start -a android.intent.action.MAIN -n my.package.app/.MainActivity

Solution 6 - Java

I liked workingMatt's script but thought it could be improved a bit, here's my modified version:

#!/bin/bash

install_to_device(){
local prettyName=$(adb -s $1 shell getprop ro.product.model)
echo "Starting Installatroning on $prettyName"
for APKLIST in $(find . -name "*.apk" -not -name "*unaligned*");
  do
  echo "Installatroning $APKLIST on $prettyName"
  adb -s $1 install -r $APKLIST
  adb -s $1 shell am start -n com.foo.barr/.FirstActivity;
  adb -s $1 shell input keyevent KEYCODE_WAKEUP
  done
  echo "Finished Installatroning on $prettyName"
}

echo "Installatron"
gradlew assembleProdDebug

for SERIAL in $(adb devices | tail -n +2 | cut -sf 1);
do 
  install_to_device $SERIAL&
done

My version does the same thing except:

  • it finds the apks from the root of the project
  • it installs to every device simultaneously
  • it excludes the "unaligned" versions of the apks (these were just being installed over by the aligned versions anyway
  • it shows the readable names for the phones instead if their device ids

There's a few ways it could still be improved but I'm quite happy with it.

Solution 7 - Java

The following command should work:

$ adb devices | tail -n +2 | head -n -1 | cut -f 1 | xargs -I X adb -s X install -r path/to/your/package.apk

adb devices returns the list of devices. Use tail -n +2 to start from the 2nd line and head -n -1 to remove the last blank line at the end. Piping through cut with the default tab delimiter gets us the first column which are the serials.

xargs is used to run the adb command for each serial. Remove the -r option if you are not re-installing.

Solution 8 - Java

With this script you can just do:

adb+ install <path to apk>

Clean, simple.

Solution 9 - Java

If you don't want use the devices that have not enabled adb; use this

Mac/Linux

adb devices | grep device | grep -v devices | awk '{print$1}' | xargs -I {} adb -s {} install path/to/yourApp.apk 

adb devices | grep device | grep -v devices | cut -sf 1 | xargs -I {} adb -s {} install path/to/yourApp.apk

Solution 10 - Java

Use this command-line utility: adb-foreach

Solution 11 - Java

PowerShell solution

function global:adba() {
    $deviceIds = iex "adb devices" | select -skip 1 |  %{$_.Split([char]0x9)[0].Trim() } | where {$_ -ne "" }
	foreach ($deviceId in $deviceIds) {
    	Echo ("--Executing on device " + $deviceId + ":---")
	    iex ("adb -s $deviceId " + $args)
	}
}

Put this in your profile file (notepad $PROFILE), restart your shell and you can invoke installations with :

adba install yourApp.apk

Solution 12 - Java

This command works perfect adb devices | awk 'NR>1{print $1}' | xargs -n1 -I% adb -s % install foo.apk

Solution 13 - Java

well its simple you can create a installapk.bat file that can do the job for multiple apk to multiple connected devices open installapk.bat with notepad++ and copy paste this code

FOR /F "skip=1"  %%x IN ('adb devices') DO start adb -s %%x install -r Facebook.apk
FOR /F "skip=1"  %%x IN ('adb devices') DO start adb -s %%x install -r Instagram.apk
FOR /F "skip=1"  %%x IN ('adb devices') DO start adb -s %%x install -r Messenger.apk
FOR /F "skip=1"  %%x IN ('adb devices') DO start adb -s %%x install -r Outlook.apk
FOR /F "skip=1"  %%x IN ('adb devices') DO start adb -s %%x install -r Viber.apk
FOR /F "skip=1"  %%x IN ('adb devices') DO start adb -s %%x install -r WhatsApp.apk

Solution 14 - Java

Here is bash for install and run apk on all connected devices

Using

nick@nickolay:/home/workspace/MyProject$ > bash path/to/installAndRunApk.sh

installAndRunApk.sh

#!/usr/bin/env bash
#--------find apk---------
apkFile=$(find -name '*.apk' -print | grep -oP '(?<=.).*(.apk)')

#--------find apkFilePath---------
if test -z "apkFile"
then
echo "apkFile: is NULL"
exit 0;
fi

echo "apkFile: ${apkFile}"
apkFilePath=$(pwd)${apkFile}
echo "apk file path: ${apkFilePath}"

#--------install---------
if test -z "$apkFilePath"
then
echo "apkFilePath: is NULL"
exit 0;
fi

echo "adb install -t -r ${apkFilePath}"
for SERIAL in $(adb devices | grep -v List | cut -f 1);
do `adb -s ${SERIAL} install -t -r ${apkFilePath}`;
done

#--------get applicationId---------
echo "aapt dump badging ${apkFilePath} | grep -oP '(?<=package: name=).*(?=versionCode)'"
applicationId=$(aapt dump badging ${apkFilePath} | grep -oP '(?<=package: name=).*(?=versionCode)')
echo "applicationId: is ${applicationId}"

#--------launch---------
if test -z "$applicationId"
then
echo "applicationId: is NULL"
exit 0;
fi

echo "____________________START_APPLICATION_ID________________________"
echo "applicationId: ${applicationId}"
echo "____________________END_APPLICATION_ID__________________________"
echo "____________________START_LAUNCHER______________________________"
for SERIAL in $(adb devices | grep -v List | cut -f 1);
do `adb -s ${SERIAL} shell monkey -p ${applicationId} -c android.intent.category.LAUNCHER 1`;
done
echo "____________________END_LAUNCHER________________________________"

Solution 15 - Java

I added to the answer from @WorkingMatt

I updated his answer to additionally do the following things

  1. Attempt to connect to all devices on the local network with open port 5555. Warning: this may be a security risk. Beware connecting to arbitrary ports unless you know that it is safe. I am not trained in cybersecurity, so take my advice here with a grain of salt.
  2. Uninstall the previous version of the package if there is one installed (In my case I am uninstalling to remove previous app data)
#!/bin/bash
echo "Installatron2"

# Connect to all devices on the local network (in our case 192.168.0.0)
# This section requires nmap (You may need sudo apt install nmap)
echo "Scanning the network for connected debuggable devices"
ADDRESSES=$(nmap --open -p 5555 192.168.0/24 -oG - | grep "/open" | awk '{ print $2 }')
for ADDRESS in $ADDRESSES;
do
  adb connect $ADDRESS
done

# Print devices connected to
echo "Connected to the following devices"
echo "$(adb devices)"

# Iterate through all apks in current directory
for SERIAL in $(adb devices | tail -n +2 | cut -sf 1);
do
  for APKLIST in $(ls *.apk);
  do
  #Get the package name from the apk file (Needs sudo apt install aapt)
  package=$(aapt dump badging "$APKLIST" | awk '/package/{gsub("name=|'"'"'","");  print $2}')

  # Optionally uninstalls the pre-existing version of this package (In case you do not want to retain data)
  echo "Uninstalling $package on $SERIAL"
  adb uninstall $package

  # Now install with replacement to the same device
  echo "Installatroning $APKLIST on $SERIAL"
  adb -s $SERIAL install -r $APKLIST
  done
done

echo "Installatron2 has left the building"

Solution 16 - Java

With Android Debug Bridge version 1.0.29, try this bash script:

APK=$1

if [ ! -f `which adb` ]; then
    echo 'You need to install the Android SDK before running this script.';
    exit;
fi

if [ ! $APK ]; then
    echo 'Please provide an .apk file to install.'
else
    for d in `adb devices | ack -o '^\S+\t'`; do
        adb -s $d install $APK;
    done
fi

Not sure if it works with earlier versions.

Solution 17 - Java

The key is to launch adb in a separate process (&).

I came up with the following script to simultaneously fire-off installation on all of the connected devices of mine and finally launch installed application on each of them:

#!/bin/sh

function install_job { 
    
    adb -s ${x[0]} install -r PATH_TO_YOUR_APK
    adb -s ${x[0]} shell am start -n "com.example.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER

}


#iterate over devices IP-addresses or serial numbers and start a job 

while read LINE
do
    eval x=($LINE)
    install_job ${x[0]} > /dev/null 2>&1 &
done <<< "`adb devices |  cut -sf 1`"

echo "WATING FOR INSTALLATION PROCESSES TO COMPLETE"
wait

echo "DONE INSTALLING"

Note 1: the STDOUT and STDERR are suppressed. You won't see any "adb install" operation result. This may be improved, I guess, if you really have to

Note 2: you could also improve script by providing args instead of hardcoded path and activity names.

That way you:

  1. Don't have to manually perform install on each device
  2. Don't have to wait for one install to finish in order to execute another one (adb tasks are launched in parallel)

Solution 18 - Java

Originated from here: Make The Previous Post A Mass APK Installer That Does Not Uses ADB Install-Multi Syntax


@echo off

:loop ::-------------------------- has argument ? if ["%~1"]==[""] ( echo done. goto end ) ::-------------------------- argument exist ? if not exist %~s1 ( echo error "%~1" does not exist in file-system. ) else ( echo "%~1" exist if exist %~s1\NUL ( echo "%~1" is a directory ) else ( echo "%~1" is a file! - time to install: call adb install %~s1 ) ) ::-------------------------- shift goto loop

:end

pause

::: ########################################################################## ::: ## ## ::: ## 0. run: adb devices - to start the deamon and list your device ## ::: ## ## ::: ## 1. drag&drop ANY amount of files (APK) over this batch files, ## ::: ## ## ::: ## - it will install them one by one. ## ::: ## - it just checks if file exists. ## ::: ## - it does not checks if it is a valid APK package ## ::: ## - it does not checks if package-already-installed ## ::: ## - if there is an error you can always press [CTRL]+[C] ## ::: ## to stop the script, and continue from the next one, ## ::: ## some other time. ## ::: ## - the file is copied as DOS's 8.3 naming to you ## ::: ## don't need to worry about wrapping file names or renaming ## ::: ## them, just drag&drop them over this batch. ## ::: ## ## ::: ## Elad Karako 1/1/2016 ## ::: ## http://icompile.eladkarako.com ## ::: ##########################################################################

Solution 19 - Java

Since I can't comment on the answer by @Tom, this worked for me on OSX 10.13

adb devices | tail -n +2 | cut -sf 1 | xargs -IX adb -s X install -r path/to/apk.apk

(Change the little i to a big I)

Solution 20 - Java

I was wanting to log what was happening whilst installing, also needed it to be slightly comprehendable. Ended up with:

echo "Installing app on all connected devices."

adb devices | tail -n +2 | cut -sf 1 | xargs -I % sh -c '{ \
    echo "Installing on %"; \
    adb -s % \
        install myApp.apk; \    
; }'

Tested on Linux & Mac

Solution 21 - Java

-Get all the apk stored in .apk folder

-Install and replace app on devices

getBuild() {
    for entry in .apk/*
    do
        echo "$entry"
    done
    return "$entry"
}

newBuild="$(getBuild)"

adb devices | while read line
do
  if [! "$line" = ""] && ['echo $line | awk "{print $2}"' = "device"]
  then
      device='echo $line | awk "{print $1}"'
      echo "adb -s $device install -r $newbuild"
      adb -s $device install -r $newbuild
  fi
done

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSheehan AlamView Question on Stackoverflow
Solution 1 - JavakichikView Answer on Stackoverflow
Solution 2 - JavaWorkingMattView Answer on Stackoverflow
Solution 3 - JavaTomView Answer on Stackoverflow
Solution 4 - JavaDave OwensView Answer on Stackoverflow
Solution 5 - JavaiTakeView Answer on Stackoverflow
Solution 6 - JavaAnkhwatcherView Answer on Stackoverflow
Solution 7 - JavajayView Answer on Stackoverflow
Solution 8 - JavaChristopher PerryView Answer on Stackoverflow
Solution 9 - JavafireashesView Answer on Stackoverflow
Solution 10 - JavaTinyTimZamboniView Answer on Stackoverflow
Solution 11 - JavaNilzorView Answer on Stackoverflow
Solution 12 - JavaSivakumar ChellamuthuView Answer on Stackoverflow
Solution 13 - JavaMohamed Amine AyachiView Answer on Stackoverflow
Solution 14 - JavaNickUnuchekView Answer on Stackoverflow
Solution 15 - JavaScott DriggersView Answer on Stackoverflow
Solution 16 - JavathisgeekView Answer on Stackoverflow
Solution 17 - JavaDrewView Answer on Stackoverflow
Solution 18 - Javauser257319View Answer on Stackoverflow
Solution 19 - JavatehscottView Answer on Stackoverflow
Solution 20 - JavaBlundellView Answer on Stackoverflow
Solution 21 - JavaJean-Dominique TurgeonView Answer on Stackoverflow