QProcess如何在同一窗口同一会话中写入执行多条命令
问题原因
你当前的实现每次调用cmd()接口都会新建独立的QProcess实例,启动全新的adb进程执行单条命令,进程运行结束后就自动销毁,会话上下文(包括shell工作目录、权限状态、临时环境变量等)会全部丢失,自然无法实现同一会话下连续执行多条命令的需求。

实现方案
核心逻辑是长期持有一个常驻的交互型adb shell进程,全程只启动一次,后续所有命令都写入这个进程的标准输入执行,再从标准输出读取结果,不需要每次新建进程。
为了避免多命令输出串读,需要给每条执行的命令追加专属结束标记,读到标记就判定当前命令执行完成。
完整实现代码
首先是Adb类的定义:
#include <QObject> #include <QProcess> #include <QDateTime> class Adb : public QObject { Q_OBJECT public: static Adb& instance() { static Adb ins; return ins; } // 初始化常驻adb会话,程序启动时调用一次即可 bool initSession(); // 同会话执行命令,传入命令字符串,返回执行输出结果 QString cmd(const QString &command, int timeoutMs = 3000); // 关闭会话释放资源 void closeSession(); private: Adb() = default; ~Adb() { closeSession(); } QProcess* m_shellProc = nullptr; const QString m_endFlag = "__ADB_CMD_DONE__"; // 命令结束标识,不要和正常输出冲突 };
对应实现逻辑:
bool Adb::initSession() { // 已经有运行中的会话直接返回 if (m_shellProc && m_shellProc->state() == QProcess::Running) { return true; } m_shellProc = new QProcess(this); // 启动交互模式的adb shell m_shellProc->start("adb shell"); if (!m_shellProc->waitForStarted(3000)) { m_shellProc->deleteLater(); m_shellProc = nullptr; return false; } // 关闭shell回显,避免输入的命令本身被当成输出读取 m_shellProc->write("stty -echo\n"); m_shellProc->waitForBytesWritten(500); return true; } QString Adb::cmd(const QString &command, int timeoutMs) { // 会话不存在就先初始化 if (!m_shellProc || m_shellProc->state() != QProcess::Running) { if (!initSession()) return "ADB会话启动失败"; } // 写入命令,同时追加echo结束标识的语句,用来判定命令执行终点 QString execCmd = QString("%1\necho %2\n").arg(command, m_endFlag); m_shellProc->write(execCmd.toUtf8()); m_shellProc->waitForBytesWritten(500); QString totalOutput; qint64 startTime = QDateTime::currentMSecsSinceEpoch(); // 循环读取输出,直到读到结束标识或者触发超时 while (QDateTime::currentMSecsSinceEpoch() - startTime < timeoutMs) { if (m_shellProc->waitForReadyRead(100)) { // 同时读标准输出和标准错误 totalOutput += QString::fromUtf8(m_shellProc->readAllStandardError()); totalOutput += QString::fromUtf8(m_shellProc->readAllStandardOutput()); if (totalOutput.contains(m_endFlag)) { break; } } } // 裁掉结束标识和前后多余空白字符 if (totalOutput.contains(m_endFlag)) { totalOutput = totalOutput.left(totalOutput.indexOf(m_endFlag)).trimmed(); } return totalOutput; } void Adb::closeSession() { if (m_shellProc) { if (m_shellProc->state() == QProcess::Running) { m_shellProc->write("exit\n"); m_shellProc->waitForFinished(1000); m_shellProc->kill(); } m_shellProc->deleteLater(); m_shellProc = nullptr; } }
使用说明
- 程序启动时调用一次
Adb::instance().initSession()初始化会话即可,后续所有命令直接调用cmd()方法,所有操作都在同一个shell会话中执行,cd切换目录、su提权、export设置环境变量等操作的状态都会全程保留 - 结束标识可以自行修改,只要保证不会和业务命令的正常输出内容冲突即可
- 如果需要执行
logcat这类持续输出的长耗时命令,不要用这个同步接口,改为绑定m_shellProc的readyReadStandardOutput信号做异步读取即可,否则会触发超时逻辑 - 如果adb连接意外断开,下次调用
cmd()时会自动尝试重新建立会话 - 不要在会话中直接执行
exit命令,否则会直接终止常驻shell进程
内容的提问来源于stack exchange,提问作者NOOBY SHARP
相关产品推荐
相关产品推荐

