Загрузка...

Автоматизация Android с помощью Python и uiautomator2

Тема в разделе Статьи создана пользователем ch3m1c0d3 26 апр 2024. (поднята 12 июл 2024) 2820 просмотров

Опрос

Делать разбор Appium?

Голосование закрыто 10 май 2024.
  1. Да

    8
    100%
  2. Нет

    0
    0%
  1. ch3m1c0d3
    ch3m1c0d3 Автор темы 26 апр 2024 71 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 мне кажется более лаконичным и понятным.

    Благодарю тех, кто дочитал до конца! ;)
     
    Этот материал оказался полезным?
    Вы можете отблагодарить автора темы путем перевода средств на баланс
    Отблагодарить автора
    26 апр 2024 Изменено
  2. august
    august 26 апр 2024 голые альтушки - https://lolz.live/threads/8317967/ 7742 8 дек 2021
    на бумаге ахуенно, но надо будет затестить
     
  3. актив
    актив 26 апр 2024 Заблокирован(а)
    красава, максимально подробно, даже захотелось попробовать
     
  4. LifeFounder
    LifeFounder 26 апр 2024 :catzaza: 20 129 25 сен 2018
    Есть еще AndroidStudio + appium, тоже годный Варик
     
  5. Пиписёк
    Пиписёк 27 апр 2024 МИЛЛИОНЕР ЗА МЕСЯЦ - https://lolz.live/threads/8241684/ 3434 15 дек 2020
    Охуенно расписал :+rep:
     
  6. К0ДЕР
    К0ДЕР 4 май 2024 448 22 янв 2024
    Расписал нихуево, :+rep:
     
  7. RedCap_inactive8238194
    отличная статья, спасибо!
     
  8. K9lobok
    K9lobok 22 июл 2024 34 8 апр 2020
    если будете как и я мучаться с вопросом почему не идёт подключение, ставьте более новый adb
     
  9. KOKURO
    KOKURO 29 июл 2024 Дедики тут https://lolz.live/threads/2901120 478 13 янв 2022
    Классно расписано, спасибо, будем пользоваться
     
  10. racc0on1
    racc0on1 24 фев 2025 3 20 апр 2021
    А что делать, если весь иерархия выглядит так и никак иначе? [IMG]
     
Загрузка...
Top