从零开始用QT编写一个Android投屏、PC反控软件(一)--ADB基础知识

ADB介绍

GitHub: linkedbyte
Android Debug Bridge(ADB)是一种功能强大的命令行工具,它可以让开发者和设备进行通信。ADB 是由三个部分组成:PC上的 adb client、adb server 和设备上的 adb daemon。这三部分构成了一个多连接的设计,即一台PC可以连接多个设备,一台设备也可以连接多个PC。

当启动 adb 客户端时,它会首先检查 adb 服务端进程是否在运行。如果没有运行,它会启动服务端进程。adb 服务端在启动时,会绑定到本地的 TCP 5037 端口,并监听从 adb 客户端发来的命令——所有的 adb 客户端都使用 5037 端口与 adb 服务端通信。

然后,adb 服务端会扫描所有 5555 到 5585 范围内的奇数端口来定位所有的模拟器或设备,并与之建立连接。一旦 adb 服务端找到了 adb daemon(守护进程),它将建立一个到该端口的连接。这样,开发者就可以使用 adb 命令来控制和访问模拟器或设备了。

设备上的 adb daemon 是一个后台进程,它在 Android 设备或模拟器系统中运行。它的作用是连接 adb 服务器,并且为运行在主机上的客户端提供服务。

投屏软件使用到的ADB命令

  1. adb devices -l

    • 功能:列出当前连接到计算机的所有 Android 设备或模拟器的详细信息。
    • 解释adb devices 命令用于检查是否有设备或模拟器连接到计算机。添加 -l 选项可以提供更详细的信息,例如设备的型号或状态。这对于开发者在调试时确认设备连接非常有用。
  2. adb push

    • 功能:将计算机上的文件或目录复制到连接的 Android 设备上。
    • 解释:使用 adb push 命令,开发者可以将本地计算机上的文件或目录推送到 Android 设备上的指定位置。这对于将测试数据、配置文件或其他资源部署到设备上非常有用。
    • 用法adb push <本地路径> <设备路径>
  3. adb reverse

    • 功能:在 Android 设备与计算机之间设置端口转发。
    • 解释adb reverse 允许开发者将 Android 设备上的某个端口映射到计算机上的端口,从而实现两者之间的通信。这对于在开发过程中需要在设备和计算机之间共享数据或进行调试的应用程序非常有用。
    • 用法adb reverse <设备端口> <计算机端口>
  4. adb shell app_process

    • 功能:在 Android 设备的 shell 中以指定权限运行 Java 应用程序。
    • 解释app_process 是 Android 系统上的一个原生程序,它是 APP 进程的主入口点。通过 adb shell 使用 app_process,开发者可以在设备上以特定用户权限(通常是高权限)运行 Java 程序。这对于需要执行系统级操作或测试应用程序在不同权限环境下的行为非常有用。
    • 用法:通常涉及更复杂的命令行参数和 Java 类路径设置,但基本形式是在 adb shell 内调用 app_process 并传递相应的参数。

使用QProcess执行adb命令

首先,确保你的 Qt 项目包含了必要的头文件,并且链接了相应的 Qt 模块(通常是 core)。

#include <QCoreApplication>
#include <QProcess>
#include <QDebug>

void runAdbDevices() {
    QProcess process;
    QString program = "adb";
    QStringList arguments;

    // 执行 adb devices -l
    arguments << "devices" << "-l";
    process.start(program, arguments);
    process.waitForFinished();
    QString output = QString(process.readAllStandardOutput());
    qDebug() << "adb devices -l output:" << output;
}

void runAdbPush(const QString &localFilePath, const QString &devicePath) {
    QProcess process;
    QString program = "adb";
    QStringList arguments;

    // 执行 adb push
    arguments << "push" << localFilePath << devicePath;
    process.start(program, arguments);
    process.waitForFinished();
    QString output = QString(process.readAllStandardOutput());
    qDebug() << "adb push output:" << output;
}

void runAdbReverse(int devicePort, int hostPort) {
    QProcess process;
    QString program = "adb";
    QStringList arguments;

    // 执行 adb reverse
    arguments << "reverse" << QString("tcp:%1").arg(devicePort) << QString("tcp:%2").arg(hostPort);
    process.start(program, arguments);
    process.waitForFinished();
    QString output = QString(process.readAllStandardOutput());
    qDebug() << "adb reverse output:" << output;
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 调用 adb devices -l
    runAdbDevices();

    // 调用 adb push,假设你要推送一个名为 "myfile.txt" 的文件到设备的 "/sdcard/" 目录下
    runAdbPush("/path/to/myfile.txt", "/sdcard/myfile.txt");

    // 调用 adb reverse,假设你要将设备的 8080 端口映射到主机的 8888 端口
    runAdbReverse(8080, 8888);

    return a.exec();
}

在这段代码中,runAdbDevices 函数执行 adb devices -l 命令,runAdbPush 函数执行 adb push 命令来推送文件,runAdbReverse 函数执行 adb reverse 命令来设置端口转发。每个函数都使用 QProcess 来启动外部程序,并等待其完成。完成后,它们读取并打印命令的输出。

请确保替换 /path/to/myfile.txt 为你要推送的文件的实际路径,并根据需要调整端口号和设备路径。此外,如果你的 adb 不在系统路径中,你需要提供 adb 的完整路径作为 program 变量的值。

使用QProcess异步执行ADB命令

在Qt中,要将QProcess的执行过程换成异步的,你可以使用信号和槽机制。QProcess类提供了一系列的信号,如readyReadStandardOutputfinished等,这些信号可以在进程输出可用或进程结束时发出。你可以将这些信号连接到自定义的槽函数中以异步地处理进程输出和进程结束事件。

下面是一个修改后的例子,展示了如何使用QProcess以异步方式执行adb命令:

#include <QCoreApplication>
#include <QProcess>
#include <QObject>
#include <QDebug>

class AdbProcess : public QObject {
    Q_OBJECT
public:
    AdbProcess(QObject *parent = nullptr) : QObject(parent) {}

    void runAdbCommand(const QString &command) {
        adbProcess->start("adb", QStringList() << command);
    }

    void runAdbDevices() {
        runAdbCommand("devices -l");
    }

    void runAdbPush(const QString &localFile, const QString &remoteDest) {
        QStringList args = {"push", localFile, remoteDest};
        adbProcess->start("adb", args);
    }

    void runAdbReverse(int localPort, int remotePort) {
        QStringList args = {"reverse", QString("tcp:%1").arg(localPort), QString("tcp:%2").arg(remotePort)};
        adbProcess->start("adb", args);
    }

private slots:
    void onReadyReadStandardOutput() {
        QByteArray output = adbProcess->readAllStandardOutput();
        qDebug() << "ADB Output:" << output;
    }

    void onFinished(int exitCode, QProcess::ExitStatus exitStatus) {
        qDebug() << "ADB Command Finished"
                 << "Exit Code:" << exitCode
                 << "Exit Status:" << exitStatus;
        adbProcess->deleteLater();
    }

private:
    QProcess *adbProcess = new QProcess(this);

    void setupProcess() {
        connect(adbProcess, &QProcess::readyReadStandardOutput, this, &AdbProcess::onReadyReadStandardOutput);
        connect(adbProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &AdbProcess::onFinished);
    }

public:
    // 构造函数中设置进程
    AdbProcess(bool setup = true, QObject *parent = nullptr) : QObject(parent) {
        if (setup) {
            setupProcess();
        }
    }
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    AdbProcess adb;
    adb.runAdbDevices();

    // 这里可以添加更多的 adb 命令或者其他逻辑
    // ...

    return a.exec();
}

在这个例子中,AdbProcess 类封装了对 adb 命令的异步调用。构造函数中设置了必要的信号和槽连接。runAdbCommand 方法是一个私有方法,用于启动进程并执行特定的 adb 命令。onReadyReadStandardOutputonFinished 是槽函数,分别用于处理进程的标准输出和进程结束事件。

注意,这里的代码假设你的 adb 命令已经在系统路径中。如果不是,你需要提供 adb 可执行文件的完整路径。

此外,请确保在实际的项目中正确地管理 QProcess 对象的生命周期。在这个示例中,adbProcess 对象在 AdbProcess 类中被创建,并在命令执行完毕后通过 deleteLater 方法进行清理。如果你的应用程序需要在多处执行 adb 命令,你可能需要为每个命令创建一个新的 QProcess 对象,或者确保在命令之间重置 QProcess 对象的状态。

GitHub: linkedbyte

微信:linkedbyte
QQ:2276769057

  • 34
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值