ZennoPoster + Android Studio AVD: нативная автоматизация Android без посредников

kolina

Client
Регистрация
05.10.2019
Сообщения
178
Благодарностей
57
Баллы
28
О чём статья

  • Как напрямую управлять Android-эмулятором Android Studio AVD из ZennoPoster (через adb).
  • Как нажимать, свайпить, печатать и снимать UI без Appium и сторонних «прокладок».
  • Как стабильно работать с «прожорливыми» мессенджерами (пример: Telegram).
  • Готовые сниппеты C# для вставки в ZennoPoster, чек-листы стабильности и отладки.

    Zenno.png

Почему AVD (Android Studio) + ZennoPoster

AVD — официальный эмулятор Android. Он:
  • максимально совместим с новыми API/SDK;
  • не тащит лишний софт/рекламу;
  • предсказуем по координатам и поведению ввода;
  • поддерживает «родной» инструментарий (ADB, UIAutomator).
ZennoPoster — мощный раннер с визуальными блоками и C#:
  • легко миксует HTTP/API-шаги и мобильную автоматизацию;
  • хранит состояния (Таблицы/Списки/Переменные);
  • позволяет писать «тонкие» C#-обработчики для adb/UI.

Итог: минимальная связка, высокая скорость, гибкость и полная управляемость.

Архитектура решения:
ZennoPoster (C# блоки)
       │
       ├─ запускает adb.exe с нужными аргументами
       │
       ├─ отправляет команды ввода:
       │    input tap / text / swipe / keyevent
       │
       ├─ снимает разметку экрана:
       │    uiautomator dump → /sdcard/ui.xml → cat
       │
       └─ парсит XML (bounds, class, text, content-desc)
Быстрый старт (чек-лист)
  1. Поставьте Android StudioSDK Platform-Tools (там adb.exe).
    Пример пути:
    C:\Users\User\AppData\Local\Android\Sdk\platform-tools\adb.exe
  2. Создайте AVD (напр., Pixel 7 / Android 14–15). Запустите эмулятор.
    В adb devices -l увидите что-то вроде emulator-5554.
  3. Подготовьте ZennoPoster: блок C# + ваш путь к adb и serial AVD.
  4. Проверьте команду:
cmd:
adb -s emulator-5554 shell getprop ro.product.model
Базовые операции: готовые сниппеты
1) Быстрый вызов adb из C# блока ZennoPoster

C#:
string adb = @"C:\Users\User\AppData\Local\Android\Sdk\platform-tools\adb.exe";
string serial = "emulator-5554";
string RunAdb(string args, int timeoutMs = 1500)
{
    var psi = new System.Diagnostics.ProcessStartInfo {
        FileName = adb, Arguments = args,
        UseShellExecute = false, CreateNoWindow = true,
        RedirectStandardOutput = true, RedirectStandardError = true,
        StandardOutputEncoding = System.Text.Encoding.UTF8,
        StandardErrorEncoding  = System.Text.Encoding.UTF8
    };
    using var p = new System.Diagnostics.Process { StartInfo = psi };
    p.Start();
    if (!p.WaitForExit(timeoutMs)) { try { p.Kill(); } catch {} }
    var err = p.StandardError.ReadToEnd();
    if (!string.IsNullOrWhiteSpace(err) && !err.Contains("dumped to"))
        project.SendWarningToLog("[ADB] " + err);
    return p.StandardOutput.ReadToEnd();
}
2) Ввод: тап, текст, свайп, «назад»

C#:
void Tap(int x, int y) =>
    RunAdb($"-s {serial} shell input tap {x} {y}");

void TypeText(string text) =>
    RunAdb($"-s {serial} shell input text {text}");

void Swipe(int x1,int y1,int x2,int y2,int ms=150) =>
    RunAdb($"-s {serial} shell input swipe {x1} {y1} {x2} {y2} {ms}");

void Back() => RunAdb($"-s {serial} shell input keyevent KEYCODE_BACK");
3) Снятие UI без зависаний

C#:
string DumpUI()
{
    RunAdb($"-s {serial} shell uiautomator dump /sdcard/ui.xml");
    return RunAdb($"-s {serial} shell cat /sdcard/ui.xml");
}
Как «читать» экран: парсим UIAutomator XML

В DumpUI() приходит XML со структурой элементов. Можно искать:
  • @class (например, androidx.recyclerview.widget.RecyclerView);
  • @text — текст у виджета (часто у «листовых» сообщений);
  • @Content-desc — подпись для доступности (иконки, FAB);
  • @bounds — координаты [x1,y1][x2,y2].
Пример извлечения текстов сообщений из ленты (RecyclerView):

C#:
List<string> ExtractMessages(string xml)
{
    var res = new List<string>();
    var m = System.Text.RegularExpressions.Regex.Match(xml ?? "", "(<hierarchy[\\s\\S]*?</hierarchy>)");
    if (!m.Success) return res;

    var doc = new System.Xml.XmlDocument();
    doc.LoadXml(m.Groups[1].Value);

    // Многие мессенджеры кладут «текст сообщения» прямо в text узлов ViewGroup
    var nodes = doc.SelectNodes("//node[@class='androidx.recyclerview.widget.RecyclerView']/node[@class='android.view.ViewGroup' and @text!='']");
    if (nodes != null)
        foreach (System.Xml.XmlNode n in nodes)
            res.Add(n.Attributes?["text"]?.Value ?? "");

    return res;
}
Примечание: структура у разных приложений может отличаться — смотрите реальный XML (project.Variables["test"] = DumpUI();-) и корректируйте XPath.

Практика на примере Telegram
Переход в канал/группу по схеме «deeplink + intent»
C#:
// Жёстко: Telegram уже установлен в профиле AVD с Play Services.
string tgGroup = "@gruz"; // или t.me/...
RunAdb($"-s {serial} shell am start -a android.intent.action.VIEW -d https://t.me/{tgGroup.TrimStart('@')}");
Если Telegram уже открыт поверх — система часто пишет:
Activity not started, intent has been delivered to currently running top-most instance.
Это норм: приложение получило интент и само переключило экран.

«Прыгнуть к последним» (если есть FAB)
  • снимаем XML → ищем content-desc/text с ключами типа «в конец», «последним», «jump», «new message»;
  • тапаем в центр найденной кнопки (по bounds);
  • если не нашли — делаем пару свайпов вверх по левому краю (чтобы избежать случайного «поделиться/реакции»).
Сбор сообщений
Подходы:
  1. Скроллить и парсить каждую «порцию» UI (быстро, но зависит от верстки).
  2. Не скроллить, а ждать 30 сек и каждые N секунд снимать UI (полезно для «живых» каналов).
Оба подхода мы успешно использовали. В «скроллинговом» — помогает:
  • свайпать по левому краю,
  • не делать слишком короткие свайпы (иначе эмулятор считает их tap),
  • избегать долгих свайпов (>500 мс), чтобы не сработал long-press.

«Анти-ловушки» и лайфхаки стабильности
  • Шторка «Поделиться». При слишком длинном/правом свайпе может выпадать системный «chooser».
    Решение: свайпать по левому краю, при детекте «resolver/chooser/share» делать KEYCODE_BACK.
  • Залипания uiautomator. Команда exec-out uiautomator dump иногда «виснет».
    Решение: использовать «надёжную» схему
    uiautomator dump /sdcard/ui.xml → cat /sdcard/ui.xml.
  • Тайминги. Избыточные Thread.Sleep(1000+) убивают скорость.
    На практике хватает 30–120 мс между жестами, 20–50 мс перед дампом.
  • Координаты. Нормируйте от размеров экрана (wm size), а не хардкод.
  • Кодировка. Если видите «кракозябры», попробуйте «перекинуть» как 1251/1252→UTF-8 (простые фиксы в коде).

Когда нужен Appium / UIAutomator2
  • Нужны локаторы по ресурсу/иерархии и стабильные клики без координат.
  • Сложные сценарии с ожиданиями и взаимодействием изнутри Android (Accessibility).
  • Мульти-эмуляторы и тонкий контроль времени анимаций.
Но для массы задач (чтение ленты, «снять последние X», базовые клики/свайпы) ADB-подход проще, быстрее и не требует лишних слоёв.

Готовый «скелет» сценария (свайп + сбор)

C#:
// 1) уже перешли в группу (интентом) и «провалились в самый низ» другой подзадачей
// 2) здесь: делаем 10 свайпов «в историю» и собираем тексты как есть

IZennoList outList = project.Lists["Список 1"];
outList.Clear();

string adb = @"C:\Users\User\AppData\Local\Android\Sdk\platform-tools\adb.exe";
string serial = "emulator-5554";

string RunAdb(string args, int t=900) { /* из блока выше */ return ""; }
void Swipe(int x1,int y1,int x2,int y2,int ms=160) => RunAdb($"-s {serial} shell input swipe {x1} {y1} {x2} {y2} {ms}");
string DumpUI(){ RunAdb($"-s {serial} shell uiautomator dump /sdcard/ui.xml"); return RunAdb($"-s {serial} shell cat /sdcard/ui.xml"); }

(int W,int H) GetWH(){
  var m = System.Text.RegularExpressions.Regex.Match(RunAdb($"-s {serial} shell wm size"), @"(\d+)\s*x\s*(\d+)");
  return m.Success ? (int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value)) : (1080,2400);
}
var (W,H) = GetWH();
int xL = (int)(W*0.08);
int y1 = (int)(H*0.12), y2 = (int)(H*0.90);

System.Collections.Generic.List<string> Extract(string xml){
  var res = new System.Collections.Generic.List<string>();
  var mm = System.Text.RegularExpressions.Regex.Match(xml ?? "", "(<hierarchy[\\s\\S]*?</hierarchy>)");
  if (!mm.Success) return res;
  var doc = new System.Xml.XmlDocument(); doc.LoadXml(mm.Groups[1].Value);
  var nodes = doc.SelectNodes("//node[@class='androidx.recyclerview.widget.RecyclerView']/node[@class='android.view.ViewGroup' and @text!='']");
  if (nodes!=null) foreach(System.Xml.XmlNode n in nodes) res.Add(n.Attributes?["text"]?.Value ?? "");
  return res;
}

// текущий кадр + 10 свайпов
var seen = new System.Collections.Generic.HashSet<string>();
for (int i=0;i<11;i++){
  var xml = DumpUI();
  foreach (var t in Extract(xml))
    if (!string.IsNullOrWhiteSpace(t) && seen.Add(t)) outList.Add(t);

  if (i==10) break;       // дефолт: 10 свайпов
  Swipe(xL, y1, xL, y2);  // вниз (в историю)
}

project.SendInfoToLog($"[OK] Собрано: {outList.Count}");
return 0;
Диагностика и логирование (чек-лист)
  • Писать в лог путь к adb, serial, размеры экрана.
  • Хранить сырой XML последнего DumpUI() в переменной test для быстрой отладки XPath.
  • Фиксировать «подозрительные» stderr из adb (но не ругаться на «dumped to /sdcard/ui.xml»).
  • Если что-то «случайно нажимается» — перенести жесты ещё левее и чуть удлинить ms.

Безопасность и этика
  • Уважайте правила площадок и приватность пользователей.
  • Не автоматизируйте действий, запрещённых ToS/законами.
  • Работайте в тестовых/демо-окружениях и своих аккаунтах.
FAQ
Почему иногда пусто в списке сообщений?
Чаще всего — из-за XPath (у вашего приложения другой класс/расположение текста). Сохраните DumpUI() в переменную, откройте XML и подстройте SelectNodes().
Почему срабатывает «Поделиться/реакция»?
Короткий/правый свайп похож на tap/long-press. Свайпайте слева и держите длительность ~140–200 мс.
uiautomator dump зависает.
Используйте «через файл»: dump /sdcard/ui.xml → cat /sdcard/ui.xml.
Нужно ли Appium?
Если нужен надёжный поиск по resource-id, сложные ожидания внутри активности или кросс-девайс сценарии — да. Для «читать/листать/нажимать» чаще достаточно ADB.

Итоги
  • ZennoPoster + AVD даёт нативный, быстрый и прозрачный способ автоматизировать Android без посредников.
  • Базовых кирпичиков (tap/text/swipe/dump + XPath) достаточно для 80% задач: от чтения лент до аккуратных действий в приложениях.
  • Стабильность обеспечивают левый край свайпов, корректные тайминги и «быстрый» дамп UI.

    Приложил видео работы проекта
 

Для запуска проектов требуется программа ZennoPoster.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...

Для того чтобы запустить шаблон, откройте программу ZennoPoster. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.

Последнее редактирование:

Gfoblin

Client
Регистрация
30.05.2013
Сообщения
4 685
Благодарностей
1 047
Баллы
113
Пошла жара!!!
 

Dr.Pipetka

Client
Регистрация
12.12.2017
Сообщения
1 391
Благодарностей
941
Баллы
113
А что с подменой отпечатков?)
 

nvrskozzy

Client
Регистрация
11.07.2025
Сообщения
279
Благодарностей
24
Баллы
18
Это для эмуляторов или реальные трубки тоже?
 

soprano

Client
Регистрация
25.08.2011
Сообщения
964
Благодарностей
1 135
Баллы
93
Отлично. Вот на ZennoDroid жду таких примеров.
 

kolina

Client
Регистрация
05.10.2019
Сообщения
178
Благодарностей
57
Баллы
28
GPT утверждает что реальными трубками управлять можно тоже. Для моих задач достаточно эмулятора. Потребляет 700мб оперативки
С подменой отпечатков не знаю, но можно создавать множество устройств в Android Studio AVD
 

kolina

Client
Регистрация
05.10.2019
Сообщения
178
Благодарностей
57
Баллы
28
Отлично. Вот на ZennoDroid жду таких примеров.
Нет у меня ZennoDroid))) Стояла задача автоматизировать андроид, думал что делать покупать или найти решение и прикрутить к Zennoposter. Сейчас понимаю что наверно все вопросы закрою Zennoposter.
 

Protey

Client
Регистрация
09.01.2016
Сообщения
209
Благодарностей
29
Баллы
28
а база отпечатков реальных телефонов есть?)
 

kolina

Client
Регистрация
05.10.2019
Сообщения
178
Благодарностей
57
Баллы
28

radv

Client
Регистрация
11.05.2015
Сообщения
3 874
Благодарностей
2 109
Баллы
113
Нет у меня ZennoDroid))) Стояла задача автоматизировать андроид, думал что делать покупать или найти решение и прикрутить к Zennoposter. Сейчас понимаю что наверно все вопросы закрою Zennoposter.
все зависит от задач и сервисов которые автоматизировать нужно.
 

Кто просматривает тему: (Всего: 2, Пользователи: 0, Гости: 2)