PYTHON3 之 小工具(PyQt5-Pyinstaller-subprocess-ADB)
一、介绍
1、工具目标:
1)执行adb devices,shell,root,pull命令;
2)有图形界面,可以傻瓜式操作
2、方法:
经过技术可行性分析,可以使用python3,PyQt5,pyinstaller,subprocess.run,adb等技术实现目标
3、原理:使用python3 执行 adb相关命令,用PyQt5制作显示界面
二、工具
1、界面
先看看界面,使用的控件:groupBox,pushButton,comboBox,lineEdit,toolButton,label,textBrowser,
使用Qt Desiger布置界面,然后转化成python代码
2、代码
1)界面py,文件名LOG_TOOL_UI.ui
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'LOG_TOOL_UI.ui' # # Created by: PyQt5 UI code generator 5.14.2 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(410, 410) MainWindow.setMinimumSize(QtCore.QSize(410, 410)) MainWindow.setMaximumSize(QtCore.QSize(410, 410)) MainWindow.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.groupBox_setting = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_setting.setGeometry(QtCore.QRect(10, 10, 391, 61)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.groupBox_setting.setFont(font) self.groupBox_setting.setObjectName("groupBox_setting") self.pushButton_devices = QtWidgets.QPushButton(self.groupBox_setting) self.pushButton_devices.setGeometry(QtCore.QRect(20, 20, 75, 30)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.pushButton_devices.setFont(font) self.pushButton_devices.setObjectName("pushButton_devices") self.pushButton_root = QtWidgets.QPushButton(self.groupBox_setting) self.pushButton_root.setGeometry(QtCore.QRect(120, 20, 75, 30)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.pushButton_root.setFont(font) self.pushButton_root.setObjectName("pushButton_root") self.pushButton_cmd = QtWidgets.QPushButton(self.groupBox_setting) self.pushButton_cmd.setGeometry(QtCore.QRect(220, 20, 75, 30)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.pushButton_cmd.setFont(font) self.pushButton_cmd.setObjectName("pushButton_cmd") self.groupBox_option = QtWidgets.QGroupBox(self.centralwidget) self.groupBox_option.setEnabled(True) self.groupBox_option.setGeometry(QtCore.QRect(10, 80, 391, 311)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.groupBox_option.setFont(font) self.groupBox_option.setTabletTracking(False) self.groupBox_option.setAcceptDrops(False) self.groupBox_option.setFlat(False) self.groupBox_option.setCheckable(False) self.groupBox_option.setObjectName("groupBox_option") self.comboBox_option_log = QtWidgets.QComboBox(self.groupBox_option) self.comboBox_option_log.setGeometry(QtCore.QRect(20, 20, 171, 25)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.comboBox_option_log.setFont(font) self.comboBox_option_log.setMouseTracking(False) self.comboBox_option_log.setEditable(False) self.comboBox_option_log.setMaxVisibleItems(5) self.comboBox_option_log.setObjectName("comboBox_option_log") self.comboBox_option_log.addItem("") self.comboBox_option_log.addItem("") self.comboBox_option_log.addItem("") self.comboBox_option_log.addItem("") self.comboBox_option_log.addItem("") self.lineEdit_folderpath = QtWidgets.QLineEdit(self.groupBox_option) self.lineEdit_folderpath.setGeometry(QtCore.QRect(20, 70, 241, 25)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.lineEdit_folderpath.setFont(font) self.lineEdit_folderpath.setObjectName("lineEdit_folderpath") self.toolButton_filepath = QtWidgets.QToolButton(self.groupBox_option) self.toolButton_filepath.setGeometry(QtCore.QRect(260, 70, 41, 25)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.toolButton_filepath.setFont(font) self.toolButton_filepath.setObjectName("toolButton_filepath") self.pushButton_export = QtWidgets.QPushButton(self.groupBox_option) self.pushButton_export.setGeometry(QtCore.QRect(310, 66, 61, 31)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.pushButton_export.setFont(font) self.pushButton_export.setObjectName("pushButton_export") self.labelFilePath = QtWidgets.QLabel(self.groupBox_option) self.labelFilePath.setGeometry(QtCore.QRect(20, 50, 71, 21)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.labelFilePath.setFont(font) self.labelFilePath.setObjectName("labelFilePath") self.label = QtWidgets.QLabel(self.groupBox_option) self.label.setGeometry(QtCore.QRect(20, 100, 61, 31)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.label.setFont(font) self.label.setObjectName("label") self.textBrowser_logging = QtWidgets.QTextBrowser(self.groupBox_option) self.textBrowser_logging.setGeometry(QtCore.QRect(20, 130, 351, 171)) font = QtGui.QFont() font.setFamily("SimSun") font.setPointSize(10) self.textBrowser_logging.setFont(font) self.textBrowser_logging.setObjectName("textBrowser_logging") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 410, 21)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) self.comboBox_option_log.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.groupBox_setting.setTitle(_translate("MainWindow", "Setting")) self.pushButton_devices.setText(_translate("MainWindow", "devices")) self.pushButton_root.setText(_translate("MainWindow", "root")) self.pushButton_cmd.setText(_translate("MainWindow", "cmd")) self.groupBox_option.setTitle(_translate("MainWindow", "Option")) self.comboBox_option_log.setCurrentText(_translate("MainWindow", "tbox_message")) self.comboBox_option_log.setItemText(0, _translate("MainWindow", "tbox_message")) self.comboBox_option_log.setItemText(1, _translate("MainWindow", "ota_log")) self.comboBox_option_log.setItemText(2, _translate("MainWindow", "ota_data")) self.comboBox_option_log.setItemText(3, _translate("MainWindow", "ds_logcat")) self.comboBox_option_log.setItemText(4, _translate("MainWindow", "xf_logcat")) self.toolButton_filepath.setText(_translate("MainWindow", "...")) self.pushButton_export.setText(_translate("MainWindow", "export")) self.labelFilePath.setText(_translate("MainWindow", "log path:")) self.label.setText(_translate("MainWindow", "Logging:")) #button self.pushButton_devices.clicked.connect(MainWindow.adb_devices) self.pushButton_root.clicked.connect(MainWindow.adb_root) self.pushButton_cmd.clicked.connect(MainWindow.cmd_windows) self.pushButton_export.clicked.connect(MainWindow.export_log) self.toolButton_filepath.clicked.connect(MainWindow.set_log_folder_path)
2)核心!!!,实现adb相关命令,文件名LOG_TOOL.py
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys import threading import subprocess from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog from LOG_TOOL_UI import * class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) #log folder path temp_path = 'C:/Users/Administrator/Downloads' #CMD命令-变量 global CMD_IVI_OTA_DATA_MKDIR global CMD_IVI_OTA_DATA_RM global CMD_IVI_OTA_LOG_MKDIR global CMD_IVI_OTA_LOG_RM global CMD_IVI_TBOX_MESSAGES_MKDIR global CMD_IVI_TBOX_MESSAGES_RM global CMD_ADB_SHELL_MODE_EXIT global CMD_XF_IVI_LOGCAT_TO_PC global CMD_DS_IVI_LOGCAT_TO_PC global CMD_OTA_DATA_TO_IVI global CMD_OTA_DATA_TO_PC global CMD_OTA_LOG_TO_IVI global CMD_OTA_LOG_TO_PC global CMD_TBOX_MESSAGES_TO_IVI global CMD_TBOX_MESSAGES0_TO_IVI global CMD_TBOX_MESSAGES_TO_PC #cmd命令 #初始化global部分略 #set log folder self.lineEdit_folderpath.setText(temp_path) #设置log path def set_log_folder_path(self): temp_path = self.lineEdit_folderpath.text() log_folder_path = QFileDialog.getExistingDirectory(self, directory = temp_path) if '' == log_folder_path : self.lineEdit_folderpath.setText(temp_path) else : self.lineEdit_folderpath.setText(log_folder_path) #打印日志 def out_put_write(self, text): # self.textBrowserLogging.setText(info) cursor = self.textBrowser_logging.textCursor() cursor.movePosition(QtGui.QTextCursor.End) cursor.insertText(text) self.textBrowser_logging.setTextCursor(cursor) self.textBrowser_logging.ensureCursorVisible() #adb devices def adb_devices(self): res_devices = subprocess.run('adb devices', shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines = True) if '' == res_devices.stderr : print('\n------设备信息!------\n') self.out_put_write('\n------设备信息!------\n') print(res_devices.stdout) self.out_put_write(res_devices.stdout) else : print(res_devices.stderr) self.out_put_write(res_devices.stderr) print('\n------获取设备信息失败!------\n') self.out_put_write('\n------获取设备信息失败!------\n') #adb root def adb_root(self): res_root = subprocess.run('adb root', shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines=True) if '' == res_root.stderr : print(res_root.stdout) self.out_put_write(res_root.stdout) print('\n------ROOT成功!------\n') self.out_put_write('\n------ROOT成功!------\n') else : print(res_root.stderr) self.out_put_write(res_root.stderr) print('\n------ROOT失败!------\n') self.out_put_write('\n------ROOT失败!------\n') #adb shell def cmd_windows(self): res_cmd_windows = subprocess.run('start cmd.exe', shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines=True) if '' != res_cmd_windows.stderr : print(res_cmd_windows.stderr) self.out_put_write(res_cmd_windows.stderr) print('\n------cmd打开失败!------\n') self.out_put_write('\n------cmd打开失败!------\n') #导出ivi log def export_ds_ivi_logcat(self): print('\n------ivi_logcat开始传输...------\n') self.out_put_write('\n------ivi_logcat开始传输...------\n') # cmd_export_ds_ivi_logcat = CMD_DS_IVI_LOGCAT_TO_PC try: res_ds_ivi_logcat = subprocess.Popen(CMD_DS_IVI_LOGCAT_TO_PC, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) while res_ds_ivi_logcat.poll() == None: ds_ivi_logcat_info = res_ds_ivi_logcat.stdout.readline() self.out_put_write(ds_ivi_logcat_info) if res_ds_ivi_logcat.returncode : print('\n------ivi_logcat传输失败!------\n') self.out_put_write('\n------ivi_logcat传输失败!------\n') subprocess.CalledProcessError(res_ds_ivi_logcat.returncode, res_ds_ivi_logcat) else : print('\n------ivi_logcat传输完成!------\n') self.out_put_write('\n------ivi_logcat传输完成!------\n') except Exception as e: print(e) # 导出ivi log def export_xf_ivi_logcat(self): print('\n------ivi_logcat开始传输...------\n') self.out_put_write('\n------ivi_logcat开始传输...------\n') # cmd_export_ga_ivi_logcat = CMD_GA_IVI_LOGCAT_TO_PC try: res_xf_ivi_logcat = subprocess.Popen(CMD_XF_IVI_LOGCAT_TO_PC, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) while res_xf_ivi_logcat.poll() == None: ga_ivi_logcat_info = res_xf_ivi_logcat.stdout.readline() self.out_put_write(ga_ivi_logcat_info) if res_xf_ivi_logcat.returncode : print('\n------ivi_logcat传输失败!------\n') self.out_put_write('\n------ivi_logcat传输失败!------\n') subprocess.CalledProcessError(res_xf_ivi_logcat.returncode, res_xf_ivi_logcat) else : print('\n------ivi_logcat传输完成!------\n') self.out_put_write('\n------ivi_logcat传输完成!------\n') except Exception as e: print(e) ''' res_ga_ivi_logcat = subprocess.run(CMD_GA_IVI_LOGCAT_TO_PC, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines = True) if '' == res_ga_ivi_logcat.stderr : print(res_ga_ivi_logcat.stdout) self.out_put_write(res_ga_ivi_logcat.stdout) print('\n------ivi_logcat传输完成!------\n') self.out_put_write('\n------ivi_logcat传输完成!------\n') else : print(res_ga_ivi_logcat.stderr) self.out_put_write(res_ga_ivi_logcat.stderr) print('\n------ivi_logcat传输失败!------\n') self.out_put_write('\n------ivi_logcat传输失败!------\n') ''' # 导出tbox messages def export_tbox_messages(self): print('\n------tbox_messages开始传输...------\n') self.out_put_write('\n------tbox_messages开始传输...------\n') cmd_export_tbox_messages = CMD_IVI_TBOX_MESSAGES_RM + ' & ' + CMD_IVI_TBOX_MESSAGES_MKDIR + ' && ' + \ CMD_TBOX_MESSAGES_TO_IVI + ' && ' + CMD_TBOX_MESSAGES0_TO_IVI + ' && ' + \ CMD_TBOX_MESSAGES_TO_PC + ' && ' + CMD_IVI_TBOX_MESSAGES_RM try: res_tbox_messages = subprocess.Popen(cmd_export_tbox_messages, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) while res_tbox_messages.poll() == None: tbox_messages_info = res_tbox_messages.stdout.readline() self.out_put_write(tbox_messages_info) if res_tbox_messages.returncode : print('\n------tbox_messages传输失败!------\n') self.out_put_write('\n------tbox_messages传输失败!------\n') subprocess.CalledProcessError(res_tbox_messages.returncode, res_tbox_messages) else : print('\n------tbox_messages传输完成!------\n') self.out_put_write('\n------tbox_messages传输完成!------\n') except Exception as e: print(e) ''' res_tbox_messages = subprocess.run(cmd_export_tbox_messages, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines = True) if '' == res_tbox_messages.stderr : print(res_tbox_messages.stdout) self.out_put_write(res_tbox_messages.stdout) print('\n------tbox_messages传输完成!------\n') self.out_put_write('\n------tbox_messages传输完成!------\n') else : print(res_tbox_messages.stderr) self.out_put_write(res_tbox_messages.stderr) print('\n------tbox_messages传输失败!------\n') self.out_put_write('\n------tbox_messages传输失败!------\n') ''' # 导出ota log def export_ota_log(self): print('\n------ota_log开始传输...------\n') self.out_put_write('\n------ota_log开始传输...------\n') cmd_export_ota_log = CMD_IVI_OTA_LOG_RM + ' & ' + CMD_IVI_OTA_LOG_MKDIR + ' && ' + \ CMD_OTA_LOG_TO_IVI + ' && ' + CMD_OTA_LOG_TO_PC + ' && ' + CMD_IVI_OTA_LOG_RM try: res_ota_log = subprocess.Popen(cmd_export_ota_log, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines=True) while res_ota_log.poll() == None: ota_log_info = res_ota_log.stdout.readline() self.out_put_write(ota_log_info) if res_ota_log.returncode: print('\n------ota_log传输失败!------\n') self.out_put_write('\n------ota_log传输失败!------\n') subprocess.CalledProcessError(res_ota_log.returncode, res_ota_log) else: print('\n------ota_log传输成功!------\n') self.out_put_write('\n------ota_log传输成功!------\n') except Exception as e: print(e) # 导出ota data def export_ota_data(self): print('\n------ota_data开始传输...------\n') self.out_put_write('\n------ota_data开始传输...------\n') cmd_export_ota_data = CMD_IVI_OTA_DATA_RM + ' && ' + CMD_IVI_OTA_DATA_MKDIR + ' && ' + \ CMD_OTA_DATA_TO_IVI + ' && ' + CMD_OTA_DATA_TO_PC + ' && ' + CMD_IVI_OTA_DATA_RM try: res_ota_data = subprocess.Popen(cmd_export_ota_data, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, universal_newlines=True) while res_ota_data.poll() == None: ota_data_info = res_ota_data.stdout.readline() self.out_put_write(ota_data_info) if res_ota_data.returncode: print('\n------ota_data传输失败!------\n') self.out_put_write('\n------ota_data传输失败!------\n') subprocess.CalledProcessError(res_ota_data.returncode, res_ota_data) else: print('\n------ota_data传输完成!------\n') self.out_put_write('\n------ota_data传输完成!------\n') except Exception as e: print(e) # 导出log def export_log(self): # temp_path = self.lineEdit_folderpath.text() get_log_type = self.comboBox_option_log.currentText() if get_log_type == 'ota_log' : threading.Thread(target=self.export_ota_log).start() elif get_log_type == 'tbox_messages' : threading.Thread(target=self.export_tbox_messages).start() elif get_log_type == 'ds_logcat' : threading.Thread(target=self.export_ds_ivi_logcat).start() elif get_log_type == 'xf_logcat' : threading.Thread(target=self.export_xf_ivi_logcat).start() elif get_log_type == 'ota_data' : threading.Thread(target=self.export_ota_data).start() else : print('\n------传输失败!!!------\n') self.out_put_write('\n------传输失败!!!------\n') if __name__ == '__main__': # multiprocessing.freeze_support() app = QApplication(sys.argv) ToolWindow = MainWindow() ToolWindow.show() sys.exit(app.exec_())
三、遇到的问题(最重要)
1、PyQt5/PyInstaller安装尽量用pip命令在线安装
2、subprocess执行多个adb命令的方法,使用 && 连接命令
3、pyinstaller最好打包成文件夹(-Dw),不要打包成exe可执行文件(-Fw)
4、threading.Thread().start()解决界面没有响应问题
5、PyQt5控件使用