pure-python-adb

repository·master·Indexed 20 days ago

https://github.com/swind/pure-python-adb

A pure-Python implementation of the ADB (Android Debug Bridge) client that allows developers to communicate with an ADB server to manage Android devices, execute shell commands, and transfer files without requiring the official ADB binary. It provides classes for client connectivity, host-level server management, and device-specific operations including APK installation, screencaps, and port forwarding.

Tokens
4.8K
Snippets
29
Records
29
Agent score
69%

What's inside pure-python-adb

  1. Install pure-python-adb

    master

    Install the pure-python-adb package using pip. Note that the package was renamed from adb to ppadb starting from version v0.2.1-dev to avoid conflicts with Google's python-adb.

    Requirements:

    • Python 3.6+
    $pip install -U pure-python-adb
  2. Manage the ADB server with the Host class

    master

    The Host class allows you to interact with the ADB server itself (host-level commands) rather than specific connected devices. You can use it to check the server version, list connected devices, manage port forwarding, and control the server lifecycle.

    Common host-level operations include:

    • Checking version: Get the ADB server version.
    • Listing devices: Retrieve a list of connected devices, optionally filtered by their state.
    • Managing connections: Connect to or disconnect from remote ADB hosts.
    • Server control: Kill the ADB server or clear all forwardings.
    from ppadb.command.host import Host
    
    # Assuming a connection is established
    host = Host()
    print(f"ADB Version: {host.version()}")
  3. Manage APK installation on devices

    master

    You can install, check, and uninstall APKs on devices using the device object.

    from ppadb.client import Client as AdbClient
    
    apk_path = "example.apk"
    client = AdbClient(host="127.0.0.1", port=5037)
    devices = client.devices()
    
    # Install on all devices
    for device in devices:
        device.install(apk_path)
    
    # Check if package is installed
    for device in devices:
        print(device.is_installed("example.package"))
    
    # Uninstall package
    for device in devices:
        device.uninstall("example.package")
    from ppadb.client import Client as AdbClient
    
    apk_path = "example.apk"
    client = AdbClient(host="127.0.0.1", port=5037)
    devices = client.devices()
    
    for device in devices:
        device.install(apk_path)
    
    for device in devices:
        print(device.is_installed("example.package"))
    
    for device in devices:
        device.uninstall("example.package")
  4. Execute shell commands and handle logcat

    master

    Execute commands via device.shell(). For streaming output like logcat, provide a handler function.

    Basic shell command

    device.shell("echo hello world !")

    Streaming logcat with a handler

    def dump_logcat(connection):
        while True:
            data = connection.read(1024)
            if not data:
                break
            print(data.decode('utf-8'))
        connection.close()
    
    device.shell("logcat", handler=dump_logcat)

    Reading logcat line by line

    def dump_logcat_by_line(connect):
        file_obj = connect.socket.makefile()
        for index in range(0, 10):
            print("Line {}: {}".format(index, file_obj.readline().strip()))
        file_obj.close()
        connect.close()
    
    device.shell("logcat", handler=dump_logcat_by_line)
  5. Connect to the ADB server and manage devices

    master

    Use ppadb.client.Client to connect to an ADB server. By default, it attempts to connect to 127.0.0.1 on port 5037.

    Get ADB version

    from ppadb.client import Client as AdbClient
    client = AdbClient(host="127.0.0.1", port=5037)
    print(client.version())

    Connect to a specific device

    from ppadb.client import Client as AdbClient
    client = AdbClient(host="127.0.0.1", port=5037)
    device = client.device("emulator-5554")

    List all connected devices

    from ppadb.client import Client as AdbClient
    client = AdbClient(host="127.0.0.1", port=5037)
    devices = client.devices()
  6. Use the Async Client for asynchronous operations

    master

    For asyncio compatible workflows, use ppadb.client_async.ClientAsync.

    import asyncio
    import aiofiles
    from ppadb.client_async import ClientAsync as AdbClient
    
    async def _save_screenshot(device):
        result = await device.screencap()
        file_name = f"{device.serial}.png"
        async with aiofiles.open(f"{file_name}", mode='wb') as f:
            await f.write(result)
        return file_name
    
    async def main():
        client = AdbClient(host="127.0.0.1", port=5037)
        devices = await client.devices()
        for device in devices:
            print(device.serial)
    
        result = await asyncio.gather(*[_save_screenshot(device) for device in devices])
        print(result)
    
    asyncio.run(main())
    from ppadb.client_async import ClientAsync as AdbClient
  7. Remote device connection and disconnection

    master

    Connect to a device via its IP address and port using remote_connect.

    from ppadb.client import Client as AdbClient
    client = AdbClient(host="127.0.0.1", port=5037)
    
    # Connect to a remote device
    client.remote_connect("172.20.0.1", 5555)
    device = client.device("172.20.0.1:5555")
    
    # Disconnect all devices
    client.remote_disconnect()
    
    # Disconnect a specific device (IP and port)
    # client.remote_disconnect("172.20.0.1", 5555)
    client.remote_connect("172.20.0.1", 5555)
  8. Take screenshots, push, and pull files

    master

    Take a screenshot

    device.screencap() returns the screenshot data as bytes.

    result = device.screencap()
    with open("screen.png", "wb") as fp:
        fp.write(result)

    Push a file to the device

    device.push("example.apk", "/sdcard/example.apk")

    Pull a file from the device

    device.pull("/sdcard/screen.png", "screen.png")
  9. Execute shell commands with Transport.shell()

    master

    Use the shell() method to execute a command on the device via the shell. If a handler function is provided, it will be called with the connection object; otherwise, the method returns the decoded UTF-8 string of the command's output.

    # Basic usage returning output as a string
    output = transport_instance.shell("ls /sdcard")
    
    # Usage with a custom handler for stream processing
    def my_handler(conn):
        # process connection directly
        pass
    
    transport_instance.shell("ls /sdcard", handler=my_handler)
  10. Connect to and disconnect from remote hosts using Host

    master

    Use these methods to manage connections to remote ADB servers over the network.

    • remote_connect(host, port): Attempts to connect to a remote ADB server at the specified host and port. Returns True if successful.
    • remote_disconnect(host=None, port=None): Disconnects from a specific remote host and port. If no arguments are provided, it performs a general disconnect.
    from ppadb.command.host import Host
    
    host = Host()
    
    # Connect to a remote server
    if host.remote_connect("192.168.1.50", 5555):
        print("Connected to remote host")
    
    # Disconnect from the remote server
    host.remote_disconnect("192.168.1.50", 5555)
  11. Control device power and system state

    master

    Perform system-level operations using the following methods:

    • reboot(): Reboots the device. Returns True on success.
    • remount(): Remounts the file system as read-write. Returns True on success.
    • root(): Attempts to restart adbd as root. Returns True if successful, otherwise raises RuntimeError.
    • wait_boot_complete(timeout=60, timedelta=1): Blocks until the device has finished booting (checks sys.boot_completed).
      • timeout: Maximum seconds to wait (default 60).
      • timedelta: Seconds to sleep between checks (default 1).
    # Wait for device to boot
    transport_instance.wait_boot_complete(timeout=120)
    
    # Attempt to get root access
    transport_instance.root()
    
    # Reboot the device
    transport_instance.reboot()
  12. Manage device data with Transport.clear()

    master

    Clears all data for a specific package on the device. This method uses pm clear <package>.

    Returns True if the operation was successful. If the operation fails, it raises a ppadb.ClearError containing the error message from the device.

    try:
        transport_instance.clear("com.example.app")
    except ClearError as e:
        print(f"Failed to clear package: {e}")