
Привет, Хабр. Меня зовут Даниил Смирнов. Я руководитель команды Android Core R&D в VK.
Не так давно я уже рассказывал о DeviceHub — инструменте от команды VK для одновременного управления несколькими смартфонами. Он позволяет тестировать мобильные приложения и сайты в фермах, состоящих из сотен гаджетов. Подробнее почитать об этом можно здесь.
Изначально DeviceHub мог работать только с Android-устройствами. Но теперь, после обновления, инструмент поддерживает и iOS-устройства.
Расскажу в статье, для чего нам понадобилась поддержка iOS и с чем мы столкнулись при внедрении новых возможностей.
Как мы шли к ферме для удалённого доступа к девайсам
Все бизнес-юниты VK активно разрабатывают продукты для мобильных платформ и тестируют работоспособность приложений на разных устройствах. Представьте: идёт январь 2020 года, вы с командой работаете в одном офисе, встречаетесь, обсуждаете проекты и вместе тестируете прототипы. Тогда с этим не возникало проблем — команды могли получать доступ к физическим устройствам в рамках одного офиса и тестировать свои наработки на разных устройствах iOS или Android.
Но с общим переходом на удалённый формат работы в период пандемии, ситуация кардинально изменилась. Чтобы команды могли и дальше активно разрабатывать продукты и тестировать их, нужно было рассылать устройства каждому вовлечённому в процессы. Это было долго, сложно и дорого. Поэтому мы решили адаптироваться к новым условиям — и начали работу над переходом к фермам мобильных устройств с возможностью удалённого доступа.
Уже после первой итерации стало очевидно, что писать свою ферму с нуля будет очень дорого. Поэтому мы решили применить популярное open-source решение — OpenSTF. Но и здесь всё оказалось непросто. Чтобы выбранный инструмент справлялся с текущими задачами, нам приходилось непрерывно оптимизировать его. Но доработок хватало ненадолго. В итоге мы поняли, что лучшее решение — не брать чистый open source, а полностью перенести доработки на нашу сторону. Так мы создали собственный форк, выросший в полноценное решение — VK DeviceHub.

Сейчас VK DeviceHub используется не только для ручного тестирования, но и для автотестов. Сегодня наша ферма — это 3 000 автотестов, которые прогоняются одновременно, 70+ серверов, более 700 эмуляторов на разных фермах, физические устройства, а также свыше 400 прогонов в день.
Наша физическая ферма мобильных устройств расположена в отдельном кондиционируемом помещении. В один серверный юнит мы подключаем до 50 девайсов. Также для подключения устройств в качестве серверов используем Mac mini. Он один выдерживает подключение до 40 смартфонов.
Примечание. Больше об опыте оптимизации работы с автотестами и нашей ферме мы рассказывали в предыдущих докладах «Как мы повысили эффективность фермы эмуляторов и ускорили UI-автотесты на Android» и «DeviceHub: облегчаем работу с устройствами и эмуляторами».
Зачем нам понадобился iOS в ферме?
Изначально VK DeviceHub был ориентирован на работу с устройствами на базе Android и позволял закрыть потребности всех участников процесса тестирования и разработки без необходимости закупки огромного количества Android-устройств.
С Apple всё несколько проще, поскольку нет многообразия устройств от разных производителей с неочевидными особенностями. Поэтому в теории было достаточно закупить устройства нескольких версий под основные сценарии разработки и тестирования. Но под влиянием внешних факторов ситуация изменилась.
В феврале 2025 года Apple изменила корпоративные правила. Теперь каждое устройство, на котором нужно проверить продукт, надо добавлять в аккаунт TestFlight. Это создало дополнительные издержки и трудности.
Часть специалистов продолжает работать удалённо или часто ездит в командировки. При этом нередко им может понадобиться что-то проверить на iOS-устройстве. Но отправлять iPhone 16 Android-тестировщику, который несколько раз в год будет использовать на нём отдельные сценарии — нерационально.
Иногда для тестов нужен быстрый доступ к разным версиям iOS. При использовании физических устройств здесь могут возникать трудности. Например, нам надо протестировать приложение на последней версии, а обновление на смартфон ещё не пришло. Или наоборот — телефон уже обновился, а нужно посмотреть, как ведёт себя обновление на старой версии.
Учитывая это, мы решили мигрировать с индивидуальных девайсов на столе к устройствам в облаке.
С чем мы столкнулись?
Поняв, что нам нужна ферма мобильных устройств, мы начали изучать рынок и существующие инструменты. Поиск не увенчался успехом:
в открытом доступе есть либо фермы только для автотестов, либо фермы только для iOS — ничего универсального под наши запросы;
релевантных библиотек для работы нет: некоторые из них сломались совсем недавно (например, в iOS 18), а другие — давно, и про них забыли;
есть несколько старых репозиториев с интересными идеями, но владельцы забросили их.
Так мы поняли, что надеяться на готовое решение не стоит, и начали изучать доступные возможности реализации. Требования были довольно простыми — ферма должна позволять получать картинку, а также передавать на устройство нажатие и ввод текста и работать так же круто, как наша Android-ферма.
Начали с самой сложной задачи — получения картинки.
Получение изображения с iOS
Есть несколько основных вариантов получения изображения с iOS:
HLS через ReplayKit;
AirPlay;
по проводу;
AVFoundation (он же QuickTime);
Appium WebDriverAgent.

Но у каждого из них есть свои особенности:
HLS через ReplayKit — самый простой и очевидный вариант. Чтобы протестировать его, мы нашли open-source приложение, которое доработали под себя. Но такой подход оказался неоптимален для нашего кейса — на выходе мы получили от 4 до 20 секунд задержки отображения, что критично. Поэтому от варианта отказались.
AirPlay — интересное решение, но проприетарное. Соответственно, чтобы работать с ним безопасно, нужны разрешённые интерпретации. А они не всегда работают стабильно и зачастую не могут быть развёрнуты без дополнительных сервисов.
Вариант с подключением по проводу на первый взгляд простой и надёжный. Но на практике переусложнён: нужна карта захвата, механизм получения картинки с карты захвата, алгоритм передачи картинки через браузер. И на каждом этапе этой цепочки потенциально может произойти сбой, поэтому от этой идеи тоже отказались.
AVFoundation (он же QuickTime) — программа, которая позволяет получать картинку с экрана телефона. Решение удобное и популярное, но iOS 17 — последняя версия с поддержкой QuickTime.
В поисках оптимального решения мы наткнулись на статью, где одна из команд делилась похожим кейсом. Ребята успешно применили Appium WebDriverAgent — реализацию WebDriver iOS, которая позволяет автоматизировать работу и управлять устройствами через XCTest. Изучив их опыт, мы решили рассмотреть инструмент подробнее и попробовать применить его для своих задач.
Подробнее о работе с Appium WebDriverAgent
WebDriverAgent работает по следующему принципу:
Appium tests при запуске по HTTP отправляют запросы на Appium server;
Appium server отправляет запросы на порт 8100 устройства, где работает WebDriverAgent;
WebDriverAgent через системные вызовы выполняет нужные действия с iOS.
Всё предельно просто.
Для запуска WebDriverAgent на устройстве мы используем простой алгоритм:
открываем проект в Xcode;
собираем его;
запускаем тесты из него.
Примечание: для физического устройства будет нужно изменить bundleID.

После запуска на порту 8100 устройства станет доступен WebDriver сервер, а на порту 9100 — MozJpeg поток с изображением с экрана устройства.
Чтобы взаимодействовать с WDA из фермы и запускать всё автоматически, мы сделали несколько доработок.
Реализовали отправку команд из модуля фермы в WebDriverAgent на устройстве. Подробнее об этом можно почитать здесь.
С помощью USBMux пробрасываем порты с устройства на хост, чтобы не ходить через сеть. Подробнее об этом можно почитать здесь.
Примечание: USBMux — демон, который обрабатывает связь по USB с устройствами iOS (включая связь из iTunes). Когда устройство подключено, USBMux взаимодействует с ним, как посредник для связи с устройством. Изначально мы использовали pymobiledevice3, но решили уменьшить число внешних зависимостей и перешли на использование USBMux из js. Подробнее о нём можно прочитать здесь.
Предусмотрели автоматическое переподписывание сертификата приложения с помощью небольшого скрипта:
xcodebuild\
-project WebDriverAgent.xcodeproj\
-scheme WebDriverAgentRunner\
-destination “id=$deviceld”\
-allowProvisioningUpdates\
test | tee/tmp/wdalog.txt &
wdapid=$!
В результате собрали требуемую конфигурацию для получения картинки с iOS.
Но важно отметить — наша ферма работает на Kubernetes, то есть использует Linux. Xcode там нет. Поэтому мы разместили рядом Mac mini на macOS, а на нём развернули самописное приложение STF iOS Provider. Оно взаимодействует и с USBMux и с Xcode — и выступает в роли Appium-клиента для WebDriver, который работает на устройстве.
Передача нажатия и ввода текста
Есть несколько основных способов передавать нажатия и ввод текста:
через XCTest;
с помощью внешнего устройства.

Мы решили начать с WebDriverAgent и XCTest.
XCTest
Передать нажатие через WebDriverAgent довольно просто: отправляем запросы — нажатие происходит. Но есть нюансы: для отправки свайпа нужно, чтобы пользователь завершил всё действие свайпа. Только после этого отправляются нужные координаты.
Но для полноценной фермы этого недостаточно. Нам также нужно заглядывать «под капот», как минимум — иметь возможность изучить логи.
Примечательно, что для Android есть решение, предоставляющее такие возможности, — Android Debug Bridge (ADB). Так, ADB позволяет:
собирать логи;
устанавливать приложения;
управлять устройством;
проверять статусы и состояния;
настраивать устройства под задачи.
Соответственно, нам нужен был инструмент со схожим набором возможностей для iOS.
Быстрый поиск показал, что нужный инструмент уже есть — iOS Development Bridge. Он подошёл под наши запросы, потому мы решили его применить сразу для нескольких задач, среди которых:
получение информации об устройстве;
получение файлов с устройства;
чтение логов.
Примечание: iOS Development Bridge отдаёт логи не целиком, а чанками. Чтобы парсить их, мы придумали несколько вариантов. Подробно об их реализации можно узнать здесь.
Что из этого получилось
В результате мы выстроили простой пайплайн передачи нажатия и ввода текста с помощью WebDriverAgent:
iOS-девайс с установленным WebDriverAgent подключается к машине на macOS для управления;
машина на macOS, в свою очередь, подключена к общему кластеру VK DeviceHub;
устройства обмениваются данными о состоянии через ZeroMQ и базу данных.

В итоге у нас получилось подключить живые iOS-устройства и симуляторы — всё заработало стабильно и плавно.
Немножко RnD: прототипы
У XCTest и механики работы с ним есть нюансы — и мы проводили смежные исследования.
V-USB
В рамках одной из своих гипотез мы хотели взять Arduino, оснастить его набором резисторов с конденсаторами, подключить к порту iPhone и попробовать понажимать кнопки.
Довольно быстро оказалось, что подобная реализация уже есть — V-USB. Это программная библиотека, позволяющая получить поддержку USB на AVR-микроконтроллерах, например Arduino Nano или Uno, и эмулировать HID-устройство Human Input Device.
В теории решение хорошее, но для нас оно оказалось недостаточно быстрым и стабильным.
Поэтому мы решили, что нужен контроллер сразу с HID. Так мы нашли AtMega32U4.
AtMega32U4
ATmega32U4 — 8-битный микроконтроллер от компании Microchip (ранее Atmel). Его вычислительное ядро, память и периферийные модули расположены на одной микросхеме. Это решение для проектов, где нужно прямое подключение к компьютеру без лишних компонентов. Работает быстро и почти безотказно.
Но у него есть издержки — ATmega32U4 занимает порт, поэтому остальные манипуляции с девайсом приходится проводить через сеть. Соответственно, и зарядку нужно подкидывать на аккумулятор или выполнять через MagSafe.
То есть почти успех, но чуть-чуть не хватило.
Финальная итерация
В поисках решений мы наткнулись на ролик с китайскими фермами для майнинга мобильных криптовалют или лайков, для которых нужно нажать на экран смартфона. После беглого ресёрча поняли, что подобные решения можно приобрести на тесты.
Мы решили попробовать — нашли друзей в Китае, заказали комплект и начали его тестировать. Довольно быстро увидели точки роста в существующей реализации и погрузились в свои доработки с реверс-инжинирингом. Так мы создали механизм, работающий на ESP — bluetooth-мышь и bluetooth-клавиатуру, которыми управляем с помощью команд, поступающих через serial port.
Немного о результатах проделанной работы
Мы подключили Mac mini, на котором хостилась iOS-ферма, в саму ферму, чтобы заходить в Mac mini не по SSH, когда что-то сломается, а через ферму.
-
Мы получили универсальный модуль, который позволяет подключить ферму к нам — или практически любой девайс, который работает с VNC, в проект, развёрнутый у вас.
Например, уже сейчас с помощью VK DeviceHub мы можем тестировать работу приложений на умных девайсах (например, смарт-часах), Android Auto, телевизорах и не только. В перспективе мы также планируем добавить поддержку Tizen и WebOS.
После обновления VK DeviceHub поддерживает iOS и новый интуитивно понятный интерфейс, собранный на VKUI-компонентах. Также мы устранили более 170 уязвимостей в коде.
Сценарии использования VK DeviceHub не ограничиваются автотестами. Инструмент позволяет получить удалённый доступ к устройствам для агентов поддержки и девайсам для разработки и тестирования фич.
Docker-образ VK DeviceHub уже скачали более 5 000 раз пользователи более чем из 8 стран. Отчасти такая география обусловлена тем, что в инструменте реализована поддержка 12 языков.
Специалист с опытом поднимет DeviceHub примерно за 8 минут. Среднее время решения проблемы в чате open source — 15 минут.
Краткое послесловие
Уже сейчас VK DeviceHub покрывает 99% сценариев мобильного тестирования ВКонтакте и даёт возможность проводить миллионы автотестов в месяц. При этом решение непрерывно развивается — например, в перспективе мы планируем поддержать расширенную удалённую отладку. Она упростит работу тестировщиков и даст им больше возможностей.
При этом VK DeviceHub и мы, как команда его разработки, полностью открыты: инструмент со всеми изменениями можно найти в репозитории GitHub, его образ — в Docker Hub, а любой обратной связью можно поделиться в чате DeviceHub в GitHub или ВКонтакте.