From version v0.2.1-dev, the package name has been renamed from 'adb' to 'ppadb' to avoid conflit with Google google/python-adb
This is pure-python implementation of the ADB client.
You can use it to communicate with adb server (not the adb daemon on the device/emulator).
When you use adb command
Now you can use pure-python-adb to connect to adb server as adb command line
This package supports most of the adb command line tool's functionality.
- adb devices
- adb shell
- adb forward
- adb pull/push
- adb install/uninstall
Python 3.6+
$pip install -U pure-python-adbfromppadb.clientimportClientasAdbClient# Default is "127.0.0.1" and 5037client=AdbClient(host="127.0.0.1", port=5037)
print(client.version())
>>>39fromppadb.clientimportClientasAdbClient# Default is "127.0.0.1" and 5037client=AdbClient(host="127.0.0.1", port=5037)
device=client.device("emulator-5554")fromppadb.clientimportClientasAdbClientapk_path="example.apk"# Default is "127.0.0.1" and 5037client=AdbClient(host="127.0.0.1", port=5037)
devices=client.devices()
fordeviceindevices:
device.install(apk_path)
# Check apk is installedfordeviceindevices:
print(device.is_installed("example.package"))
# Uninstallfordeviceindevices:
device.uninstall("example.package")fromppadb.clientimportClientasAdbClient# Default is "127.0.0.1" and 5037client=AdbClient(host="127.0.0.1", port=5037)
device=client.device("emulator-5554")
device.shell("echo hello world !")defdump_logcat(connection):
whileTrue:
data=connection.read(1024)
ifnotdata:
breakprint(data.decode('utf-8'))
connection.close()
fromppadb.clientimportClientasAdbClient# Default is "127.0.0.1" and 5037client=AdbClient(host="127.0.0.1", port=5037)
device=client.device("emulator-5554")
device.shell("logcat", handler=dump_logcat)read logcat line by line
fromppadb.clientimportClientdefdump_logcat_by_line(connect):
file_obj=connect.socket.makefile()
forindexinrange(0, 10):
print("Line {}: {}".format(index, file_obj.readline().strip()))
file_obj.close()
connect.close()
client=Client()
device=client.device("emulator-5554")
device.shell("logcat", handler=dump_logcat_by_line)fromppadb.clientimportClientasAdbClientclient=AdbClient(host="127.0.0.1", port=5037)
device=client.device("emulator-5554")
result=device.screencap()
withopen("screen.png", "wb") asfp:
fp.write(result)fromppadb.clientimportClientasAdbClientclient=AdbClient(host="127.0.0.1", port=5037)
device=client.device("emulator-5554")
device.push("example.apk", "/sdcard/example.apk")fromppadb.clientimportClientasAdbClientclient=AdbClient(host="127.0.0.1", port=5037)
device=client.device("emulator-5554")
device.shell("screencap -p /sdcard/screen.png")
device.pull("/sdcard/screen.png", "screen.png")fromppadb.clientimportClientasAdbClientclient=AdbClient(host="127.0.0.1", port=5037)
client.remote_connect("172.20.0.1", 5555)
device=client.device("172.20.0.1:5555")
# Disconnect all devicesclient.remote_disconnect()
##Disconnect 172.20.0.1# client.remote_disconnect("172.20.0.1")##Or# client.remote_disconnect("172.20.0.1", 5555)logging.getLogger("ppadb").setLevel(logging.DEBUG)importasyncioimportaiofilesfromppadb.client_asyncimportClientAsyncasAdbClientasyncdef_save_screenshot(device):
result=awaitdevice.screencap()
file_name=f"{device.serial}.png"asyncwithaiofiles.open(f"{file_name}", mode='wb') asf:
awaitf.write(result)
returnfile_nameasyncdefmain():
client=AdbClient(host="127.0.0.1", port=5037)
devices=awaitclient.devices()
fordeviceindevices:
print(device.serial)
result=awaitasyncio.gather(*[_save_screenshot(device) fordeviceindevices])
print(result)
asyncio.run(main())- Install Docker
- Install Docker Compose
pip install docker-compose- Modify test/conftest.py
Change the value of adb_host to the "emulator"
adb_host="emulator"- Run testcases
docker-compose upResult
Starting purepythonadb_emulator_1 ... doneRecreating purepythonadb_python_environment_1 ... doneAttaching to purepythonadb_emulator_1, purepythonadb_python_environment_1emulator_1 | + echo nemulator_1 | + /home/user/android-sdk-linux/tools/bin/avdmanager create avd -k system-images;android-25;google_apis;x86 -n Docker -b x86 -g google_apis --device 8 --forceParsing /home/user/android-sdk-linux/emulator/package.xmlParsing /home/user/android-sdk-linux/patcher/v4/package.xmlParsing /home/user/android-sdk-linux/platform-tools/package.xmlParsing /home/user/android-sdk-linux/platforms/android-25/package.xmlParsing /home/user/android-sdk-linux/system-images/android-25/google_apis/x86/package.xmlParsing /home/user/android-sdk-linux/tools/package.xml+ echo hw.keyboard = trueemulator_1 | + adb start-serveremulator_1 | * daemon not running; starting now at tcp:5037python_environment_1 | ============================= test session starts ==============================python_environment_1 | platform linux -- Python 3.6.1, pytest-3.6.3, py-1.5.4, pluggy-0.6.0python_environment_1 | rootdir: /code, inifile:python_environment_1 | collected 27 itemspython_environment_1 |emulator_1 | * daemon started successfullyemulator_1 | + exec /usr/bin/supervisordemulator_1 | /usr/lib/python2.7/dist-packages/supervisor/options.py:298: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.emulator_1 | 'Supervisord is running as root and it is searching 'emulator_1 | 2018-07-07 17:19:47,560 CRIT Supervisor running as root (no user in config file)emulator_1 | 2018-07-07 17:19:47,560 INFO Included extra file "/etc/supervisor/conf.d/supervisord.conf" during parsingemulator_1 | 2018-07-07 17:19:47,570 INFO RPC interface 'supervisor' initializedemulator_1 | 2018-07-07 17:19:47,570 CRIT Server 'unix_http_server' running without any HTTP authentication checkingemulator_1 | 2018-07-07 17:19:47,570 INFO supervisord started with pid 1emulator_1 | 2018-07-07 17:19:48,573 INFO spawned: 'socat-5554' with pid 74emulator_1 | 2018-07-07 17:19:48,574 INFO spawned: 'socat-5555' with pid 75emulator_1 | 2018-07-07 17:19:48,576 INFO spawned: 'socat-5037' with pid 76emulator_1 | 2018-07-07 17:19:48,578 INFO spawned: 'novnc' with pid 77emulator_1 | 2018-07-07 17:19:48,579 INFO spawned: 'socat-9008' with pid 78emulator_1 | 2018-07-07 17:19:48,582 INFO spawned: 'emulator' with pid 80emulator_1 | 2018-07-07 17:19:49,607 INFO success: socat-5554 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)emulator_1 | 2018-07-07 17:19:49,607 INFO success: socat-5555 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)emulator_1 | 2018-07-07 17:19:49,607 INFO success: socat-5037 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)emulator_1 | 2018-07-07 17:19:49,607 INFO success: novnc entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)emulator_1 | 2018-07-07 17:19:49,608 INFO success: socat-9008 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)emulator_1 | 2018-07-07 17:19:49,608 INFO success: emulator entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)python_environment_1 | test/test_device.py .............. [ 51%]python_environment_1 | test/test_host.py .. [ 59%]python_environment_1 | test/test_host_serial.py ........ [ 88%]python_environment_1 | test/test_plugins.py ... [100%]python_environment_1 |python_environment_1 | ------------------ generated xml file: /code/test_result.xml -------------------python_environment_1 | ========================= 27 passed in 119.15 seconds ==========================purepythonadb_python_environment_1 exited with code 0Aborting on container exit...Stopping purepythonadb_emulator_1 ... done
