Revised scripts for payments and history retrieval, introducing improved error management with screenshots for debugging. Added a new LoginAndCheckAccountsScript for account validation, streamlined multi-threading, and updated application logic for clarity and reliability.
270 lines
10 KiB
C++
270 lines
10 KiB
C++
#include "AdbUtils.h"
|
||
#include <QProcess>
|
||
#include <qDebug>
|
||
#include <QString>
|
||
|
||
AdbUtils::AdbUtils(QObject *parent) : QObject(parent) {
|
||
}
|
||
|
||
// 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<QPair<QString, QString> > AdbUtils::getListDevices() {
|
||
QProcess process;
|
||
process.start("adb", {"devices"});
|
||
process.waitForFinished();
|
||
|
||
const QString output = process.readAllStandardOutput();
|
||
QList<QPair<QString, QString> > 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("<?xml"); startIndex != -1) {
|
||
xmlBytes = xmlBytes.mid(startIndex); // Обрезаем всё до "<?xml"
|
||
}
|
||
return QString::fromUtf8(xmlBytes);
|
||
}
|
||
|
||
bool AdbUtils::takeScreenshot(const QString &deviceId, const QString &name) {
|
||
QProcess process;
|
||
QString screenshot = QString(
|
||
"adb -s %1 shell 'screencap -p /sdcard/screen.png' && "
|
||
"adb -s %1 pull /sdcard/screen.png %2.png && "
|
||
"adb -s %1 shell 'rm /sdcard/screen.png'"
|
||
).arg(deviceId, name);
|
||
process.start("sh", {"-c", screenshot});
|
||
process.waitForFinished();
|
||
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
|
||
}
|
||
|
||
bool AdbUtils::takeXmlDump(const QString &deviceId, const QString &name) {
|
||
QProcess process;
|
||
QString xml = QString(
|
||
"adb -s %1 shell 'uiautomator dump /sdcard/uidump.xml' && "
|
||
"adb -s %1 pull /sdcard/uidump.xml %2.xml && "
|
||
"adb -s %1 shell 'cat /sdcard/uidump.xml' && "
|
||
"adb -s %1 shell 'rm /sdcard/uidump.xml'"
|
||
).arg(deviceId, name);
|
||
process.start("sh", {"-c", xml});
|
||
process.waitForFinished();
|
||
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
|
||
}
|
||
|
||
bool AdbUtils::makeTap(const QString &deviceId, const int x, const int y) {
|
||
QProcess process;
|
||
process.start("adb", {
|
||
"-s", deviceId,
|
||
"shell", "input",
|
||
"tap", QString::number(x), QString::number(y)
|
||
});
|
||
process.waitForFinished();
|
||
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
|
||
}
|
||
|
||
bool AdbUtils::enableAdbIMEKeyboard(const QString &deviceId) {
|
||
QProcess process;
|
||
QString command = QString(
|
||
"adb -s %1 shell ime enable com.android.adbkeyboard/.AdbIME "
|
||
"&& adb -s %1 shell ime set com.android.adbkeyboard/.AdbIME"
|
||
).arg(deviceId);
|
||
process.start(command);
|
||
process.waitForFinished();
|
||
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
|
||
}
|
||
|
||
bool AdbUtils::inputAdbIMEText(const QString &deviceId, const QString &text) {
|
||
QProcess process;
|
||
QString command = QString(
|
||
"adb -s %1 shell am broadcast -a ADB_INPUT_TEXT --es msg '%2'"
|
||
).arg(deviceId, text);
|
||
process.start(command);
|
||
process.waitForFinished();
|
||
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
|
||
}
|
||
|
||
bool AdbUtils::disableAdbIMEKeyboard(const QString &deviceId) {
|
||
QProcess process;
|
||
QString command = QString(
|
||
"adb -s %1 shell ime disable com.android.adbkeyboard/.AdbIME"
|
||
).arg(deviceId);
|
||
process.start(command);
|
||
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.start(
|
||
"adb",
|
||
{
|
||
"-s", deviceId,
|
||
"shell", "input",
|
||
"swipe", QString("%1 %2 %3 %4").arg(x1).arg(y1).arg(x2).arg(y2)
|
||
}
|
||
);
|
||
process.waitForFinished();
|
||
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
|
||
}
|
||
|
||
bool AdbUtils::inputText(const QString &deviceId, const QString &text) {
|
||
QProcess process;
|
||
process.start("adb", {
|
||
"-s", deviceId,
|
||
"shell", "input",
|
||
"text", text
|
||
});
|
||
process.waitForFinished();
|
||
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
|
||
}
|
||
|
||
bool AdbUtils::goBack(const QString &deviceId) {
|
||
QProcess process;
|
||
process.start("adb", {
|
||
"-s", deviceId,
|
||
"shell", "input",
|
||
"keyevent", "4"
|
||
});
|
||
process.waitForFinished();
|
||
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
|
||
}
|
||
|
||
QSet<QString> 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<QString> 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;
|
||
}
|