// // Created by Misterio on 24.04.2025. // #include "script_worker.h" #include "adb_fun.h" #include "xml_reader.h" #include #include #include #include // Вспомогательные функции void wait(const int milliseconds) { std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); } // Функция для запуска скрипта с передачей параметров void runScriptWorker(const std::string& pin, const std::string& last4digits) { log("Запуск скрипта для ru.rshb.dbo"); if (!checkDevices()) { log("ADB: Нет устройств"); qDebug("ADB: Нет устройств"); return; } if (!startApp("ru.rshb.dbo")) { log("Не удалось запустить приложение"); qDebug("Не удалось запустить приложение"); return; } wait(4500); dumpAndPullUiXml("ui_01.xml"); auto ui = parseUiDumpUsingQXml("ui_01.xml"); if (isPinScreen(ui)) { log("Экран PIN-кода"); qDebug("Экран PIN-кода"); // Находим координаты цифр на экране и вводим ПИН std::vector pinButtons = getPinButtons(ui); for (size_t i = 0; i < pin.length(); ++i) { char digit = pin[i]; for (const auto& el : pinButtons) { if (el.text == std::string(1, digit)) { tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2); break; } } } wait(1000); } // Пост-логин баннеры — цикл для обработки разных состояний показов модальных окон bool postLoginScreenFound = false; int attempts = 5; // Максимальное количество попыток парсинга xml while (attempts-- > 0) { dumpAndPullUiXml("ui_02.xml"); auto ui2 = parseUiDumpUsingQXml("ui_02.xml"); // Закрытие баннеров или диалогов if (handlePostLoginScreen(ui2)) { postLoginScreenFound = true; break; } // Проверка, если мы на главном экране if (isMainScreen(ui2)) { log("Главный экран подтверждён"); postLoginScreenFound = true; break; } // Ждем немного перед следующим запросом дампа экрана wait(1000); } if (!postLoginScreenFound) { log("Не удалось определить пост-логин баннер."); return; } // Пролистывание до кнопки "Все продукты" swipe(1000, 2000, 1000, 1300); wait(500); // Нажимаем на кнопку "Все продукты" dumpAndPullUiXml("ui_03.xml"); auto ui3 = parseUiDumpUsingQXml("ui_03.xml"); // Ищем кнопку "Все продукты" и нажимаем на неё tapByText(ui3, "Все продукты"); wait(800); // Шаг 6: Выбор карты на экране "Все продукты" // Запрашиваем дамп UI для поиска карт dumpAndPullUiXml("ui_04.xml"); auto ui4 = parseUiDumpUsingQXml("ui_04.xml"); // Определим, какую карту выбрать, например, с 4 цифрами "0823" UiElement cardButton = findCardByLast4Digits(ui4, last4digits); if (cardButton.text.isEmpty()) { log("Не найдена карта с номером, содержащим " + last4digits); return; } // Нажимаем на карту tap((cardButton.x1 + cardButton.x2) / 2, (cardButton.y1 + cardButton.y2) / 2); wait(1000); // Нажимаем на кнопку "Оплатить" // Запрашиваем дамп UI для поиска кнопки "Оплатить" dumpAndPullUiXml("ui_05.xml"); auto ui5 = parseUiDumpUsingQXml("ui_05.xml"); // Ищем кнопку "Оплатить" и нажимаем на неё UiElement payBtn = findPayButton(ui5); if (payBtn.text.isEmpty()) { log("Не найдена кнопка 'Оплатить'"); return; } // Нажимаем на кнопку "Оплатить" tap((payBtn.x1 + payBtn.x2) / 2, (payBtn.y1 + payBtn.y2) / 2); log("Нажата кнопка 'Оплатить'"); wait(1000); } // Функции для определения экранов и действий bool isPinScreen(const std::vector& ui) { for (const auto& el : ui) { if (el.text == "Введите ПИН") { return true; } } return false; } std::vector getPinButtons(const std::vector& ui) { std::vector pinButtons; for (const auto& el : ui) { if (el.text.length() == 1 && std::isdigit(el.text[0].toLatin1())) { pinButtons.push_back(el); // Собираем все элементы с цифрами } } return pinButtons; } void tapByText(const std::vector& ui, const std::string& text) { for (const auto& el : ui) { if (el.text == QString::fromStdString(text)) { tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2); break; } } } // Тап по полю ввода void tapInputField(const std::vector& ui, const std::string& fieldText) { for (const auto& el : ui) { if (el.text == QString::fromStdString(fieldText)) { tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2); break; } } } // Тап по кнопке "Далее" void tapNextButton(const std::vector& ui) { for (const auto& el : ui) { if (el.text == "Войти" || el.text == "Далее" || el.text == "Продолжить") { tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2); break; } } } bool handlePostLoginScreen(const std::vector& ui) { for (const auto& el : ui) { // Ищем баннеры и модальные окна, которые нужно закрыть if (el.text == "Получайте новости с помощью" || el.text == "Не пропускайте специальные предложения и рекомендации") { // Тапаем по пустой области tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2); wait(900); return true; } if (el.text == "Позже" || el.text == "Окей" || el.text == "Закрыть") { // Тапаем по кнопке закрытия или кнопке "Позже" tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2); wait(900); return true; } } return false; } bool isMainScreen(const std::vector& ui) { for (const auto& el : ui) { if (el.text == "Счета и карты" || el.text == "Доступно баллов") { return true; } } return false; } UiElement findCardByLast4Digits(const std::vector& ui, const std::string& last4digits) { // Проходим по всем элементам UI, которые парсились из XML for (const auto& el : ui) { // Используем регулярное выражение для поиска 4 цифр в тексте std::smatch m; std::string str = el.text.toUtf8().constData(); // Преобразуем QString в std::string // Если в тексте найдено совпадение с регулярным выражением для 4 цифр if (std::regex_search(str, m, std::regex(R"(\*\*\s?(\d{4}))"))) { // Проверяем, совпадают ли последние 4 цифры с переданными if (m[1] == last4digits) { // Если нашли совпадение, возвращаем элемент return el; } } } // Если карта с такими последними цифрами не найдена, возвращаем пустой элемент return {}; } UiElement findPayButton(const std::vector& ui) { for (const auto& el : ui) { if (el.text == "Оплатить") { return el; } } return {}; }