一、介绍
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控件使用