Загрузка...

Automating Android with Python and uiautomator2

Thread in Articles created by ch3m1c0d3 Apr 26, 2024. (bumped Jul 12, 2024) 2917 views

The poll
Poll closed May 10, 2024.
Делать разбор Appium?
  1. Да

    100%
    8
  2. Нет

    0%
    0
  1. ch3m1c0d3
    ch3m1c0d3 Topic starter Apr 26, 2024 71 Jan 30, 2020

    Всем привет! Решил написать гайд, как можно автоматизировать ваши Android устройства или эмуляторы.
    Тема достаточно объёмная и здесь будет лишь база, чтобы начать изучать этот вопрос. Желательно минимальное знание синтаксика Python и чуть-чуть ООП.

    uiautomator2 - это Python обертка для сервиса UIAutomator2, который позволяет управлять действиями на устройствах Android через интерфейс HTTP.

    Для любой автоматизации ваших действий на Android устройствах. Например, я делал ферму для регистрации аккаунтов и залива видео в TikTok, когда арбитражил на дейтинг. Тогда я использовал Appium, но суть та же.

    Можно реализовать всё что, угодно (например, любые автореггеры).

    Разработчикам приложений это пригодится для тестирования.
    Прежде всего, установите Python 3.8+.
    Также потребуется установить драйвер ADB под свою операционную систему. Пример установки на Arch Linux:

    ⁡ sudo pacman -S android-tools


    Пользователи Windows могут воспользоваться инструкцией из другой моей темы.

    После этого подключите устройство к компьютеру и включите отладку по USB. Подробнее в той же теме, пункт "Настройка Android".
    Создаём директорию, где будет лежать наш проект и переходим в неё.
    Я использую Linux, поэтому приведу команды для него, но на Windows последовательность будет такая же.

    Поочерёдно вводим команды:
    bash

    mkdir project
    cd project
    Создаём виртуальное окружение

    В разных дистрибутивах Linux (и в Windows, если вы меняли псевдонимы приложений) команда запуска Python может отличаться (например, python или python3):

    ⁡ python -m venv venv


    Второй аргумент venv - название папки виртуального окружения.

    Активируем виртуальное окружение

    Linux

    ⁡ source venv/bin/activate


    Windows

    PowerShell:

    ⁡ venv/Scripts/Activate.ps1


    Командная строка:

    ⁡ venv\Scripts\activate
    uiauto — это проект, независимый от uiautomator2, используемый для просмотра структуры приложений.

    Устанавливаем обе библиотеки:

    ⁡ pip install uiautomator2 uiautodev


    На этом установка окончена и мы переходим к коду.
    Мы можем подключить устройство 2 способами:
    • Через WiFi
    • По USB

    В данной теме я не буду затрагивать подключение по WiFi, поэтому вы можете самостоятельно с ним ознакомиться.

    Импортируем библиотеку и подключаем устройство:
    python

    import uiautomator2 as u2

    device = u2.connect()
    В данном примере uiautomator2 автоматически выберет наше единственное подключённое устройство.

    Если устройств будет несколько, мы можем указать серийный номер устройства из вывода
    ⁡adb devices
    ⁡ :
    python

    import uiautomator2 as u2

    device = u2.connect('сериный номер из вывода adb devices')
    Время ожидания новой команды

    По-умолчанию uiautomator2 будет ожидать новых команд от клиента в течение 3-х минут и после этого завершит свою работу. Мы можем изменить это значение:
    python

    device.set_new_command_timeout(300) # Время в секундах (5 минут)
    Неявное ожидание элемента

    Если нам в дальнейшем потребуется произвести какие-то действия с элементом, но его не будет на экране, то мы свалимся с ошибкой, что элемент не существует.

    Чтобы это предотвратить, мы можем установить неявное ожидание, в течение которого клиент будет искать элемент:
    python

    device.implicitly_wait(10.0) # Время в секундах. Если в течение 10 секунд элемент не появится на экране, то будет поднято исключение UiObjectNotFoundError
    Если хотим обратно вернуть значение по-умолчанию, то вызываем без аргументов:
    python

    device.implicitly_wait()
    Запуск

    Запуск приложения происходит не по его имени, а по названию его пакета:
    python

    device.app_start(
    'com.android.settings',
    use_monkey=True
    )
    В разных оболочках название пакета можно узнать по-разному. Самый простой - зайти в информацию об приложении, название будет снизу:

    [IMG]
    Другой способ - скачать это приложение и ввести название приложения нужного вам.



    Остановка

    Остановка производится аналогично по названию пакета:
    python

    device.app_stop('com.android.settings')
    Очистка данных приложения
    python

    device.app_clear('com.android.settings')
    Клик по координатам
    python

    device.click(x, y)
    Свайп по координатам
    python

    device.swipe(start_x, start_y, end_x, end_y) # Начальные и конечные координаты свайпа
    device.swipe(start_x, start_y, end_x, end_y, 0.5) # Также можно указать скорость свайпа в секундах
    Расширенный свайп

    Можно указать направление свайпа:
    python

    # right
    # left
    # up
    # down

    device.swipe_ext('up')
    Можно импортировать направления свайпа из библиотеки:
    python

    from uiautomator2 import Direction

    device.swipe_ext(Direction.FORWARD) # вверх
    device.swipe_ext(Direction.BACKWARD) # вниз
    device.swipe_ext(Direction.HORIZ_FORWARD) # вправо
    device.swipe_ext(Direction.HORIZ_BACKWARD) # влево


    Все методы для взаимодействия тут.
    Селекторы

    Многим из вас знакомы селекторы (например, из Selenium). Селектор - это механизм для определения конкретного объекта пользовательского интерфейса.

    В Android мы также можем искать элементы с помощью селекторов.

    В этом нам поможет библиотека uiauto.

    Запускаем её, желательно в отдельном окне терминала:
    ⁡ uiauto.dev


    Команда даст следующий вывод, в котором нам нужен IP адрес (в моём случае - 127.0.0.1:20242):

    INFO: Started server process [57249]
    INFO: Waiting for application startup.
    INFO: Application startup complete.
    INFO: Uvicorn running on http://127.0.0.1:20242 (Press CTRL+C to quit)

    Переходим по нему и попадаем на выбор устройства:


    [IMG]
    Выбираем наше единственное устройство и попадаем на главную страницу, где мы и будем производить все манипуляции:


    [IMG]
    Здесь мы видим экран нашего устройства (думаю, не стоит говорить, что экран должен быть разблокирован) и пару вкладок:


    Hierarchy

    Иерархия элементов того, что сейчас происходит на экране. Справа видим элементы, при нажатии на которые отобразятся параметры, которые мы сможем использовать в дальнейшем. Самое главное, что мы отсюда возьмём - это XPath. Это самый беспроигрышный вариант поиска элементов, но об этом позже. Также элемент выделится на экране:


    [IMG]
    Нажав на любой элемент на экране (они обводятся пунктиром разных цветов), мы провалимся в параметры конкретно данного элемента:


    [IMG]
    Property


    Тут отображается краткая сводка о выбранном элементе


    [IMG]
    Color


    Можем узнать цвет каждого пикселя


    [IMG]
    Поиск по XPath в контексте мобильной автоматизации может быть менее эффективным из-за особенностей мобильных приложений и их элементов.

    Вместо XPath часто рекомендуется использовать другие методы поиска, такие как поиск по id, тексту, классу и т.д.

    Но XPath на текущий момент является самым стабильным методом поиска, ведь он продолжит работать, даже если приложение обновится и его интерфейс изменится. С классами и т.д. такое не прокатит.

    Единственный случай, когда я не использую XPath - когда у элемента есть параметр
    ⁡resource-id
    ⁡ , потому что он уникален и другого элемента с таким id нет. Но в некоторых приложениях, например в том же TikTok, эти id генерируются динамически.

    Чтобы найти элемент по XPath, мы можем либо вручную написать путь, либо скопировать его из uiauto

    Например, я автоматизирую запуск приложения настроек и клик на строку поиска. Для начала запустите приложение вручную, вернитесь на главную страницу uiauto и нажмите зелёную кнопку обновления сверху экрана (или просто нажмите клавишу
    ⁡R
    ⁡ ). Это обновит экран устройства в браузере.

    Далее кликаем на нужный элемент, в моём случае это строка ввода:


    [IMG]
    В большинстве случаев, у любых текстовых элементов класс будет
    ⁡android.widget.TextView
    ⁡ .



    Сверху рядом с надписью
    ⁡XPath by
    ⁡ выбираем
    ⁡text
    ⁡ , чтобы искать элемент по тексту. У этого элемента текст
    ⁡Search settings
    ⁡ :


    [IMG]
    Копируем XPath, в моём случае это
    ⁡//*[@text="Search settings")]
    ⁡ . Обратите внимание на знак
    ⁡*
    ⁡ в пути. Он означает, что мы пройдём по всем элементам и выберем тот, у которого текст равен Search settings.
    ⁡text
    ⁡ - это один из параметров, которые мы видим на вкладке
    ⁡Hierarchy
    ⁡ .



    Пишем код:
    python

    import uiautomator2 as u2

    def main():
    device = u2.connect() # Подключаем устройство
    device.implicitly_wait(10.0) # Выставляем неявное ожидание элемента в 10 секунд
    device.app_start('com.android.settings', use_monkey=True) # Запускаем приложение настроек по имени его пакета
    device.xpath('//*[@text="Search settings")]').click() # Ищем элемент по XPath и кликаем на него

    if __name__ == '__main__':
    main()
    Обратите внимание, что XPath заключён в одинарные кавычки, соответственно для текста мы используем уже двойные.

    Запускаем код и бум, мы сделали свою первую автоматизацию!


    Давайте поищем что-то в этой строке. Для этого нам нужно получить селектор для поля ввода текста. Повторяем шаги, идём на страницу uiauto, обновляем экран и выбираем поле ввода:


    [IMG]
    Здесь мы можем воспользоваться поиском по resource-id, копируем его и вносим изменения в код:

    python

    import uiautomator2 as u2

    def main():
    device = u2.connect()
    device.implicitly_wait(10.0)
    device.app_start('com.android.settings', use_monkey=True)
    device.xpath('//*[@text="Search settings"]').click()
    search_input = device(resourceId='android:id/search_src_text') # Сначала ищем элемент и присваиваем его к переменной
    search_input.clear_text() # На всякий случай очищаем поле ввода (это необязательно, но пригодится если поле не пустое)
    search_input.set_text('Battery') # Вводим нужный текст

    if __name__ == '__main__':
    main()
    Запускаем код:


    И текст введён.

    Это лишь базовый пример того, что можно сделать. А более подробное описание всех методов можно прочитать в репозитории библиотеки.
    У библиотеки есть возможность устанавливать приложения, но только по ссылке.

    Для установки приложений (и не только) мы будем использовать другую библиотеку -
    ⁡pure-python-adb
    ⁡ .

    Установим:

    ⁡ pip install pure-python-adb


    Для начала создадим экземпляр класса Client, получим список всех устройств и выберем наше единственное:
    python

    from ppadb.client import Client as ADBClient

    def main():
    adb_client = ADBClient(host='127.0.0.1', port=5037)
    adb_device = adb_client.devices()[0]

    if __name__ == '__main__':
    main()
    В эту же папку я положил APK файл. Установим его:
    python

    from ppadb.client import Client as ADBClient

    def main():
    adb_client = ADBClient(host='127.0.0.1', port=5037)
    adb_device = adb_client.devices()[0]
    adb_device.install('Open***.apk')

    if __name__ == '__main__':
    main()
    Запустим скрипт и на устройство начнёт устанавливаться приложение.
    Если мы хотим проверить, что приложение ещё не установлено, то нам нужно узнать название его пакета (об этом я писал выше):
    python

    from ppadb.client import Client as ADBClient

    def main():
    adb_client = ADBClient(host='127.0.0.1', port=5037)
    adb_device = adb_client.devices()[0]
    if not adb_device.is_installed('net.open***.open***'):
    adb_device.install('Open***.apk')

    if __name__ == '__main__':
    main()
    Метод
    ⁡is_installed
    ⁡ с аргументом названия пакета проверяет, установлено ли приложение. Мы делаем проверку и если нет, то устанавливаем его.
    Таким образом, мы можем закинуть APK файлы в отдельную папку и пройтись по ним циклом.
    Метод
    ⁡shell
    ⁡ открывает нам доступ к терминалу устройства. С помощью него мы, например, можем отключить таймаут экрана, подключиться к WiFi, переключить Bluetooth, GPS и многое другое:
    python

    from ppadb.client import Client as ADBClient

    def main():
    adb_client = ADBClient(host='127.0.0.1', port=5037)
    adb_device = adb_client.devices()[0]
    adb_device.shell('settings put system screen_off_timeout 1800000') # Отключить таймаут экрана
    adb_device.shell('svc bluetooth disable') # Отключить Bluetooth. enable чтобы включить
    adb_device.shell('settings put secure location_mode 0') # 1 чтобы включить # Отключить GPS

    adb_device.shell('svc wifi enable') # Включить модуль WiFi
    adb_device.shell('cmd wifi connect-network WIFI_SSID wpa2 WIFI_PASSWORD') # Подключиться к сети

    if __name__ == '__main__':
    main()
    Это может сработать не на всех устройствах, поэтому тестируйте. Я использую устройство на Android 12, где это работает.
    Таким образом вы можете автоматизировать как реальные устройства, так и эмуляторы. Единственное ограничение - это ваша фантазия.

    Библиотека uiautomator2, в отличие от Appium, не требует дополнительных манипуляций с системой, но синтаксис Appium мне кажется более лаконичным и понятным.

    Благодарю тех, кто дочитал до конца! ;)
     
    This article was useful for you?
    You can thank the author of the topic by transferring funds to your balance
    Thank the author
  2. august
    august Apr 26, 2024 голые альтушки - https://lolz.live/threads/8317967/ 8811 Dec 8, 2021
    на бумаге ахуенно, но надо будет затестить
     
  3. актив
    красава, максимально подробно, даже захотелось попробовать
     
  4. LifeFounder
    LifeFounder Apr 26, 2024 ) 20,144 Sep 25, 2018
    Есть еще AndroidStudio + appium, тоже годный Варик
     
  5. Пиписёк
    Пиписёк Apr 27, 2024 Смотрит тему Как увеличить член на 20 см 3464 Dec 15, 2020
    Охуенно расписал :+rep:
     
  6. К0ДЕР
    К0ДЕР May 4, 2024 446 Jan 22, 2024
    Расписал нихуево, :+rep:
     
  7. RedCap_inactive8238194
    отличная статья, спасибо!
     
  8. K9lobok
    K9lobok Jul 22, 2024 34 Apr 8, 2020
    если будете как и я мучаться с вопросом почему не идёт подключение, ставьте более новый adb
     
  9. KOKURO
    KOKURO Jul 29, 2024 Дедики тут https://lolz.live/threads/2901120 485 Jan 13, 2022
    Классно расписано, спасибо, будем пользоваться
     
  10. racc0on1
    racc0on1 Feb 24, 2025 3 Apr 20, 2021
    А что делать, если весь иерархия выглядит так и никак иначе? [IMG]
     
Top
Loading...