#include "AdbUtils.h" #include #include #include #include AdbUtils::AdbUtils(QObject *parent) : QObject(parent) { } QString AdbUtils::adbPath() { #ifdef Q_OS_WIN return QCoreApplication::applicationDirPath() + "/tools/adb/adb.exe"; #else return QCoreApplication::applicationDirPath() + "/tools/adb/macos/adb"; #endif } // adb shell dumpsys package ru.rshb.dbo | grep permission // TODO доделать обработку пермишинов // adb shell pm revoke ru.rshb.dbo android.permission.WRITE_CONTACTS; adb shell pm revoke ru.rshb.dbo android.permission.READ_CONTACTS; adb shell pm revoke ru.rshb.dbo android.permission.ACCESS_COARSE_LOCATION; adb shell pm revoke ru.rshb.dbo android.permission.ACCESS_FINE_LOCATION // adb shell cmd appops set ru.rshb.dbo POST_NOTIFICATION ignore /** * Возвращает список найденных устройств в виде пар (ID устройства и Статус) * @return [(id, status), ...] */ QList > AdbUtils::getListDevices() { QProcess process; process.start("adb", {"devices"}); process.waitForFinished(); const QString output = process.readAllStandardOutput(); QList > devices; const QStringList lines = output.split('\n'); for (int i = 1; i < lines.size(); ++i) { QString line = lines.at(i).trimmed(); if (line.isEmpty()) { continue; } /** * device — устройство готово к использованию. * offline — устройство подключено, но не может быть использовано. * unauthorized — устройство не авторизовано для работы с ADB (нужно подтвердить запрос на подключение на самом устройстве). * recovery — устройство в режиме восстановления. */ if (QStringList parts = line.split('\t'); parts.size() == 2) { const QString &id = parts.at(0); const QString &status = parts.at(1); devices.append(qMakePair(id, status)); } } return devices; } QString AdbUtils::tryToGetRunningAppPid(const QString &deviceId, const QString &packageName) { QProcess process; process.start("adb", { "-s", deviceId, "shell", "pidof", packageName }); process.waitForFinished(); QString pid = process.readAllStandardOutput(); return pid.replace("\n", ""); } bool AdbUtils::tryToStartApplication(const QString &deviceId, const QString &packageName) { QProcess process; process.start("adb", { "-s", deviceId, "shell", "monkey", "-p", packageName, "-c", "android.intent.category.LAUNCHER", "1" }); process.waitForFinished(); const QString output = process.readAllStandardOutput(); // Если процесс запустился, там будет такая строка. // Если нет, то: "** No activities found to run, monkey aborted." if (output.contains("Events injected: 1")) { return true; } // Тут надо в логи писать, почему не стартует qDebug() << "Start app output:" << output; return false; } bool AdbUtils::tryToKillApplication(const QString &deviceId, const QString &packageName) { QProcess process; process.start("adb", { "-s", deviceId, "shell", "am", "force-stop", packageName }); process.waitForFinished(); return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } // idx - временный лог // adb -s 6edc4a47 shell 'uiautomator dump /sdcard/uidump.xml' && adb -s 6edc4a47 pull /sdcard/uidump.xml step_1.xml && adb -s 6edc4a47 shell 'rm /sdcard/uidump.xml' QString AdbUtils::getScreenDumpAsXml(const QString &deviceId, const int idx, const bool screenshot) { // TODO убрать логирование в xml файл // "adb -s %1 pull /sdcard/uidump.xml step_%2.xml && " QProcess process; QString xml; if (screenshot) { xml = QString( "adb -s %1 shell 'uiautomator dump /sdcard/uidump.xml' && " "adb -s %1 pull /sdcard/uidump.xml step_%2.xml && " "adb -s %1 shell 'cat /sdcard/uidump.xml' && " "adb -s %1 shell 'rm /sdcard/uidump.xml'" ).arg(deviceId, QString::number(idx)); } else { xml = QString( "adb -s %1 shell 'uiautomator dump /sdcard/uidump.xml' && " "adb -s %1 shell 'cat /sdcard/uidump.xml' && " "adb -s %1 shell 'rm /sdcard/uidump.xml'" ).arg(deviceId); } process.start("sh", {"-c", xml}); process.waitForFinished(); if (screenshot) { // TODO делаем скрин, убрать потом // adb -s 6edc4a47 shell 'screencap -p /sdcard/screen.png' && adb -s 6edc4a47 pull /sdcard/screen.png screen_step_1.png && adb -s 6edc4a47 shell 'rm /sdcard/screen.png' QProcess processScreenshot; QString screenshot = QString( "adb -s %1 shell 'screencap -p /sdcard/screen.png' && " "adb -s %1 pull /sdcard/screen.png screen_step_%2.png && " "adb -s %1 shell 'rm /sdcard/screen.png'" ).arg(deviceId, QString::number(idx)); processScreenshot.start("sh", {"-c", screenshot}); processScreenshot.waitForFinished(); } // чтобы убедиться, что мы прочитали без ошибок if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { return {}; } QByteArray xmlBytes = process.readAllStandardOutput(); // UI hierchary dumped to: /sdcard/uidump.xml\n if (const int startIndex = xmlBytes.indexOf(" AdbUtils::getListApps(const QString &deviceId) { QProcess process; process.start("adb", { "-s", deviceId, "shell", "pm list", "packages", "-3" }); process.waitForFinished(); const QString output = process.readAllStandardOutput(); QSet apps; const QStringList lines = output.split("\n"); for (int i = 0; i < lines.size(); ++i) { QString line = lines.at(i).trimmed().replace("package:", ""); if (line.isEmpty()) { continue; } apps.insert(line); } return apps; }