adbutils-async


Nameadbutils-async JSON
Version 0.0.4 PyPI version JSON
download
home_pagehttps://github.com/touxiaoling/adbutils_async
SummaryPython adb async library for adb service.
upload_time2024-04-03 09:08:23
maintainerNone
docs_urlNone
authortomin
requires_python>=3.10
licenseMIT License Copyright (c) 2019 openatx Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords adb adbutils async
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # adbutils_async
[![PyPI](https://img.shields.io/pypi/v/adbutils_async.svg?color=blue)](https://pypi.org/project/adbutils_async/#history)

Python adb async library for adb service (Only support Python3.10+)

fork from [adbutils](https://github.com/openatx/adbutils)

**Table of Contents**

<!--ts-->
   * [adbutils_async](#adbutils_async)
   * [Install](#install)
   * [Usage](#usage)
      * [Connect ADB Server](#connect-adb-server)
      * [List all the devices and get device object](#list-all-the-devices-and-get-device-object)
      * [Connect remote device](#connect-remote-device)
      * [adb forward and adb reverse](#adb-forward-and-adb-reverse)
      * [Create socket connection to the device](#create-socket-connection-to-the-device)
      * [Run shell command](#run-shell-command)
      * [Transfer files](#transfer-files)
      * [Extended Functions](#extended-functions)
      * [Run in command line 命令行使用](#run-in-command-line-命令行使用)
         * [Environment variables](#environment-variables)
         * [Color Logcat](#color-logcat)
      * [Experiment](#experiment)
      * [Examples](#examples)
   * [Develop](#develop)
      * [Watch adb socket data](#watch-adb-socket-data)
   * [Thanks](#thanks)
   * [Ref](#ref)
   * [LICENSE](#license)

<!-- Added by: shengxiang, at: 2021年 3月26日 星期五 15时05分04秒 CST -->

<!--te-->

# Install
```
pip3 install adbutils-async
```

# Usage
Example

## Connect ADB Server
```python
import asyncio
import adbutils_async
async def main()
    adb = await adbutils_async.AdbClient(host="127.0.0.1", port=5037)
    for info in await adb.list():
        print(info.serial, info.state)
        # <serial> <device|offline>

    # only list state=device
    print(await adb.device_list())

    # Set socket timeout to 10 (default None)
    adb = await adbutils_async.AdbClient(host="127.0.0.1", port=5037, socket_timeout=10)
    print(await adb.device_list())
if __name__ == "__main__":
    asyncio.run(main())
```

The above code can be short to `from adbutils_async import adb`

## List all the devices and get device object
```python
import asyncio
from adbutils_async import adb

async def main()
    for d in await adb.device_list():
        print(d.serial) # print device serial

    d = await adb.device(serial="33ff22xx")

    # or
    d = await adb.device(transport_id=24) # transport_id can be found in: adb devices -l

    # You do not need to offer serial if only one device connected
    # RuntimeError will be raised if multi device connected
    d = await adb.device()
if __name__ == "__main__":
    asyncio.run(main())
```

The following code will not write `from adbutils import adb` for short

## Connect or disconnect remote device
Same as command `adb connect`

```python
output = await adb.connect("127.0.0.1:5555")
print(output)
# output: already connected to 127.0.0.1:5555

# connect with timeout
try:
    await adb.connect("127.0.0.1:5555", timeout=3.0)
except AdbTimeout as e:
    print(e)

await adb.disconnect("127.0.0.1:5555")
await adb.disconnect("127.0.0.1:5555", raise_error=True) # if device is not present, AdbError will raise

# wait-for-device
await adb.wait_for("127.0.0.1:5555", state="device") # wait for device online, state default value is "device"
await adb.wait_for("127.0.0.1:5555", state="disconnect") # wait device disconnect
```

## adb forward and adb reverse
Same as `adb forward --list` and `adb reverse --list`

```python
# list all forwards
for item in await adb.forward_list():
    print(item.serial, item.local, item.remote)
    # 8d1f93be tcp:10603 tcp:7912
    # 12345678 tcp:10664 tcp:7912

# list only one device forwards
for item in await adb.forward_list("8d1f93be"):
    print(item.serial, item.local, item.remote)
    # 8d1f93be tcp:10603 tcp:7912
    # 12345678 tcp:10664 tcp:7912


for item in await adb.reverse_list():
    print(item.serial, item.local, item.remote)

# 监控设备连接 track-devices
for event in await adb.track_devices():
    print(event.present, event.serial, event.status)

## When plugin two device, output
# True WWUDU16C22003963 device
# True bf755cab device
# False bf755cab absent

# When adb-server killed, AdbError will be raised
```

## Create socket connection to the device

For example

```python
# minitouch: https://github.com/openstf/minitouch
c = await d.create_connection("unix", "minitouch")
print(await c.recv(500))
await c.close()
```

```python
c = await d.create_connection("tcp", 7912) # the second argument must be int
await c.send(b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
print(await c.recv(500))
await c.close()
```

```python
# read device file
async with d.create_connection(adbutils.Network.DEV, "/data/local/tmp/hello.txt") as c:
    print(await c.recv(500))
```

There are many other usage, see [SERVICES.TXT](https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/SERVICES.TXT;l=175) for more details

Thanks for Pull Request from [@hfutxqd](https://github.com/openatx/adbutils/pull/27)

## Run shell command
I assume there is only one device connected.

```python
import io
import asyncio
from adbutils_async import adb

async def main():
    d = await adb.device()

    print(await d.serial) # 获取序列号

    # Argument support list, str
    serial = await d.shell(["getprop", "ro.serial"]) # 获取Prop信息

    # Same as
    serial = await d.shell("getprop ro.serial")

    # Set timeout for shell command
    await d.shell("sleep 1", timeout=0.5) # Should raise adbutils.AdbTimeout

    # The advanced shell (returncode archieved by add command suffix: ;echo EXIT:$?)
    ret = await d.shell2("echo 1")
    print(ret)
    # expect: ShellReturn(args='echo 1', returncode=0, output='1\n')

    # show property, also based on d.shell
    print(d.prop.name) # output example: surabaya
    d.prop.model
    d.prop.device
    d.prop.get("ro.product.model")
    d.prop.get("ro.product.model", cache=True) # a little faster, use cache data first

    await d.get_serialno() # same as adb get-serialno
    await d.get_devpath() # same as adb get-devpath
    await d.get_state() # same as adb get-state
if __name__ == "__main__":
    asyncio.run(main())
```

Take screenshot

```bash
# adb exec-out screencap -p p.png
png_data = await d.shell("screencap -p", encoding=None)
pathlib.Path("p.png").write_bytes(png_data)
```

## Transfer files
```python
await d.sync.push(b"Hello Android", "/data/local/tmp/hi.txt") # 推送二进制文本
await d.sync.push(io.BytesIO(b"Hello Android"), "/data/local/tmp/hi.txt") # 推送可读对象Readable object
await d.sync.push("/tmp/hi.txt", "/data/local/tmp/hi.txt") # 推送本地文件
await d.sync.push(pathlib.Path("/tmp/hi.txt"), "/data/local/tmp/hi.txt") # 推送本地文件

# 读取文件
async for chunk in d.sync.iter_content("/data/local/tmp/hi.txt"):
    print("Chunk", chunk)

await d.sync.push(b"Hello world", "/data/local/tmp/hi.txt")
output = await d.sync.read_text("/data/local/tmp/hi.txt", encoding="utf-8")
# Expect output: "Hello world"
output = await d.sync.read_bytes("/data/local/tmp/hi.txt")
# Expect output: b"Hello world"

# 拷贝到本地
await d.sync.pull("/data/local/tmp/hi.txt", "hi.txt")

# 获取包的信息
info = await  d.package_info("com.example.demo")
if info:
    print(info) 
	# output example:
    # {
	# "version_name": "1.2.3", "version_code": "12", "signature": "0xff132", 
    # "first_install_time": datetime-object, "last_update_time": datetime-object,
    # }
```

## Extended Functions

AdbUtils provided some custom functions for some complex operations.

You can use it like this:

```python
# save screenshot
pilimg = await d.screenshot()
await pilimg.save("screenshot.jpg")

# get current app info
app_info = await d.app_current()
print(app_info.package)
print(app_info.activity)
print(app_info.pid) # might be 0

# install apk
await d.install("apidemo.apk") # use local path
await d.install("http://example.com/apidemo.apk") # install from url
# raise AdbInstallError if something went wrong

# simulate click
await d.click(100, 100)
await d.click(0.5, 0.5) # center, should be float and <= 1.0

# swipe from(10, 10) to(200, 200) 500ms
await d.swipe(10, 10, 200, 200, 0.5)

await d.list_packages()
# example output: ["com.example.hello"]

await d.window_size()
# example output: (1080, 1920)

await d.rotation()
# example output: 1
# other possible valus: 0, 1, 2, 3

await d.package_info("com.github.uiautomator")
# example output: {"version_name": "1.1.7", "version_code": "1007"}

await d.keyevent("HOME")

await d.send_keys("hello world$%^&*") # simulate: adb shell input text "hello%sworld\%\^\&\*"

await d.open_browser("https://www.baidu.com") # 打开百度
# There still too many functions, please see source codes

# check if screen is on
await d.is_screen_on() # 返回屏幕是否亮屏 True or False

# adb root
await d.root()

# adb tcpip <port>
await d.tcpip(5555)
```

Screenrecord (mp4)

```python
await d.start_recording("video.mp4")
asyncio.sleep(5)
await d.stop_recording()
```

Logcat

```python
# filter logcat to file
logcat = await d.logcat("logcat.txt", clear=True, re_filter=".*FA.*") # clear default False
# do something else
await logcat.stop(timeout=3) # tell thread to stop write, wait for 3s, if not stopped, raise TimeoutError
await logcat.stop_nowait() # tell thread to stop write and close file
```


> Screenrecord will try to use scrcpy first if scrcpy found in $PATH, then fallback to `adb shell screenrecord`

_Note: The old method d.screenrecord() is removed after 0.16.2_

<!-- # run screenrecord to record screen
r = d.screenrecord()
# sleep for a while, can not large then 3 minutes
r.stop() # stop recording
r.stop_and_pull("video.mp4") # stop recording and pull video to local, then remove video from device

# control start time manually
r = d.screenrecord(no_autostart=True)
r.start() # start record
r.stop_and_pull("video.mp4") # stop recording and pull video to local, then remove video from device
``` -->

For further usage, please read [_device.py](adbutils/_device.py) for details.

## Run in command line 命令行使用

```bash
# List devices
$ python -m adbutils_async -l
8d1f93be              MI 5s
192.168.190.101:5555  Google Nexus 5X - 7.0.0 - API 24 - 1080x1920

# Show adb server version
$ python -m adbutils -V
39

# Install apk from local filesystem 安装本地apk(带有进度)
$ python -m adbutils -i some.apk
# Install apk from URL 通过URL安装apk(带有进度)
$ python -m adbutils -i http://example.com/some.apk
# Install and launch (-L or --launch)
$ python -m adbutils -i http://example.com/some.apk -L

# Parse apk info (support URL and local)
$ python -m adbutils --parse http://example.com/some.apk
$ python -m adbutils --parse some.apk
package: com.example.some
main-activity: com.example.some.MainActivity
version-name: 1.0.0
version-code: 100

# Uninstall 卸载应用
$ python -m adbutils -u com.github.example

# Push
$ python -m adbutils --push local.txt:/sdcard/remote.txt

# Pull
$ python -m adbutils --pull /sdcard/remote.txt # save to ./remote.txt

# List installed packages 列出所有应用
$ python -m adbutils --list-packages
com.android.adbkeyboard
com.buscode.whatsinput
com.finalwire.aida64
com.github.uiautomator

# Show URL of file QRCode 
$ python -m adbutils --qrcode some.apk
.--------.
|        |
| qrcode |
|        |
\--------/

# screenshot with screencap
$ python -m adbutils --screenshot screen.jpg 

# download minicap, minicap.so to device
$ python -m adbutils --minicap

# take screenshot with minicap
$ python -m adbutils --minicap --screenshot screen.jpg # screenshot with minicap

# Show more info for developers
$ python -m adbutils --dump-info
==== ADB Info ====
Path: /usr/local/bin/adb
Server version: 41

>> List of devices attached
- 9de75303 picasso Redmi K30 5G

# Track device status, function like: watch adb devices
$ python -m adbutils --track
15:09:59.534 08a3d291 -> device
15:10:02.683 08a3d291 -> absent
15:10:05.196 08a3d291 -> offline
15:10:06.545 08a3d291 -> absent
15:10:06.545 08a3d291 -> device
```

### Environment variables

```bash
ANDROID_SERIAL  serial number to connect to
ANDROID_ADB_SERVER_HOST adb server host to connect to
ANDROID_ADB_SERVER_PORT adb server port to connect to
```

### Color Logcat

For convenience of using logcat, I put put pidcat inside.

```bash
python3 -m adbutils.pidcat [package]
```

![](assets/images/pidcat.png)


## Experiment
Install Auto confirm supported(Beta), you need to famillar with [uiautomator2](https://github.com/openatx/uiautomator2) first

```bash
# Install with auto confirm (Experiment, based on github.com/openatx/uiautomator2)
$ python -m adbutils --install-confirm -i some.apk
```

For more usage, please see the code for details.

## Examples
Record video using screenrecord

```python
stream = d.shell("screenrecord /sdcard/s.mp4", stream=True)
asyncio.sleep(3) # record for 3 seconds
with stream:
	stream.send(b"\003") # send Ctrl+C
	stream.read_until_close()

start = time.time()
print("Video total time is about", time.time() - start)
d.sync.pull("/sdcard/s.mp4", "s.mp4") # pulling video
```

Reading Logcat

```python
d.shell("logcat --clear")
stream = d.shell("logcat", stream=True)
with stream:
    f = stream.conn.makefile()
    for _ in range(100): # read 100 lines
        line = f.readline()
        print("Logcat:", line.rstrip())
    f.close()
```

# Develop
```sh
git clone https://github.com/openatx/adbutils adbutils
pip3 install -e adbutils # install as development mode
```

Now you can edit code in `adbutils` and test with

```python
import adbutils
# .... test code here ...
```

Run tests requires one device connected to your computer

```sh
# change to repo directory
cd adbutils

pip3 install pytest
pytest tests/
```

# Environment
Some environment can affect the adbutils behavior

- ADBUTILS_ADB_PATH: specify adb path, default search from PATH
- ANDROID_SERIAL: default adb serial
- ANDROID_ADB_SERVER_HOST: default 127.0.0.1
- ANDROID_ADB_SERVER_PORT: default 5037

## Watch adb socket data
Watch the adb socket data using `socat`

```
$ socat -t100 -x -v TCP-LISTEN:5577,reuseaddr,fork TCP4:localhost:5037
```

open another terminal, type the following command then you will see the socket data

```bash
$ export ANDROID_ADB_SERVER_PORT=5577
$ adb devices
```

## Generate TOC
```bash
gh-md-toc --insert README.md
```

<https://github.com/ekalinin/github-markdown-toc>

# Thanks
- [adbutils](https://github.com/openatx/adbutils)
- [swind pure-python-adb](https://github.com/Swind/pure-python-adb)
- [openstf/adbkit](https://github.com/openstf/adbkit)
- [ADB Source Code](https://github.com/aosp-mirror/platform_system_core/blob/master/adb)
- ADB Protocols [OVERVIEW.TXT](https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/OVERVIEW.TXT) [SERVICES.TXT](https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/SERVICES.TXT) [SYNC.TXT](https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/SYNC.TXT)
- [Awesome ADB](https://github.com/mzlogin/awesome-adb)
- [JakeWharton/pidcat](https://github.com/JakeWharton/pidcat)

# Alternative
- https://github.com/openatx/adbutils
- https://github.com/Swind/pure-python-adb

# Ref
- <https://github.com/imageio/imageio-ffmpeg/blob/80e37882d0/imageio_ffmpeg/_utils.py>

# LICENSE
[MIT](LICENSE)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/touxiaoling/adbutils_async",
    "name": "adbutils-async",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "adb, adbutils, async",
    "author": "tomin",
    "author_email": "tomin <tomin@tomin.com>",
    "download_url": "https://files.pythonhosted.org/packages/f6/53/678a5f69387e32673de216ac64949064ca66f465d75306793adea2dc0b69/adbutils_async-0.0.4.tar.gz",
    "platform": null,
    "description": "# adbutils_async\n[![PyPI](https://img.shields.io/pypi/v/adbutils_async.svg?color=blue)](https://pypi.org/project/adbutils_async/#history)\n\nPython adb async library for adb service (Only support Python3.10+)\n\nfork from [adbutils](https://github.com/openatx/adbutils)\n\n**Table of Contents**\n\n<!--ts-->\n   * [adbutils_async](#adbutils_async)\n   * [Install](#install)\n   * [Usage](#usage)\n      * [Connect ADB Server](#connect-adb-server)\n      * [List all the devices and get device object](#list-all-the-devices-and-get-device-object)\n      * [Connect remote device](#connect-remote-device)\n      * [adb forward and adb reverse](#adb-forward-and-adb-reverse)\n      * [Create socket connection to the device](#create-socket-connection-to-the-device)\n      * [Run shell command](#run-shell-command)\n      * [Transfer files](#transfer-files)\n      * [Extended Functions](#extended-functions)\n      * [Run in command line \u547d\u4ee4\u884c\u4f7f\u7528](#run-in-command-line-\u547d\u4ee4\u884c\u4f7f\u7528)\n         * [Environment variables](#environment-variables)\n         * [Color Logcat](#color-logcat)\n      * [Experiment](#experiment)\n      * [Examples](#examples)\n   * [Develop](#develop)\n      * [Watch adb socket data](#watch-adb-socket-data)\n   * [Thanks](#thanks)\n   * [Ref](#ref)\n   * [LICENSE](#license)\n\n<!-- Added by: shengxiang, at: 2021\u5e74 3\u670826\u65e5 \u661f\u671f\u4e94 15\u65f605\u520604\u79d2 CST -->\n\n<!--te-->\n\n# Install\n```\npip3 install adbutils-async\n```\n\n# Usage\nExample\n\n## Connect ADB Server\n```python\nimport asyncio\nimport adbutils_async\nasync def main()\n    adb = await adbutils_async.AdbClient(host=\"127.0.0.1\", port=5037)\n    for info in await adb.list():\n        print(info.serial, info.state)\n        # <serial> <device|offline>\n\n    # only list state=device\n    print(await adb.device_list())\n\n    # Set socket timeout to 10 (default None)\n    adb = await adbutils_async.AdbClient(host=\"127.0.0.1\", port=5037, socket_timeout=10)\n    print(await adb.device_list())\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\nThe above code can be short to `from adbutils_async import adb`\n\n## List all the devices and get device object\n```python\nimport asyncio\nfrom adbutils_async import adb\n\nasync def main()\n    for d in await adb.device_list():\n        print(d.serial) # print device serial\n\n    d = await adb.device(serial=\"33ff22xx\")\n\n    # or\n    d = await adb.device(transport_id=24) # transport_id can be found in: adb devices -l\n\n    # You do not need to offer serial if only one device connected\n    # RuntimeError will be raised if multi device connected\n    d = await adb.device()\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\nThe following code will not write `from adbutils import adb` for short\n\n## Connect or disconnect remote device\nSame as command `adb connect`\n\n```python\noutput = await adb.connect(\"127.0.0.1:5555\")\nprint(output)\n# output: already connected to 127.0.0.1:5555\n\n# connect with timeout\ntry:\n    await adb.connect(\"127.0.0.1:5555\", timeout=3.0)\nexcept AdbTimeout as e:\n    print(e)\n\nawait adb.disconnect(\"127.0.0.1:5555\")\nawait adb.disconnect(\"127.0.0.1:5555\", raise_error=True) # if device is not present, AdbError will raise\n\n# wait-for-device\nawait adb.wait_for(\"127.0.0.1:5555\", state=\"device\") # wait for device online, state default value is \"device\"\nawait adb.wait_for(\"127.0.0.1:5555\", state=\"disconnect\") # wait device disconnect\n```\n\n## adb forward and adb reverse\nSame as `adb forward --list` and `adb reverse --list`\n\n```python\n# list all forwards\nfor item in await adb.forward_list():\n    print(item.serial, item.local, item.remote)\n    # 8d1f93be tcp:10603 tcp:7912\n    # 12345678 tcp:10664 tcp:7912\n\n# list only one device forwards\nfor item in await adb.forward_list(\"8d1f93be\"):\n    print(item.serial, item.local, item.remote)\n    # 8d1f93be tcp:10603 tcp:7912\n    # 12345678 tcp:10664 tcp:7912\n\n\nfor item in await adb.reverse_list():\n    print(item.serial, item.local, item.remote)\n\n# \u76d1\u63a7\u8bbe\u5907\u8fde\u63a5 track-devices\nfor event in await adb.track_devices():\n    print(event.present, event.serial, event.status)\n\n## When plugin two device, output\n# True WWUDU16C22003963 device\n# True bf755cab device\n# False bf755cab absent\n\n# When adb-server killed, AdbError will be raised\n```\n\n## Create socket connection to the device\n\nFor example\n\n```python\n# minitouch: https://github.com/openstf/minitouch\nc = await d.create_connection(\"unix\", \"minitouch\")\nprint(await c.recv(500))\nawait c.close()\n```\n\n```python\nc = await d.create_connection(\"tcp\", 7912) # the second argument must be int\nawait c.send(b\"GET / HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\")\nprint(await c.recv(500))\nawait c.close()\n```\n\n```python\n# read device file\nasync with d.create_connection(adbutils.Network.DEV, \"/data/local/tmp/hello.txt\") as c:\n    print(await c.recv(500))\n```\n\nThere are many other usage, see [SERVICES.TXT](https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/SERVICES.TXT;l=175) for more details\n\nThanks for Pull Request from [@hfutxqd](https://github.com/openatx/adbutils/pull/27)\n\n## Run shell command\nI assume there is only one device connected.\n\n```python\nimport io\nimport asyncio\nfrom adbutils_async import adb\n\nasync def main():\n    d = await adb.device()\n\n    print(await d.serial) # \u83b7\u53d6\u5e8f\u5217\u53f7\n\n    # Argument support list, str\n    serial = await d.shell([\"getprop\", \"ro.serial\"]) # \u83b7\u53d6Prop\u4fe1\u606f\n\n    # Same as\n    serial = await d.shell(\"getprop ro.serial\")\n\n    # Set timeout for shell command\n    await d.shell(\"sleep 1\", timeout=0.5) # Should raise adbutils.AdbTimeout\n\n    # The advanced shell (returncode archieved by add command suffix: ;echo EXIT:$?)\n    ret = await d.shell2(\"echo 1\")\n    print(ret)\n    # expect: ShellReturn(args='echo 1', returncode=0, output='1\\n')\n\n    # show property, also based on d.shell\n    print(d.prop.name) # output example: surabaya\n    d.prop.model\n    d.prop.device\n    d.prop.get(\"ro.product.model\")\n    d.prop.get(\"ro.product.model\", cache=True) # a little faster, use cache data first\n\n    await d.get_serialno() # same as adb get-serialno\n    await d.get_devpath() # same as adb get-devpath\n    await d.get_state() # same as adb get-state\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\nTake screenshot\n\n```bash\n# adb exec-out screencap -p p.png\npng_data = await d.shell(\"screencap -p\", encoding=None)\npathlib.Path(\"p.png\").write_bytes(png_data)\n```\n\n## Transfer files\n```python\nawait d.sync.push(b\"Hello Android\", \"/data/local/tmp/hi.txt\") # \u63a8\u9001\u4e8c\u8fdb\u5236\u6587\u672c\nawait d.sync.push(io.BytesIO(b\"Hello Android\"), \"/data/local/tmp/hi.txt\") # \u63a8\u9001\u53ef\u8bfb\u5bf9\u8c61Readable object\nawait d.sync.push(\"/tmp/hi.txt\", \"/data/local/tmp/hi.txt\") # \u63a8\u9001\u672c\u5730\u6587\u4ef6\nawait d.sync.push(pathlib.Path(\"/tmp/hi.txt\"), \"/data/local/tmp/hi.txt\") # \u63a8\u9001\u672c\u5730\u6587\u4ef6\n\n# \u8bfb\u53d6\u6587\u4ef6\nasync for chunk in d.sync.iter_content(\"/data/local/tmp/hi.txt\"):\n    print(\"Chunk\", chunk)\n\nawait d.sync.push(b\"Hello world\", \"/data/local/tmp/hi.txt\")\noutput = await d.sync.read_text(\"/data/local/tmp/hi.txt\", encoding=\"utf-8\")\n# Expect output: \"Hello world\"\noutput = await d.sync.read_bytes(\"/data/local/tmp/hi.txt\")\n# Expect output: b\"Hello world\"\n\n# \u62f7\u8d1d\u5230\u672c\u5730\nawait d.sync.pull(\"/data/local/tmp/hi.txt\", \"hi.txt\")\n\n# \u83b7\u53d6\u5305\u7684\u4fe1\u606f\ninfo = await  d.package_info(\"com.example.demo\")\nif info:\n    print(info) \n\t# output example:\n    # {\n\t# \"version_name\": \"1.2.3\", \"version_code\": \"12\", \"signature\": \"0xff132\", \n    # \"first_install_time\": datetime-object, \"last_update_time\": datetime-object,\n    # }\n```\n\n## Extended Functions\n\nAdbUtils provided some custom functions for some complex operations.\n\nYou can use it like this:\n\n```python\n# save screenshot\npilimg = await d.screenshot()\nawait pilimg.save(\"screenshot.jpg\")\n\n# get current app info\napp_info = await d.app_current()\nprint(app_info.package)\nprint(app_info.activity)\nprint(app_info.pid) # might be 0\n\n# install apk\nawait d.install(\"apidemo.apk\") # use local path\nawait d.install(\"http://example.com/apidemo.apk\") # install from url\n# raise AdbInstallError if something went wrong\n\n# simulate click\nawait d.click(100, 100)\nawait d.click(0.5, 0.5) # center, should be float and <= 1.0\n\n# swipe from(10, 10) to(200, 200) 500ms\nawait d.swipe(10, 10, 200, 200, 0.5)\n\nawait d.list_packages()\n# example output: [\"com.example.hello\"]\n\nawait d.window_size()\n# example output: (1080, 1920)\n\nawait d.rotation()\n# example output: 1\n# other possible valus: 0, 1, 2, 3\n\nawait d.package_info(\"com.github.uiautomator\")\n# example output: {\"version_name\": \"1.1.7\", \"version_code\": \"1007\"}\n\nawait d.keyevent(\"HOME\")\n\nawait d.send_keys(\"hello world$%^&*\") # simulate: adb shell input text \"hello%sworld\\%\\^\\&\\*\"\n\nawait d.open_browser(\"https://www.baidu.com\") # \u6253\u5f00\u767e\u5ea6\n# There still too many functions, please see source codes\n\n# check if screen is on\nawait d.is_screen_on() # \u8fd4\u56de\u5c4f\u5e55\u662f\u5426\u4eae\u5c4f True or False\n\n# adb root\nawait d.root()\n\n# adb tcpip <port>\nawait d.tcpip(5555)\n```\n\nScreenrecord (mp4)\n\n```python\nawait d.start_recording(\"video.mp4\")\nasyncio.sleep(5)\nawait d.stop_recording()\n```\n\nLogcat\n\n```python\n# filter logcat to file\nlogcat = await d.logcat(\"logcat.txt\", clear=True, re_filter=\".*FA.*\") # clear default False\n# do something else\nawait logcat.stop(timeout=3) # tell thread to stop write, wait for 3s, if not stopped, raise TimeoutError\nawait logcat.stop_nowait() # tell thread to stop write and close file\n```\n\n\n> Screenrecord will try to use scrcpy first if scrcpy found in $PATH, then fallback to `adb shell screenrecord`\n\n_Note: The old method d.screenrecord() is removed after 0.16.2_\n\n<!-- # run screenrecord to record screen\nr = d.screenrecord()\n# sleep for a while, can not large then 3 minutes\nr.stop() # stop recording\nr.stop_and_pull(\"video.mp4\") # stop recording and pull video to local, then remove video from device\n\n# control start time manually\nr = d.screenrecord(no_autostart=True)\nr.start() # start record\nr.stop_and_pull(\"video.mp4\") # stop recording and pull video to local, then remove video from device\n``` -->\n\nFor further usage, please read [_device.py](adbutils/_device.py) for details.\n\n## Run in command line \u547d\u4ee4\u884c\u4f7f\u7528\n\n```bash\n# List devices\n$ python -m adbutils_async -l\n8d1f93be              MI 5s\n192.168.190.101:5555  Google Nexus 5X - 7.0.0 - API 24 - 1080x1920\n\n# Show adb server version\n$ python -m adbutils -V\n39\n\n# Install apk from local filesystem \u5b89\u88c5\u672c\u5730apk(\u5e26\u6709\u8fdb\u5ea6)\n$ python -m adbutils -i some.apk\n# Install apk from URL \u901a\u8fc7URL\u5b89\u88c5apk(\u5e26\u6709\u8fdb\u5ea6)\n$ python -m adbutils -i http://example.com/some.apk\n# Install and launch (-L or --launch)\n$ python -m adbutils -i http://example.com/some.apk -L\n\n# Parse apk info (support URL and local)\n$ python -m adbutils --parse http://example.com/some.apk\n$ python -m adbutils --parse some.apk\npackage: com.example.some\nmain-activity: com.example.some.MainActivity\nversion-name: 1.0.0\nversion-code: 100\n\n# Uninstall \u5378\u8f7d\u5e94\u7528\n$ python -m adbutils -u com.github.example\n\n# Push\n$ python -m adbutils --push local.txt:/sdcard/remote.txt\n\n# Pull\n$ python -m adbutils --pull /sdcard/remote.txt # save to ./remote.txt\n\n# List installed packages \u5217\u51fa\u6240\u6709\u5e94\u7528\n$ python -m adbutils --list-packages\ncom.android.adbkeyboard\ncom.buscode.whatsinput\ncom.finalwire.aida64\ncom.github.uiautomator\n\n# Show URL of file QRCode \n$ python -m adbutils --qrcode some.apk\n.--------.\n|        |\n| qrcode |\n|        |\n\\--------/\n\n# screenshot with screencap\n$ python -m adbutils --screenshot screen.jpg \n\n# download minicap, minicap.so to device\n$ python -m adbutils --minicap\n\n# take screenshot with minicap\n$ python -m adbutils --minicap --screenshot screen.jpg # screenshot with minicap\n\n# Show more info for developers\n$ python -m adbutils --dump-info\n==== ADB Info ====\nPath: /usr/local/bin/adb\nServer version: 41\n\n>> List of devices attached\n- 9de75303 picasso Redmi K30 5G\n\n# Track device status, function like: watch adb devices\n$ python -m adbutils --track\n15:09:59.534 08a3d291 -> device\n15:10:02.683 08a3d291 -> absent\n15:10:05.196 08a3d291 -> offline\n15:10:06.545 08a3d291 -> absent\n15:10:06.545 08a3d291 -> device\n```\n\n### Environment variables\n\n```bash\nANDROID_SERIAL  serial number to connect to\nANDROID_ADB_SERVER_HOST adb server host to connect to\nANDROID_ADB_SERVER_PORT adb server port to connect to\n```\n\n### Color Logcat\n\nFor convenience of using logcat, I put put pidcat inside.\n\n```bash\npython3 -m adbutils.pidcat [package]\n```\n\n![](assets/images/pidcat.png)\n\n\n## Experiment\nInstall Auto confirm supported(Beta), you need to famillar with [uiautomator2](https://github.com/openatx/uiautomator2) first\n\n```bash\n# Install with auto confirm (Experiment, based on github.com/openatx/uiautomator2)\n$ python -m adbutils --install-confirm -i some.apk\n```\n\nFor more usage, please see the code for details.\n\n## Examples\nRecord video using screenrecord\n\n```python\nstream = d.shell(\"screenrecord /sdcard/s.mp4\", stream=True)\nasyncio.sleep(3) # record for 3 seconds\nwith stream:\n\tstream.send(b\"\\003\") # send Ctrl+C\n\tstream.read_until_close()\n\nstart = time.time()\nprint(\"Video total time is about\", time.time() - start)\nd.sync.pull(\"/sdcard/s.mp4\", \"s.mp4\") # pulling video\n```\n\nReading Logcat\n\n```python\nd.shell(\"logcat --clear\")\nstream = d.shell(\"logcat\", stream=True)\nwith stream:\n    f = stream.conn.makefile()\n    for _ in range(100): # read 100 lines\n        line = f.readline()\n        print(\"Logcat:\", line.rstrip())\n    f.close()\n```\n\n# Develop\n```sh\ngit clone https://github.com/openatx/adbutils adbutils\npip3 install -e adbutils # install as development mode\n```\n\nNow you can edit code in `adbutils` and test with\n\n```python\nimport adbutils\n# .... test code here ...\n```\n\nRun tests requires one device connected to your computer\n\n```sh\n# change to repo directory\ncd adbutils\n\npip3 install pytest\npytest tests/\n```\n\n# Environment\nSome environment can affect the adbutils behavior\n\n- ADBUTILS_ADB_PATH: specify adb path, default search from PATH\n- ANDROID_SERIAL: default adb serial\n- ANDROID_ADB_SERVER_HOST: default 127.0.0.1\n- ANDROID_ADB_SERVER_PORT: default 5037\n\n## Watch adb socket data\nWatch the adb socket data using `socat`\n\n```\n$ socat -t100 -x -v TCP-LISTEN:5577,reuseaddr,fork TCP4:localhost:5037\n```\n\nopen another terminal, type the following command then you will see the socket data\n\n```bash\n$ export ANDROID_ADB_SERVER_PORT=5577\n$ adb devices\n```\n\n## Generate TOC\n```bash\ngh-md-toc --insert README.md\n```\n\n<https://github.com/ekalinin/github-markdown-toc>\n\n# Thanks\n- [adbutils](https://github.com/openatx/adbutils)\n- [swind pure-python-adb](https://github.com/Swind/pure-python-adb)\n- [openstf/adbkit](https://github.com/openstf/adbkit)\n- [ADB Source Code](https://github.com/aosp-mirror/platform_system_core/blob/master/adb)\n- ADB Protocols [OVERVIEW.TXT](https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/OVERVIEW.TXT) [SERVICES.TXT](https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/SERVICES.TXT) [SYNC.TXT](https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/SYNC.TXT)\n- [Awesome ADB](https://github.com/mzlogin/awesome-adb)\n- [JakeWharton/pidcat](https://github.com/JakeWharton/pidcat)\n\n# Alternative\n- https://github.com/openatx/adbutils\n- https://github.com/Swind/pure-python-adb\n\n# Ref\n- <https://github.com/imageio/imageio-ffmpeg/blob/80e37882d0/imageio_ffmpeg/_utils.py>\n\n# LICENSE\n[MIT](LICENSE)\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2019 openatx  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "Python adb async library for adb service.",
    "version": "0.0.4",
    "project_urls": {
        "Homepage": "https://github.com/touxiaoling/adbutils_async",
        "documentation": "https://github.com/touxiaoling/adbutils_async",
        "repository": "https://github.com/touxiaoling/adbutils_async"
    },
    "split_keywords": [
        "adb",
        " adbutils",
        " async"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c4f40c05d021a622d1b910633c6773b855be1af759589a8d744b95a3cb01a98e",
                "md5": "93e0113b2c517530feea3f6e8051a368",
                "sha256": "03662df515f7981bdbd60a7228e9f822165ebd3f74f7d1ba415a0fbe2e43415f"
            },
            "downloads": -1,
            "filename": "adbutils_async-0.0.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "93e0113b2c517530feea3f6e8051a368",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 38114,
            "upload_time": "2024-04-03T09:08:21",
            "upload_time_iso_8601": "2024-04-03T09:08:21.645818Z",
            "url": "https://files.pythonhosted.org/packages/c4/f4/0c05d021a622d1b910633c6773b855be1af759589a8d744b95a3cb01a98e/adbutils_async-0.0.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f653678a5f69387e32673de216ac64949064ca66f465d75306793adea2dc0b69",
                "md5": "fb38e1342056eab08069976051723203",
                "sha256": "d9073e6cb64e4d0facd0660a99205bfc039ff6c2c1a3ecd72a762ed7dfa82fe7"
            },
            "downloads": -1,
            "filename": "adbutils_async-0.0.4.tar.gz",
            "has_sig": false,
            "md5_digest": "fb38e1342056eab08069976051723203",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 49758,
            "upload_time": "2024-04-03T09:08:23",
            "upload_time_iso_8601": "2024-04-03T09:08:23.455405Z",
            "url": "https://files.pythonhosted.org/packages/f6/53/678a5f69387e32673de216ac64949064ca66f465d75306793adea2dc0b69/adbutils_async-0.0.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-03 09:08:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "touxiaoling",
    "github_project": "adbutils_async",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "adbutils-async"
}
        
Elapsed time: 0.22080s