Master Python + ADB: Build Multi‑Device Automation Scripts for Android Apps

This tutorial explains how to use Python and ADB to create a group‑control script that connects multiple Android devices, extracts package information, launches apps, performs UI actions via YAML, and cleans up, providing a practical foundation for mobile automation testing.

Python Crawling & Data Mining
Python Crawling & Data Mining
Python Crawling & Data Mining
Master Python + ADB: Build Multi‑Device Automation Scripts for Android Apps

1. Introduction

Group control—controlling several Android devices from a single computer—is common in automation testing. This article shows how to write a Python‑ADB script to automate tasks across multiple devices.

2. Preparation

Install the Android development environment, ensure adb is added to the system PATH, and connect the devices via USB or a hub. Verify the connections with:

# Below shows three connected devices
xag:Test xingag$ adb devices
List of devices attached
822QEDTL225T7    device
ca2b3455        device
DE45d9323SE96   device

3. Practical Example

Using the Xianyu app as a case study, the automation consists of seven steps: obtain the package name and launch activity, list online devices, start the app on each device, perform UI actions defined in a YAML file, and finally stop the app.

Step 1 – Get package name and launch activity

# Get current running app package and initial Activity
adb shell dumpsys activity | grep -i run

Run the command on the device; the output displays the package and activity.

Step 2 – Get all online devices

# All device IDs
device_ids = []

def get_online_devices(self):
    """Retrieve all online devices"""
    global device_ids
    try:
        for line in exec_cmd("adb devices"):
            # Skip the first line and offline entries
            if "device" in line:
                device_ids.append(line.split("\t")[0])
        device_ids = device_ids[1:]
    except Exception as e:
        print(e)
    # Return connected devices and count
    return device_ids

Step 3 – Launch the target app on each device

def start_app(self):
    """Open the app on all devices"""
    for device in device_ids:
        os.popen("adb -s " + device + " shell am start -W {}/{}".format(self.packageName, self.home_activity))
    print('Waiting for loading...')
    sleep(10)

Step 4 – Save UI hierarchy locally

def save_ui_tree_to_local(dName):
    """Dump the current Activity UI tree and pull it locally"""
    exec_cmd("adb -s %s shell uiautomator dump /data/local/tmp/%s.xml" % (dName, dName))
    sleep(2)
    exec_cmd("adb -s %s pull /data/local/tmp/%s.xml ./../" % (dName, dName))

Step 5 – Parse UI XML to obtain element coordinates

def get_element_position(element_id, uidump_name):
    """Parse the UI XML, find the element by id, and return its center coordinates"""
    tree = ET.parse('./../%s.xml' % uidump_name)
    root = tree.getroot()
    result_element = None
    for node in root.findall('.//node'):
        if node.attrib['resource-id'] == element_id:
            result_element = node
            break
    if result_element is None:
        print('Element not found!')
        return None
    coord = re.compile(r"\d+").findall(result_element.attrib['bounds'])
    center = (int((int(coord[0]) + int(coord[2])) / 2), int((int(coord[1]) + int(coord[3])) / 2))
    return center

Step 6 – Execute steps from a YAML file

# steps_adb.yaml

# Package and Activity
package_name:  com.taobao.idlefish
home_activity:  com.taobao.fleamarket.home.activity.InitActivity

# Execution steps
steps:
  - save_ui_tree_to_local:
      method: save_ui_tree_to_local
      args:
  - find_element_and_click:
      id: com.taobao.idlefish:id/tx_id
  - save_ui_tree_to_local:
      method: save_ui_tree_to_local
  - input_content:
      content: Python
  - find_element_and_click:
      id: com.taobao.idlefish:id/search_button

The script reads each step, iterates over all devices, and performs the corresponding action (save UI tree, locate element, click, input text, etc.).

# Execute steps
for step in self.steps:
    for device in device_ids:
        step_name = list(step)[0]
        if step_name == 'save_ui_tree_to_local':
            save_ui_tree_to_local(device)
        elif step_name == 'find_element_and_click':
            element_id = step[step_name]['id']
            pos = get_element_position(element_id, device)
            exec_cmd('adb -s %s shell input tap %s %s' % (device, pos[0], pos[1]))
        elif step_name == 'input_content':
            content = step[step_name]['content']
            exec_cmd('adb -s %s shell input text %s' % (device, content))
        else:
            print('Other operation')

Step 7 – Close the app on all devices

def stop_all(self):
    """Force‑stop the app on every device"""
    for device in device_ids:
        os.popen("adb -s " + device + " shell am force-stop %s" % self.packageName)

4. Conclusion

This article presents the simplest Python‑based group‑control implementation for Android apps; more advanced techniques will be explored in future posts.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PythonUI testingADBmulti-deviceAndroid automation
Python Crawling & Data Mining
Written by

Python Crawling & Data Mining

Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.