diff --git a/CMakeLists.txt b/CMakeLists.txt index af6e512..16901bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,18 +16,27 @@ set(CMAKE_AUTOUIC ON) add_compile_definitions(QT_MESSAGELOGCONTEXT) if (WIN32) - # Определяем архитектуру: проверяем VCPKG triplet, CMAKE переменные и env - if (VCPKG_TARGET_TRIPLET MATCHES "arm64" + # Определяем целевую архитектуру. + # CMAKE_GENERATOR_PLATFORM (-A flag) — самый надёжный способ определения при кросс-компиляции. + # На ARM64 хосте CMAKE_SYSTEM_PROCESSOR может быть "ARM64" даже при сборке под x64, + # поэтому сначала проверяем явные x64-признаки. + if (CMAKE_GENERATOR_PLATFORM STREQUAL "x64" + OR CMAKE_GENERATOR_PLATFORM STREQUAL "Win64" + OR VCPKG_TARGET_TRIPLET MATCHES "x64") + message(STATUS "Detected x64 target architecture") + set(CMAKE_PREFIX_PATH "C:/Qt/6.9.0/msvc2022_64") + list(APPEND CMAKE_PREFIX_PATH "C:/Users/User/.vcpkg-clion/vcpkg/installed/x64-windows") + set(Tesseract_DIR "C:/Users/User/.vcpkg-clion/vcpkg/installed/x64-windows/share/tesseract") + elseif (VCPKG_TARGET_TRIPLET MATCHES "arm64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64" - OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64" OR CMAKE_CXX_COMPILER MATCHES "arm64") message(STATUS "Detected ARM64 target architecture") set(CMAKE_PREFIX_PATH "C:/Qt/6.9.0/msvc2022_arm64") list(APPEND CMAKE_PREFIX_PATH "C:/Users/User/.vcpkg-clion/vcpkg/installed/arm64-windows") set(Tesseract_DIR "C:/Users/User/.vcpkg-clion/vcpkg/installed/arm64-windows/share/tesseract") else () - message(STATUS "Detected x64 target architecture") + message(STATUS "Detected x64 target architecture (default)") set(CMAKE_PREFIX_PATH "C:/Qt/6.9.0/msvc2022_64") list(APPEND CMAKE_PREFIX_PATH "C:/Users/User/.vcpkg-clion/vcpkg/installed/x64-windows") set(Tesseract_DIR "C:/Users/User/.vcpkg-clion/vcpkg/installed/x64-windows/share/tesseract") diff --git a/android/adb/AdbUtils.cpp b/android/adb/AdbUtils.cpp index 829b02e..8ad1e85 100644 --- a/android/adb/AdbUtils.cpp +++ b/android/adb/AdbUtils.cpp @@ -3,29 +3,60 @@ #include #include #include +#include AdbUtils::AdbUtils(QObject *parent) : QObject(parent) { } QString AdbUtils::adbPath() { #ifdef Q_OS_WIN - return QCoreApplication::applicationDirPath() + "/tools/adb/windows/adb.exe"; + QString path = QCoreApplication::applicationDirPath() + "/tools/adb/windows/adb.exe"; #else - return QCoreApplication::applicationDirPath() + "/tools/adb/macos/adb"; + QString path = QCoreApplication::applicationDirPath() + "/tools/adb/macos/adb"; #endif + static bool checked = false; + if (!checked) { + checked = true; + QFileInfo fi(path); + if (!fi.exists()) { + qWarning() << "[AdbUtils] adb not found at:" << path; + } else if (!fi.isExecutable()) { + qWarning() << "[AdbUtils] adb is not executable:" << path; + } else { + qDebug() << "[AdbUtils] adb path:" << path; + } + } + return path; +} + +QString AdbUtils::adbDir() { + return QFileInfo(adbPath()).absolutePath(); } bool AdbUtils::startProcess(const QString &program, const QStringList &args, QString *stdOut, QString *stdErr) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(program, args); - if (!process.waitForFinished() || + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start process:" << program << args + << "error:" << process.errorString(); + if (stdErr) { + *stdErr = process.errorString(); + } + return false; + } + + if (!process.waitForFinished(30000) || process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { if (stdErr) { *stdErr = QString::fromUtf8(process.readAllStandardError()); } + qWarning() << "[AdbUtils] Process failed:" << program << args + << "exitCode:" << process.exitCode() + << "stderr:" << (stdErr ? *stdErr : QString::fromUtf8(process.readAllStandardError())); return false; } @@ -45,9 +76,36 @@ bool AdbUtils::startProcess(const QString &program, const QStringList &args, * @return [(id, status), ...] */ QList > AdbUtils::getListDevices() { + const QString adb = adbPath(); + const QString dir = adbDir(); + + // Убиваем чужой adb-сервер (возможно другой версии) и запускаем свой, + // чтобы избежать конфликта версий (например, scrcpy adb 35 vs bundled adb 36) + static bool serverRestarted = false; + if (!serverRestarted) { + serverRestarted = true; + QProcess kill; + kill.setWorkingDirectory(dir); + kill.start(adb, {"kill-server"}); + kill.waitForFinished(5000); + qDebug() << "[AdbUtils] Killed existing adb server"; + + QProcess start; + start.setWorkingDirectory(dir); + start.start(adb, {"start-server"}); + start.waitForFinished(10000); + qDebug() << "[AdbUtils] Started own adb server"; + } + QProcess process; - process.start(adbPath(), {"devices"}); - process.waitForFinished(); + process.setWorkingDirectory(dir); + process.start(adb, {"devices"}); + + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb devices:" << process.errorString(); + return {}; + } + process.waitForFinished(10000); const QString output = process.readAllStandardOutput(); QList > devices; @@ -76,10 +134,15 @@ QList > AdbUtils::getListDevices() { QString AdbUtils::tryToGetRunningAppPid(const QString &deviceId, const QString &packageName) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "pidof", packageName }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb pidof:" << process.errorString(); + return {}; + } process.waitForFinished(); QString pid = process.readAllStandardOutput(); return pid.replace("\n", ""); @@ -87,6 +150,7 @@ QString AdbUtils::tryToGetRunningAppPid(const QString &deviceId, const QString & bool AdbUtils::tryToStartApplication(const QString &deviceId, const QString &packageName) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "monkey", @@ -94,6 +158,10 @@ bool AdbUtils::tryToStartApplication(const QString &deviceId, const QString &pac "-c", "android.intent.category.LAUNCHER", "1" }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb monkey:" << process.errorString(); + return false; + } process.waitForFinished(); const QString output = process.readAllStandardOutput(); @@ -110,11 +178,16 @@ bool AdbUtils::tryToStartApplication(const QString &deviceId, const QString &pac bool AdbUtils::tryToKillApplication(const QString &deviceId, const QString &packageName) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "am", "force-stop", packageName }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb force-stop:" << process.errorString(); + return false; + } process.waitForFinished(); return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } @@ -186,7 +259,13 @@ bool AdbUtils::takeScreenshot(const QString &deviceId, const QString &name) { QByteArray AdbUtils::captureScreenshotBytes(const QString &deviceId) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), {"-s", deviceId, "exec-out", "screencap", "-p"}); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] captureScreenshotBytes failed to start for" << deviceId + << "error:" << process.errorString(); + return {}; + } if (!process.waitForFinished(10000) || process.exitCode() != 0) { qWarning() << "[AdbUtils] captureScreenshotBytes failed for" << deviceId; return {}; @@ -217,11 +296,16 @@ bool AdbUtils::takeXmlDump(const QString &deviceId, const QString &name) { bool AdbUtils::makeTap(const QString &deviceId, const int x, const int y) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "input", "tap", QString::number(x), QString::number(y) }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb tap:" << process.errorString(); + return false; + } process.waitForFinished(); return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } @@ -247,12 +331,17 @@ bool AdbUtils::enableAdbIMEKeyboard(const QString &deviceId) { bool AdbUtils::inputAdbIMEText(const QString &deviceId, const QString &text) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "am", "broadcast", "-a", "ADB_INPUT_TEXT", "--es", "msg", text }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb broadcast:" << process.errorString(); + return false; + } process.waitForFinished(); qDebug() << "[AdbUtils] inputAdbIMEText result:" << process.exitCode() << "output:" << process.readAllStandardOutput().trimmed() @@ -262,14 +351,20 @@ bool AdbUtils::inputAdbIMEText(const QString &deviceId, const QString &text) { bool AdbUtils::disableAdbIMEKeyboard(const QString &deviceId) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), {"-s", deviceId, "shell", "ime", "disable", "com.android.adbkeyboard/.AdbIME"}); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb ime disable:" << process.errorString(); + return false; + } process.waitForFinished(); return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } bool AdbUtils::makeSwipe(const QString &deviceId, const int x1, const int y1, const int x2, const int y2) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start( adbPath(), { @@ -280,50 +375,74 @@ bool AdbUtils::makeSwipe(const QString &deviceId, const int x1, const int y1, co QString::number(x2), QString::number(y2) } ); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb swipe:" << process.errorString(); + return false; + } process.waitForFinished(); return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } bool AdbUtils::inputText(const QString &deviceId, const QString &text) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "input", "text", text }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb input text:" << process.errorString(); + return false; + } process.waitForFinished(); return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } bool AdbUtils::hideKeyboard(const QString &deviceId) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "input", "keyevent", "111" }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb keyevent:" << process.errorString(); + return false; + } process.waitForFinished(); return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } bool AdbUtils::goBack(const QString &deviceId) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "input", "keyevent", "4" }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb keyevent:" << process.errorString(); + return false; + } process.waitForFinished(); return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } QSet AdbUtils::getListApps(const QString &deviceId) { QProcess process; + process.setWorkingDirectory(adbDir()); process.start(adbPath(), { "-s", deviceId, "shell", "pm list", "packages", "-3" }); + if (!process.waitForStarted(5000)) { + qWarning() << "[AdbUtils] Failed to start adb pm list:" << process.errorString(); + return {}; + } process.waitForFinished(); const QString output = process.readAllStandardOutput(); diff --git a/android/adb/AdbUtils.h b/android/adb/AdbUtils.h index 5cbbb23..bbd6629 100644 --- a/android/adb/AdbUtils.h +++ b/android/adb/AdbUtils.h @@ -47,6 +47,7 @@ public: static QSet getListApps(const QString &deviceId); private: + static QString adbDir(); static bool startProcess(const QString &program, const QStringList &args, QString *stdOut = nullptr, QString *stdErr = nullptr); }; diff --git a/database/app_data.db b/database/app_data.db deleted file mode 100644 index 1325345..0000000 Binary files a/database/app_data.db and /dev/null differ diff --git a/services/DeviceScreener.cpp b/services/DeviceScreener.cpp index 5248ff8..63fa5ff 100644 --- a/services/DeviceScreener.cpp +++ b/services/DeviceScreener.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -350,10 +351,11 @@ QByteArray convertPngToJpeg(const QByteArray &pngData, const int quality = 90) { QByteArray DeviceScreener::takeScreenshot(const QString &deviceId) { QProcess process; + process.setWorkingDirectory(QFileInfo(AdbUtils::adbPath()).absolutePath()); QStringList arguments; arguments << "-s" << deviceId << "exec-out" << "screencap" << "-p"; - process.start("adb", arguments); + process.start(AdbUtils::adbPath(), arguments); if (!process.waitForFinished(5000)) { qWarning() << "ADB скриншот не завершился для" << deviceId; @@ -372,8 +374,14 @@ QByteArray DeviceScreener::takeScreenshot(const QString &deviceId) { QList > DeviceScreener::readAdbDevices() { QProcess process; - process.start("adb", QStringList() << "devices"); - process.waitForFinished(); + process.setWorkingDirectory(QFileInfo(AdbUtils::adbPath()).absolutePath()); + process.start(AdbUtils::adbPath(), QStringList() << "devices"); + + if (!process.waitForStarted(5000)) { + qWarning() << "[DeviceScreener] Failed to start adb devices:" << process.errorString(); + return {}; + } + process.waitForFinished(10000); const QString output = process.readAllStandardOutput(); QList > devices; @@ -412,7 +420,8 @@ DeviceInfo DeviceScreener::readDeviceInfo(const QString &deviceId, const bool is auto runAdbCommand = [&](const QStringList &args) -> QString { QProcess process; - process.start("adb", QStringList{"-s", deviceId} + args); + process.setWorkingDirectory(QFileInfo(AdbUtils::adbPath()).absolutePath()); + process.start(AdbUtils::adbPath(), QStringList{"-s", deviceId} + args); process.waitForFinished(); return QString::fromUtf8(process.readAllStandardOutput()).trimmed(); };