mirror of
https://github.com/Dev-Wiki/HarmonyDevTools.git
synced 2025-08-31 01:54:44 +08:00
增加python版本
This commit is contained in:
parent
1f15856a68
commit
c903a9e444
106
HarmonyDevTools_Python/.gitignore
vendored
Normal file
106
HarmonyDevTools_Python/.gitignore
vendored
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
# Python运行时文件
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# 分发/打包
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# 单元测试/覆盖率报告
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# 翻译
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# 项目特定文件
|
||||||
|
config.json
|
||||||
|
harmony_dev_tools.log
|
||||||
|
*.exe
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# 导出目录(时间戳格式)
|
||||||
|
[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9][0-9]/
|
183
HarmonyDevTools_Python/README_Python.md
Normal file
183
HarmonyDevTools_Python/README_Python.md
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
# HarmonyDevTools - Python版本
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
本项目为HarmonyOS/OpenHarmony的 toolchains 工具提供Python Tkinter UI操作界面,方便使用。
|
||||||
|
|
||||||
|
## 1. 版本说明
|
||||||
|
|
||||||
|
这是原C# WPF项目的Python Tkinter版本,保持了相同的功能特性:
|
||||||
|
|
||||||
|
hdc功能支持:
|
||||||
|
- 枚举设备/连接设备
|
||||||
|
- 重启hdc
|
||||||
|
- 版本信息显示
|
||||||
|
- 安装、卸载应用
|
||||||
|
- 导出照片
|
||||||
|
- 获取手机的UDID
|
||||||
|
- 其他命令的执行(手动输入执行)
|
||||||
|
|
||||||
|
## 2. 环境要求
|
||||||
|
|
||||||
|
- Python 3.7+
|
||||||
|
- Windows操作系统
|
||||||
|
- HarmonyOS/OpenHarmony SDK(包含toolchains目录)
|
||||||
|
|
||||||
|
## 3. 安装和运行
|
||||||
|
|
||||||
|
### 3.1 直接运行
|
||||||
|
|
||||||
|
1. 确保已安装Python 3.7或更高版本
|
||||||
|
2. 下载项目文件
|
||||||
|
3. 确保`toolchains`目录包含`hdc.exe`文件
|
||||||
|
4. 运行主程序:
|
||||||
|
|
||||||
|
**方式一:使用启动脚本(推荐)**
|
||||||
|
```bash
|
||||||
|
run.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
**方式二:直接运行Python文件**
|
||||||
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 安装依赖(可选)
|
||||||
|
|
||||||
|
如果需要额外的功能,可以安装可选依赖:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 打包为exe文件
|
||||||
|
|
||||||
|
### 4.1 使用项目自带的构建脚本(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 运行构建脚本
|
||||||
|
python build.py
|
||||||
|
```
|
||||||
|
|
||||||
|
构建脚本会:
|
||||||
|
- 自动检查PyInstaller是否安装
|
||||||
|
- 自动清理之前的构建文件
|
||||||
|
- 构建HarmonyDevTools.exe
|
||||||
|
- 自动创建完整的发布包
|
||||||
|
- 生成启动脚本和说明文档
|
||||||
|
|
||||||
|
### 4.2 使用PyInstaller手动打包
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 安装PyInstaller
|
||||||
|
pip install pyinstaller
|
||||||
|
|
||||||
|
# 打包为exe文件
|
||||||
|
pyinstaller --onefile --windowed --name HarmonyDevTools main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 使用auto-py-to-exe(GUI工具)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 安装auto-py-to-exe
|
||||||
|
pip install auto-py-to-exe
|
||||||
|
|
||||||
|
# 启动GUI打包工具
|
||||||
|
auto-py-to-exe
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
HarmonyDevTools_Python/
|
||||||
|
├── main.py # 主程序文件
|
||||||
|
├── requirements.txt # Python依赖文件
|
||||||
|
├── README_Python.md # 说明文档
|
||||||
|
├── toolchains/ # 工具链目录
|
||||||
|
│ ├── hdc.exe # HDC工具
|
||||||
|
│ └── libusb_shared.dll
|
||||||
|
└── build/ # 打包输出目录(可选)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. 功能说明
|
||||||
|
|
||||||
|
### 6.1 设备管理
|
||||||
|
- **列举设备**: 显示所有可用的HarmonyOS设备
|
||||||
|
- **连接设备**: 通过connect key连接指定设备
|
||||||
|
- **重启hdc**: 重启HDC服务
|
||||||
|
|
||||||
|
### 6.2 应用管理
|
||||||
|
- **安装hap**: 安装HarmonyOS应用包
|
||||||
|
- 替换安装: 覆盖已存在的应用
|
||||||
|
- 允许降级: 允许安装较低版本
|
||||||
|
- 动态授权: 动态授权安装
|
||||||
|
- **卸载应用**: 根据包名卸载应用
|
||||||
|
|
||||||
|
### 6.3 文件操作
|
||||||
|
- **导出照片**: 从设备导出照片到本地
|
||||||
|
- **自定义命令**: 执行任意hdc命令
|
||||||
|
|
||||||
|
### 6.4 系统信息
|
||||||
|
- **版本信息**: 显示HDC版本信息
|
||||||
|
- **UDID**: 获取设备唯一标识符
|
||||||
|
|
||||||
|
## 7. 与原C#版本的对比
|
||||||
|
|
||||||
|
| 特性 | C# WPF版本 | Python Tkinter版本 |
|
||||||
|
|------|------------|-------------------|
|
||||||
|
| 运行环境 | .NET Core 6.0 | Python 3.7+ |
|
||||||
|
| UI框架 | WPF | Tkinter |
|
||||||
|
| 打包大小 | 较大 | 较小 |
|
||||||
|
| 跨平台 | Windows | Windows/Linux/macOS |
|
||||||
|
| 开发难度 | 中等 | 简单 |
|
||||||
|
| 维护成本 | 中等 | 低 |
|
||||||
|
|
||||||
|
## 8. 故障排除
|
||||||
|
|
||||||
|
### 8.1 常见问题
|
||||||
|
|
||||||
|
1. **找不到hdc.exe**
|
||||||
|
- 确保`toolchains`目录存在且包含`hdc.exe`
|
||||||
|
- 检查文件路径是否正确
|
||||||
|
|
||||||
|
2. **Python未安装**
|
||||||
|
- 从[Python官网](https://www.python.org/downloads/)下载并安装Python
|
||||||
|
|
||||||
|
3. **tkinter模块错误**
|
||||||
|
- 大多数Python安装都包含tkinter
|
||||||
|
- 如果缺失,请重新安装Python并确保选中tkinter选项
|
||||||
|
|
||||||
|
### 8.2 日志查看
|
||||||
|
|
||||||
|
程序运行时会输出日志信息,可以通过查看控制台输出来诊断问题。
|
||||||
|
|
||||||
|
## 9. 开发说明
|
||||||
|
|
||||||
|
### 9.1 代码结构
|
||||||
|
|
||||||
|
- `HdcUtil`: HDC工具类,负责执行命令
|
||||||
|
- `HarmonyDevTools`: 主界面类,负责UI交互
|
||||||
|
- `main()`: 程序入口函数
|
||||||
|
|
||||||
|
### 9.2 扩展功能
|
||||||
|
|
||||||
|
如需添加新功能,可以:
|
||||||
|
|
||||||
|
1. 在`HdcUtil`类中添加新的静态方法
|
||||||
|
2. 在`HarmonyDevTools`类中添加对应的UI元素和事件处理
|
||||||
|
3. 更新UI布局
|
||||||
|
|
||||||
|
## 10. 许可证
|
||||||
|
|
||||||
|
本项目遵循原项目的许可证条款。
|
||||||
|
|
||||||
|
## 11. 贡献
|
||||||
|
|
||||||
|
欢迎提交Issue和Pull Request来改进这个项目。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**注意**: 使用前请确保已正确安装HarmonyOS/OpenHarmony SDK,并且`toolchains`目录包含所需的工具文件。
|
213
HarmonyDevTools_Python/build.py
Normal file
213
HarmonyDevTools_Python/build.py
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
HarmonyDevTools Python版本打包脚本
|
||||||
|
用于将Python项目打包为exe文件
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def check_pyinstaller():
|
||||||
|
"""检查PyInstaller是否已安装"""
|
||||||
|
try:
|
||||||
|
import PyInstaller
|
||||||
|
return True
|
||||||
|
except ImportError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def install_pyinstaller():
|
||||||
|
"""安装PyInstaller"""
|
||||||
|
print("正在安装PyInstaller...")
|
||||||
|
try:
|
||||||
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
|
||||||
|
print("PyInstaller安装成功!")
|
||||||
|
return True
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print("PyInstaller安装失败!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def build_exe():
|
||||||
|
"""构建exe文件"""
|
||||||
|
print("开始构建exe文件...")
|
||||||
|
|
||||||
|
# 检查主程序文件是否存在
|
||||||
|
if not os.path.exists("main.py"):
|
||||||
|
print("错误:找不到main.py文件!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
main_file = "main.py"
|
||||||
|
exe_name = "HarmonyDevTools"
|
||||||
|
print("构建HarmonyDevTools...")
|
||||||
|
|
||||||
|
# 检查toolchains目录是否存在
|
||||||
|
if not os.path.exists("toolchains"):
|
||||||
|
print("警告:找不到toolchains目录,请确保包含hdc.exe文件")
|
||||||
|
|
||||||
|
# 构建命令
|
||||||
|
cmd = [
|
||||||
|
"pyinstaller",
|
||||||
|
"--onefile", # 打包为单个文件
|
||||||
|
"--windowed", # 无控制台窗口
|
||||||
|
f"--name={exe_name}", # 输出文件名
|
||||||
|
"--icon=icon.ico", # 图标文件(如果存在)
|
||||||
|
"--add-data=toolchains;toolchains", # 包含toolchains目录
|
||||||
|
main_file
|
||||||
|
]
|
||||||
|
|
||||||
|
# 如果图标文件不存在,移除图标参数
|
||||||
|
if not os.path.exists("icon.ico"):
|
||||||
|
cmd = [arg for arg in cmd if not arg.startswith("--icon")]
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
print("构建成功!")
|
||||||
|
return exe_name
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"构建失败:{e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def create_distribution(exe_name="HarmonyDevTools"):
|
||||||
|
"""创建发布包"""
|
||||||
|
print("创建发布包...")
|
||||||
|
|
||||||
|
# 直接使用dist目录作为发布目录
|
||||||
|
dist_dir = "dist"
|
||||||
|
if not os.path.exists(dist_dir):
|
||||||
|
os.makedirs(dist_dir)
|
||||||
|
|
||||||
|
# 复制toolchains目录到dist
|
||||||
|
if os.path.exists("toolchains"):
|
||||||
|
toolchains_dest = os.path.join(dist_dir, "toolchains")
|
||||||
|
if os.path.exists(toolchains_dest):
|
||||||
|
shutil.rmtree(toolchains_dest)
|
||||||
|
shutil.copytree("toolchains", toolchains_dest)
|
||||||
|
print("已复制toolchains目录到dist")
|
||||||
|
|
||||||
|
# 创建适合exe发布包的README
|
||||||
|
create_release_readme(dist_dir)
|
||||||
|
|
||||||
|
print(f"发布包已创建:{dist_dir}")
|
||||||
|
print("发布包包含:")
|
||||||
|
print(f"- {exe_name}.exe")
|
||||||
|
print("- toolchains/目录")
|
||||||
|
print("- README.md")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def create_release_readme(dist_dir):
|
||||||
|
"""创建发布版README文件"""
|
||||||
|
readme_content = """# HarmonyDevTools
|
||||||
|
|
||||||
|
HarmonyOS/OpenHarmony开发工具,提供图形化界面操作HDC工具。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- **设备管理**: 列举设备、连接设备、重启HDC服务
|
||||||
|
- **应用管理**: 安装/卸载HarmonyOS应用包
|
||||||
|
- **文件操作**: 导出设备照片、导出应用日志
|
||||||
|
- **系统信息**: 获取设备UDID、查看版本信息
|
||||||
|
- **命令执行**: 支持执行任意HDC命令
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
1. **启动程序**: 双击 `HarmonyDevTools.exe` 启动程序
|
||||||
|
2. **连接设备**: 点击"列举设备"查看可用设备,输入connect key后点击"连接设备"
|
||||||
|
3. **安装应用**: 选择hap文件,设置安装选项后点击"安装hap"
|
||||||
|
4. **导出文件**: 点击"导出照片"或"导出日志"从设备导出文件
|
||||||
|
|
||||||
|
## 系统要求
|
||||||
|
|
||||||
|
- Windows 10/11
|
||||||
|
- 无需安装Python或其他依赖
|
||||||
|
- 需要HarmonyOS/OpenHarmony设备
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 首次使用前请确保设备已开启开发者模式
|
||||||
|
- 确保toolchains目录包含hdc.exe文件
|
||||||
|
- 导出文件会自动创建时间戳目录并打开文件夹
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
1. **无法连接设备**: 检查设备是否开启USB调试,尝试重启HDC服务
|
||||||
|
2. **安装失败**: 检查hap文件是否有效,确认设备存储空间充足
|
||||||
|
3. **导出失败**: 确认设备路径正确,检查文件权限
|
||||||
|
|
||||||
|
---
|
||||||
|
基于原C# WPF项目转换的Python Tkinter版本
|
||||||
|
"""
|
||||||
|
|
||||||
|
readme_path = os.path.join(dist_dir, "README.md")
|
||||||
|
with open(readme_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(readme_content)
|
||||||
|
print("已创建发布版README.md")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def clean_build_files():
|
||||||
|
"""清理构建文件"""
|
||||||
|
print("清理构建文件...")
|
||||||
|
|
||||||
|
# 清理所有构建相关的临时文件
|
||||||
|
dirs_to_clean = ["build", "dist", "__pycache__"]
|
||||||
|
files_to_clean = ["HarmonyDevTools.spec", "HarmonyDevTools_Enhanced.spec"]
|
||||||
|
|
||||||
|
for dir_name in dirs_to_clean:
|
||||||
|
if os.path.exists(dir_name):
|
||||||
|
shutil.rmtree(dir_name)
|
||||||
|
print(f"已删除目录:{dir_name}")
|
||||||
|
|
||||||
|
for file_name in files_to_clean:
|
||||||
|
if os.path.exists(file_name):
|
||||||
|
os.remove(file_name)
|
||||||
|
print(f"已删除文件:{file_name}")
|
||||||
|
|
||||||
|
print("清理完成")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
print("=" * 50)
|
||||||
|
print("HarmonyDevTools Python版本打包工具")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
# 检查Python版本
|
||||||
|
if sys.version_info < (3, 7):
|
||||||
|
print("错误:需要Python 3.7或更高版本!")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"Python版本:{sys.version}")
|
||||||
|
|
||||||
|
# 检查PyInstaller
|
||||||
|
if not check_pyinstaller():
|
||||||
|
print("PyInstaller未安装")
|
||||||
|
choice = input("是否自动安装PyInstaller?(y/n): ").lower()
|
||||||
|
if choice == 'y':
|
||||||
|
if not install_pyinstaller():
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print("请手动安装PyInstaller:pip install pyinstaller")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 自动清理之前的构建文件
|
||||||
|
if os.path.exists("build") or os.path.exists("dist"):
|
||||||
|
print("清理之前的构建文件...")
|
||||||
|
clean_build_files()
|
||||||
|
|
||||||
|
# 构建exe文件
|
||||||
|
exe_name = build_exe()
|
||||||
|
if exe_name:
|
||||||
|
# 自动创建发布包
|
||||||
|
create_distribution(exe_name)
|
||||||
|
|
||||||
|
print("\n构建完成!")
|
||||||
|
print(f"exe文件位置:dist/{exe_name}.exe")
|
||||||
|
print("发布包位置:dist/目录")
|
||||||
|
print("可以直接分发dist目录作为完整的发布包")
|
||||||
|
else:
|
||||||
|
print("构建失败!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
668
HarmonyDevTools_Python/main.py
Normal file
668
HarmonyDevTools_Python/main.py
Normal file
@ -0,0 +1,668 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
HarmonyDevTools - Python Tkinter版本(增强版)
|
||||||
|
提供更丰富的功能和更好的用户体验
|
||||||
|
"""
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, filedialog, messagebox, scrolledtext, Menu
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
import ctypes
|
||||||
|
import webbrowser
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional, Dict, Any
|
||||||
|
|
||||||
|
# --- UI 界面 ---
|
||||||
|
# 启用 DPI 感知(避免高分屏模糊)
|
||||||
|
try:
|
||||||
|
ctypes.windll.shcore.SetProcessDpiAwareness(1)
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
ctypes.windll.user32.SetProcessDPIAware()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||||
|
handlers=[
|
||||||
|
logging.FileHandler('harmony_dev_tools.log', encoding='utf-8'),
|
||||||
|
logging.StreamHandler()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def center_window(win, width, height):
|
||||||
|
"""让窗口在屏幕中央显示"""
|
||||||
|
screen_width = win.winfo_screenwidth()
|
||||||
|
screen_height = win.winfo_screenheight()
|
||||||
|
x = (screen_width - width) // 2
|
||||||
|
y = (screen_height - height) // 2
|
||||||
|
win.geometry(f"{width}x{height}+{x}+{y}")
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
"""配置管理类"""
|
||||||
|
|
||||||
|
def __init__(self, config_file="config.json"):
|
||||||
|
self.config_file = config_file
|
||||||
|
self.config = self.load_config()
|
||||||
|
|
||||||
|
def load_config(self) -> Dict[str, Any]:
|
||||||
|
"""加载配置"""
|
||||||
|
default_config = {
|
||||||
|
"window_size": "970x600",
|
||||||
|
"theme": "default",
|
||||||
|
"auto_connect": False,
|
||||||
|
"default_target": "",
|
||||||
|
"recent_commands": [],
|
||||||
|
"max_recent_commands": 10,
|
||||||
|
"log_level": "INFO"
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists(self.config_file):
|
||||||
|
with open(self.config_file, 'r', encoding='utf-8') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
# 合并默认配置
|
||||||
|
for key, value in default_config.items():
|
||||||
|
if key not in config:
|
||||||
|
config[key] = value
|
||||||
|
return config
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"加载配置失败: {e}")
|
||||||
|
|
||||||
|
return default_config
|
||||||
|
|
||||||
|
def save_config(self):
|
||||||
|
"""保存配置"""
|
||||||
|
try:
|
||||||
|
with open(self.config_file, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(self.config, f, indent=2, ensure_ascii=False)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"保存配置失败: {e}")
|
||||||
|
|
||||||
|
def get(self, key: str, default=None):
|
||||||
|
"""获取配置值"""
|
||||||
|
return self.config.get(key, default)
|
||||||
|
|
||||||
|
def set(self, key: str, value):
|
||||||
|
"""设置配置值"""
|
||||||
|
self.config[key] = value
|
||||||
|
self.save_config()
|
||||||
|
|
||||||
|
class HdcUtil:
|
||||||
|
"""HDC工具类,用于执行hdc命令"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.hdc_path = "toolchains/hdc.exe"
|
||||||
|
self.check_hdc_path()
|
||||||
|
|
||||||
|
def check_hdc_path(self):
|
||||||
|
"""检查hdc.exe路径"""
|
||||||
|
if not os.path.exists(self.hdc_path):
|
||||||
|
logger.warning(f"HDC路径不存在: {self.hdc_path}")
|
||||||
|
# 尝试查找hdc.exe
|
||||||
|
possible_paths = [
|
||||||
|
"hdc.exe",
|
||||||
|
"toolchains/hdc.exe",
|
||||||
|
"toolchains\\hdc.exe",
|
||||||
|
"../toolchains/hdc.exe"
|
||||||
|
]
|
||||||
|
for path in possible_paths:
|
||||||
|
if os.path.exists(path):
|
||||||
|
self.hdc_path = path
|
||||||
|
logger.info(f"找到HDC路径: {self.hdc_path}")
|
||||||
|
break
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def run_cmd(parameter="", with_exit=True):
|
||||||
|
"""使用cmd.exe执行命令"""
|
||||||
|
output = []
|
||||||
|
try:
|
||||||
|
if parameter:
|
||||||
|
cmd = ["cmd.exe", "/c", parameter]
|
||||||
|
if with_exit:
|
||||||
|
cmd.append("&exit")
|
||||||
|
else:
|
||||||
|
cmd = ["cmd.exe"]
|
||||||
|
|
||||||
|
process = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
creationflags=subprocess.CREATE_NO_WINDOW
|
||||||
|
)
|
||||||
|
|
||||||
|
stdout, stderr = process.communicate()
|
||||||
|
|
||||||
|
# 过滤输出
|
||||||
|
for line in stdout.split('\n'):
|
||||||
|
if line and not line.startswith("(c) Microsoft") and not line.startswith("Microsoft Windows"):
|
||||||
|
output.append(line)
|
||||||
|
|
||||||
|
if stderr:
|
||||||
|
output.append(f"ERROR: {stderr}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"执行命令失败: {e}")
|
||||||
|
output.append(f"ERROR: {e}")
|
||||||
|
|
||||||
|
return '\n'.join(output)
|
||||||
|
|
||||||
|
def run_exe(self, exe_path, arguments=""):
|
||||||
|
"""使用指定的exe文件执行命令"""
|
||||||
|
output = []
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[exe_path] + arguments.split() if arguments else [exe_path],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
creationflags=subprocess.CREATE_NO_WINDOW
|
||||||
|
)
|
||||||
|
|
||||||
|
stdout, stderr = process.communicate()
|
||||||
|
|
||||||
|
if stdout:
|
||||||
|
output.extend(stdout.split('\n'))
|
||||||
|
|
||||||
|
if stderr:
|
||||||
|
output.append(f"ERROR: {stderr}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"执行exe失败: {e}")
|
||||||
|
output.append(f"ERROR: {e}")
|
||||||
|
|
||||||
|
return '\n'.join(output)
|
||||||
|
|
||||||
|
def export_file(self, origin_path):
|
||||||
|
"""导出文件"""
|
||||||
|
formatted_date = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
HdcUtil.run_cmd(f"mkdir {formatted_date}")
|
||||||
|
command = f"file recv {origin_path} ./{formatted_date}"
|
||||||
|
return self.run_exe(self.hdc_path, command)
|
||||||
|
|
||||||
|
def run_command(self, command):
|
||||||
|
"""运行hdc命令"""
|
||||||
|
return self.run_exe(self.hdc_path, command)
|
||||||
|
|
||||||
|
class CommandHistory:
|
||||||
|
"""命令历史管理"""
|
||||||
|
|
||||||
|
def __init__(self, max_history=50):
|
||||||
|
self.max_history = max_history
|
||||||
|
self.history = []
|
||||||
|
self.current_index = -1
|
||||||
|
|
||||||
|
def add_command(self, command):
|
||||||
|
"""添加命令到历史"""
|
||||||
|
if command and command not in self.history:
|
||||||
|
self.history.append(command)
|
||||||
|
if len(self.history) > self.max_history:
|
||||||
|
self.history.pop(0)
|
||||||
|
self.current_index = len(self.history)
|
||||||
|
|
||||||
|
def get_previous(self):
|
||||||
|
"""获取上一条命令"""
|
||||||
|
if self.history and self.current_index > 0:
|
||||||
|
self.current_index -= 1
|
||||||
|
return self.history[self.current_index]
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_next(self):
|
||||||
|
"""获取下一条命令"""
|
||||||
|
if self.history and self.current_index < len(self.history) - 1:
|
||||||
|
self.current_index += 1
|
||||||
|
return self.history[self.current_index]
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_recent(self, count=10):
|
||||||
|
"""获取最近的命令"""
|
||||||
|
return self.history[-count:] if self.history else []
|
||||||
|
|
||||||
|
class HarmonyDevTools:
|
||||||
|
"""Harmony开发工具主界面(增强版)"""
|
||||||
|
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
self.config = Config()
|
||||||
|
self.hdc_util = HdcUtil()
|
||||||
|
self.command_history = CommandHistory()
|
||||||
|
|
||||||
|
# 设置窗口
|
||||||
|
self.setup_window()
|
||||||
|
self.setup_menu()
|
||||||
|
self.setup_ui()
|
||||||
|
self.setup_bindings()
|
||||||
|
|
||||||
|
# 加载配置
|
||||||
|
self.load_config()
|
||||||
|
|
||||||
|
def setup_window(self):
|
||||||
|
"""设置窗口"""
|
||||||
|
self.root.title("HDC Tools - Python版本")
|
||||||
|
self.root.minsize(970, 600) # 最小大小限制
|
||||||
|
self.root.resizable(False, True) # 允许水平 & 垂直拉伸
|
||||||
|
center_window(self.root, 970, 600) # 初始化居中
|
||||||
|
|
||||||
|
# 设置图标(如果存在)
|
||||||
|
try:
|
||||||
|
if os.path.exists("icon.ico"):
|
||||||
|
self.root.iconbitmap("icon.ico")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def setup_menu(self):
|
||||||
|
"""设置菜单栏"""
|
||||||
|
menubar = Menu(self.root)
|
||||||
|
self.root.config(menu=menubar)
|
||||||
|
|
||||||
|
# 文件菜单
|
||||||
|
file_menu = Menu(menubar, tearoff=0)
|
||||||
|
menubar.add_cascade(label="文件", menu=file_menu)
|
||||||
|
file_menu.add_command(label="保存日志", command=self.save_log)
|
||||||
|
file_menu.add_separator()
|
||||||
|
file_menu.add_command(label="退出", command=self.on_closing)
|
||||||
|
|
||||||
|
# 工具菜单
|
||||||
|
tools_menu = Menu(menubar, tearoff=0)
|
||||||
|
menubar.add_cascade(label="工具", menu=tools_menu)
|
||||||
|
tools_menu.add_command(label="清理HDC进程", command=self.kill_hdc_processes)
|
||||||
|
tools_menu.add_command(label="检查HDC状态", command=self.check_hdc_status)
|
||||||
|
tools_menu.add_separator()
|
||||||
|
tools_menu.add_command(label="打开日志文件", command=self.open_log_file)
|
||||||
|
|
||||||
|
# 帮助菜单
|
||||||
|
help_menu = Menu(menubar, tearoff=0)
|
||||||
|
menubar.add_cascade(label="帮助", menu=help_menu)
|
||||||
|
help_menu.add_command(label="关于", command=self.show_about)
|
||||||
|
help_menu.add_command(label="查看帮助", command=self.show_help)
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
"""设置用户界面"""
|
||||||
|
# 主框架
|
||||||
|
main_frame = ttk.Frame(self.root, padding="10")
|
||||||
|
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
|
||||||
|
|
||||||
|
# 配置网格权重
|
||||||
|
self.root.columnconfigure(0, weight=1)
|
||||||
|
self.root.rowconfigure(0, weight=1)
|
||||||
|
main_frame.columnconfigure(1, weight=1)
|
||||||
|
main_frame.columnconfigure(2, weight=1)
|
||||||
|
|
||||||
|
# 第一行:设备操作
|
||||||
|
row = 0
|
||||||
|
ttk.Button(main_frame, text="列举设备", width=12, command=self.list_devices).grid(
|
||||||
|
row=row, column=0, padx=(0, 5), pady=5)
|
||||||
|
|
||||||
|
self.target_var = tk.StringVar()
|
||||||
|
target_entry = ttk.Entry(main_frame, textvariable=self.target_var, width=30)
|
||||||
|
target_entry.grid(row=row, column=1, columnspan=2, padx=5, pady=5, sticky=(tk.W, tk.E))
|
||||||
|
|
||||||
|
ttk.Button(main_frame, text="连接设备", width=12, command=self.connect_device).grid(
|
||||||
|
row=row, column=3, padx=5, pady=5)
|
||||||
|
|
||||||
|
ttk.Button(main_frame, text="重启hdc", width=12, command=self.restart_hdc).grid(
|
||||||
|
row=row, column=4, padx=5, pady=5)
|
||||||
|
|
||||||
|
ttk.Button(main_frame, text="版本信息", width=12, command=self.check_version).grid(
|
||||||
|
row=row, column=5, padx=(5, 0), pady=5)
|
||||||
|
|
||||||
|
# 第二行:安装操作
|
||||||
|
row += 1
|
||||||
|
install_frame = ttk.LabelFrame(main_frame, text="安装操作", padding="5")
|
||||||
|
install_frame.grid(row=row, column=0, columnspan=3, padx=(0, 5), pady=5, sticky=(tk.W, tk.E))
|
||||||
|
|
||||||
|
ttk.Button(install_frame, text="安装hap", width=12, command=self.install_hap).pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
self.replace_var = tk.BooleanVar()
|
||||||
|
ttk.Checkbutton(install_frame, text="替换安装", variable=self.replace_var).pack(side=tk.LEFT, padx=(10, 0))
|
||||||
|
|
||||||
|
self.downgrade_var = tk.BooleanVar()
|
||||||
|
ttk.Checkbutton(install_frame, text="允许降级", variable=self.downgrade_var).pack(side=tk.LEFT, padx=(10, 0))
|
||||||
|
|
||||||
|
self.dynamic_var = tk.BooleanVar()
|
||||||
|
ttk.Checkbutton(install_frame, text="动态授权", variable=self.dynamic_var).pack(side=tk.LEFT, padx=(10, 0))
|
||||||
|
|
||||||
|
# 卸载操作
|
||||||
|
uninstall_frame = ttk.LabelFrame(main_frame, text="卸载操作", padding="5")
|
||||||
|
uninstall_frame.grid(row=row, column=3, columnspan=3, padx=(5, 0), pady=5, sticky=(tk.W, tk.E))
|
||||||
|
|
||||||
|
self.package_name_var = tk.StringVar()
|
||||||
|
ttk.Entry(uninstall_frame, textvariable=self.package_name_var, width=25).pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
ttk.Button(uninstall_frame, text="卸载应用", width=12, command=self.uninstall_app).pack(side=tk.LEFT, padx=(10, 0))
|
||||||
|
|
||||||
|
# 第三行:其他操作
|
||||||
|
row += 1
|
||||||
|
ttk.Button(main_frame, text="导出照片", width=12, command=self.export_photo).grid(
|
||||||
|
row=row, column=0, padx=(0, 5), pady=5)
|
||||||
|
|
||||||
|
ttk.Button(main_frame, text="UDID", width=12, command=self.get_udid).grid(
|
||||||
|
row=row, column=1, padx=5, pady=5)
|
||||||
|
|
||||||
|
# 导出日志功能
|
||||||
|
self.log_pkg_var = tk.StringVar(value="com.xylink.video.conference")
|
||||||
|
ttk.Entry(main_frame, textvariable=self.log_pkg_var, width=30).grid(
|
||||||
|
row=row, column=2, columnspan=2, padx=5, pady=5, sticky=(tk.W, tk.E))
|
||||||
|
|
||||||
|
ttk.Button(main_frame, text="导出日志", width=12, command=self.export_log).grid(
|
||||||
|
row=row, column=4, padx=5, pady=5)
|
||||||
|
|
||||||
|
# 第四行:命令执行
|
||||||
|
row += 1
|
||||||
|
self.command_var = tk.StringVar()
|
||||||
|
command_entry = ttk.Entry(main_frame, textvariable=self.command_var, width=50)
|
||||||
|
command_entry.grid(row=row, column=0, columnspan=5, padx=(0, 5), pady=5, sticky=(tk.W, tk.E))
|
||||||
|
|
||||||
|
ttk.Button(main_frame, text="执行", width=12, command=self.execute_command).grid(
|
||||||
|
row=row, column=5, padx=(5, 0), pady=5)
|
||||||
|
|
||||||
|
# 第五行:结果显示
|
||||||
|
row += 1
|
||||||
|
result_frame = ttk.LabelFrame(main_frame, text="执行结果", padding="5")
|
||||||
|
result_frame.grid(row=row, column=0, columnspan=6, padx=0, pady=5, sticky=(tk.W, tk.E, tk.N, tk.S))
|
||||||
|
|
||||||
|
# 创建结果显示区域
|
||||||
|
self.result_text = scrolledtext.ScrolledText(result_frame, height=15, width=80)
|
||||||
|
self.result_text.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# 配置结果区域网格权重
|
||||||
|
result_frame.columnconfigure(0, weight=1)
|
||||||
|
result_frame.rowconfigure(0, weight=1)
|
||||||
|
main_frame.rowconfigure(row, weight=1)
|
||||||
|
|
||||||
|
# 保存控件引用
|
||||||
|
self.target_entry = target_entry
|
||||||
|
self.command_entry = command_entry
|
||||||
|
|
||||||
|
def setup_bindings(self):
|
||||||
|
"""设置事件绑定"""
|
||||||
|
# 命令输入框绑定回车键
|
||||||
|
self.command_entry.bind('<Return>', lambda e: self.execute_command())
|
||||||
|
|
||||||
|
# 命令输入框绑定上下箭头键(历史记录)
|
||||||
|
self.command_entry.bind('<Up>', lambda e: self.show_command_history('up'))
|
||||||
|
self.command_entry.bind('<Down>', lambda e: self.show_command_history('down'))
|
||||||
|
|
||||||
|
# 窗口大小改变事件
|
||||||
|
self.root.bind('<Configure>', self.on_window_resize)
|
||||||
|
|
||||||
|
def show_command_history(self, direction):
|
||||||
|
"""显示命令历史"""
|
||||||
|
if direction == 'up':
|
||||||
|
command = self.command_history.get_previous()
|
||||||
|
else:
|
||||||
|
command = self.command_history.get_next()
|
||||||
|
|
||||||
|
if command:
|
||||||
|
self.command_var.set(command)
|
||||||
|
# 选中所有文本
|
||||||
|
self.command_entry.select_range(0, tk.END)
|
||||||
|
|
||||||
|
def on_window_resize(self, event):
|
||||||
|
"""窗口大小改变事件"""
|
||||||
|
if event.widget == self.root:
|
||||||
|
# 保存窗口大小到配置
|
||||||
|
self.config.set("window_size", f"{event.width}x{event.height}")
|
||||||
|
|
||||||
|
def load_config(self):
|
||||||
|
"""加载配置"""
|
||||||
|
# 加载默认目标
|
||||||
|
default_target = self.config.get("default_target", "")
|
||||||
|
if default_target:
|
||||||
|
self.target_var.set(default_target)
|
||||||
|
|
||||||
|
def append_result(self, text):
|
||||||
|
"""添加结果到显示区域"""
|
||||||
|
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
|
||||||
|
self.result_text.insert(tk.END, f"[{timestamp}] {text}\n")
|
||||||
|
self.result_text.see(tk.END)
|
||||||
|
self.root.update_idletasks()
|
||||||
|
|
||||||
|
def execute_command_async(self, command):
|
||||||
|
"""异步执行命令"""
|
||||||
|
def run():
|
||||||
|
self.append_result(f"执行命令: {command}")
|
||||||
|
result = self.hdc_util.run_command(command)
|
||||||
|
self.append_result(f"执行结果: {result}")
|
||||||
|
|
||||||
|
# 添加到命令历史
|
||||||
|
self.command_history.add_command(command)
|
||||||
|
|
||||||
|
thread = threading.Thread(target=run)
|
||||||
|
thread.daemon = True
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
def list_devices(self):
|
||||||
|
"""列举设备"""
|
||||||
|
self.command_var.set("list targets -v")
|
||||||
|
self.execute_command_async("list targets -v")
|
||||||
|
|
||||||
|
def connect_device(self):
|
||||||
|
"""连接设备"""
|
||||||
|
target = self.target_var.get().strip()
|
||||||
|
if not target:
|
||||||
|
messagebox.showwarning("警告", "请输入connect key")
|
||||||
|
return
|
||||||
|
command = f"-t {target}"
|
||||||
|
self.command_var.set(command)
|
||||||
|
self.execute_command_async(command)
|
||||||
|
|
||||||
|
# 保存到配置
|
||||||
|
self.config.set("default_target", target)
|
||||||
|
|
||||||
|
def restart_hdc(self):
|
||||||
|
"""重启hdc"""
|
||||||
|
self.command_var.set("kill -r")
|
||||||
|
self.execute_command_async("kill -r")
|
||||||
|
|
||||||
|
def check_version(self):
|
||||||
|
"""检查版本信息"""
|
||||||
|
self.command_var.set("checkserver")
|
||||||
|
self.execute_command_async("checkserver")
|
||||||
|
|
||||||
|
def install_hap(self):
|
||||||
|
"""安装hap文件"""
|
||||||
|
file_path = filedialog.askopenfilename(
|
||||||
|
title="选择hap文件",
|
||||||
|
filetypes=[("HarmonyNEXT", "*.hap"), ("所有文件", "*.*")]
|
||||||
|
)
|
||||||
|
|
||||||
|
if file_path:
|
||||||
|
# 统一路径格式,确保使用正确的路径分隔符
|
||||||
|
normalized_path = os.path.normpath(file_path)
|
||||||
|
self.append_result(f"选择文件: {normalized_path}")
|
||||||
|
|
||||||
|
command = "install"
|
||||||
|
if self.replace_var.get():
|
||||||
|
command += " -r"
|
||||||
|
if self.downgrade_var.get():
|
||||||
|
command += " -d"
|
||||||
|
if self.dynamic_var.get():
|
||||||
|
command += " -g"
|
||||||
|
|
||||||
|
command += f" \"{normalized_path}\""
|
||||||
|
self.command_var.set(command)
|
||||||
|
self.execute_command_async(command)
|
||||||
|
|
||||||
|
def uninstall_app(self):
|
||||||
|
"""卸载应用"""
|
||||||
|
package_name = self.package_name_var.get().strip()
|
||||||
|
if not package_name:
|
||||||
|
messagebox.showwarning("警告", "请输入包名")
|
||||||
|
return
|
||||||
|
command = f"uninstall {package_name}"
|
||||||
|
self.command_var.set(command)
|
||||||
|
self.execute_command_async(command)
|
||||||
|
|
||||||
|
def export_photo(self):
|
||||||
|
"""导出照片"""
|
||||||
|
self.export_file("/storage/media/100/local/files/Photo")
|
||||||
|
|
||||||
|
def export_file(self, path):
|
||||||
|
"""导出文件"""
|
||||||
|
def run():
|
||||||
|
formatted_date = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||||
|
HdcUtil.run_cmd(f"mkdir {formatted_date}")
|
||||||
|
self.append_result(f"创建目录: {formatted_date}")
|
||||||
|
self.append_result(f"导出 {path} 到 {formatted_date}")
|
||||||
|
result = self.hdc_util.export_file(path)
|
||||||
|
self.append_result(f"导出结果: {result}")
|
||||||
|
|
||||||
|
# 导出完成后打开文件夹
|
||||||
|
try:
|
||||||
|
if os.path.exists(formatted_date):
|
||||||
|
os.startfile(formatted_date)
|
||||||
|
self.append_result(f"已打开导出目录: {formatted_date}")
|
||||||
|
except Exception as e:
|
||||||
|
self.append_result(f"打开文件夹失败: {e}")
|
||||||
|
|
||||||
|
thread = threading.Thread(target=run)
|
||||||
|
thread.daemon = True
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
def get_udid(self):
|
||||||
|
"""获取UDID"""
|
||||||
|
self.command_var.set("shell bm get --udid")
|
||||||
|
self.execute_command_async("shell bm get --udid")
|
||||||
|
|
||||||
|
def export_log(self):
|
||||||
|
"""导出日志"""
|
||||||
|
package_name = self.log_pkg_var.get().strip()
|
||||||
|
if not package_name:
|
||||||
|
messagebox.showwarning("警告", "请输入包名")
|
||||||
|
return
|
||||||
|
path = f"/data/app/el2/100/base/{package_name}/haps/entry/files"
|
||||||
|
self.export_file(path)
|
||||||
|
|
||||||
|
def execute_command(self):
|
||||||
|
"""执行命令"""
|
||||||
|
command = self.command_var.get().strip()
|
||||||
|
if not command:
|
||||||
|
messagebox.showwarning("警告", "请输入命令")
|
||||||
|
return
|
||||||
|
self.execute_command_async(command)
|
||||||
|
|
||||||
|
def save_log(self):
|
||||||
|
"""保存日志"""
|
||||||
|
file_path = filedialog.asksaveasfilename(
|
||||||
|
title="保存日志",
|
||||||
|
defaultextension=".txt",
|
||||||
|
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
|
||||||
|
)
|
||||||
|
|
||||||
|
if file_path:
|
||||||
|
try:
|
||||||
|
with open(file_path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(self.result_text.get(1.0, tk.END))
|
||||||
|
messagebox.showinfo("成功", f"日志已保存到: {file_path}")
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror("错误", f"保存失败: {e}")
|
||||||
|
|
||||||
|
def kill_hdc_processes(self):
|
||||||
|
"""清理HDC进程"""
|
||||||
|
def run():
|
||||||
|
result = HdcUtil.run_cmd("taskkill /IM hdc.exe")
|
||||||
|
self.append_result(f"清理HDC进程: {result}")
|
||||||
|
|
||||||
|
thread = threading.Thread(target=run)
|
||||||
|
thread.daemon = True
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
def check_hdc_status(self):
|
||||||
|
"""检查HDC状态"""
|
||||||
|
self.execute_command_async("checkserver")
|
||||||
|
|
||||||
|
def open_log_file(self):
|
||||||
|
"""打开日志文件"""
|
||||||
|
log_file = "harmony_dev_tools.log"
|
||||||
|
if os.path.exists(log_file):
|
||||||
|
try:
|
||||||
|
os.startfile(log_file)
|
||||||
|
except:
|
||||||
|
messagebox.showinfo("信息", f"日志文件位置: {os.path.abspath(log_file)}")
|
||||||
|
else:
|
||||||
|
messagebox.showinfo("信息", "暂无日志文件")
|
||||||
|
|
||||||
|
def show_about(self):
|
||||||
|
"""显示关于信息"""
|
||||||
|
about_text = """HarmonyDevTools - Python版本
|
||||||
|
|
||||||
|
版本: 1.0.0
|
||||||
|
作者: Python版本转换
|
||||||
|
功能: HarmonyOS/OpenHarmony开发工具
|
||||||
|
|
||||||
|
基于原C# WPF项目转换而来,
|
||||||
|
使用Python Tkinter重新实现。
|
||||||
|
|
||||||
|
支持功能:
|
||||||
|
- 设备管理
|
||||||
|
- 应用安装/卸载
|
||||||
|
- 文件导出
|
||||||
|
- 命令执行
|
||||||
|
"""
|
||||||
|
messagebox.showinfo("关于", about_text)
|
||||||
|
|
||||||
|
def show_help(self):
|
||||||
|
"""显示帮助"""
|
||||||
|
help_text = """使用说明:
|
||||||
|
|
||||||
|
1. 设备连接:
|
||||||
|
- 点击"列举设备"查看可用设备
|
||||||
|
- 输入connect key后点击"连接设备"
|
||||||
|
|
||||||
|
2. 应用管理:
|
||||||
|
- 选择hap文件进行安装
|
||||||
|
- 输入包名进行卸载
|
||||||
|
|
||||||
|
3. 文件操作:
|
||||||
|
- 点击"导出照片"导出设备照片
|
||||||
|
- 点击"导出日志"导出指定应用的日志文件
|
||||||
|
- 使用自定义命令执行其他操作
|
||||||
|
|
||||||
|
4. 快捷键:
|
||||||
|
- 命令输入框支持上下箭头键浏览历史
|
||||||
|
- 回车键执行命令
|
||||||
|
|
||||||
|
5. 日志管理:
|
||||||
|
- 可通过菜单保存执行日志
|
||||||
|
- 日志文件自动保存在程序目录
|
||||||
|
"""
|
||||||
|
messagebox.showinfo("帮助", help_text)
|
||||||
|
|
||||||
|
def on_closing(self):
|
||||||
|
"""窗口关闭时的处理"""
|
||||||
|
try:
|
||||||
|
# 保存配置
|
||||||
|
self.config.save_config()
|
||||||
|
|
||||||
|
# 清理HDC进程
|
||||||
|
result = HdcUtil.run_cmd("taskkill /IM hdc.exe")
|
||||||
|
self.append_result(result)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.root.destroy()
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
root = tk.Tk()
|
||||||
|
app = HarmonyDevTools(root)
|
||||||
|
|
||||||
|
# 绑定关闭事件
|
||||||
|
root.protocol("WM_DELETE_WINDOW", app.on_closing)
|
||||||
|
|
||||||
|
# 启动应用
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
14
HarmonyDevTools_Python/requirements.txt
Normal file
14
HarmonyDevTools_Python/requirements.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Python Tkinter项目依赖
|
||||||
|
# 注意:tkinter是Python标准库的一部分,通常不需要额外安装
|
||||||
|
# 但为了确保项目完整性,这里列出所有可能的依赖
|
||||||
|
|
||||||
|
# 如果需要额外的GUI增强功能,可以添加以下依赖:
|
||||||
|
# tkinter-tooltip==2.0.0 # 工具提示功能
|
||||||
|
# tkinterdnd2==0.3.0 # 拖拽功能
|
||||||
|
|
||||||
|
# 日志相关(可选)
|
||||||
|
# colorlog==6.7.0 # 彩色日志输出
|
||||||
|
|
||||||
|
# 打包相关(用于生成exe文件)
|
||||||
|
# pyinstaller==5.13.0 # 打包为exe文件
|
||||||
|
# auto-py-to-exe==2.32.0 # GUI打包工具
|
37
HarmonyDevTools_Python/run.bat
Normal file
37
HarmonyDevTools_Python/run.bat
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
@echo off
|
||||||
|
chcp 65001 >nul
|
||||||
|
echo ========================================
|
||||||
|
echo HarmonyDevTools Python版本启动脚本
|
||||||
|
echo ========================================
|
||||||
|
|
||||||
|
|
||||||
|
REM 检查Python是否安装
|
||||||
|
python --version >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo 错误:未找到Python,请先安装Python 3.7或更高版本
|
||||||
|
echo 下载地址:https://www.python.org/downloads/
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM 检查主程序文件是否存在
|
||||||
|
if not exist "main.py" (
|
||||||
|
echo 错误:找不到main.py文件!
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM 检查toolchains目录
|
||||||
|
if not exist "toolchains" (
|
||||||
|
echo 警告:找不到toolchains目录,请确保包含hdc.exe文件
|
||||||
|
echo.
|
||||||
|
)
|
||||||
|
|
||||||
|
echo 正在启动HarmonyDevTools...
|
||||||
|
echo.
|
||||||
|
|
||||||
|
python main.py
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo 程序已退出
|
||||||
|
pause
|
BIN
HarmonyDevTools_Python/toolchains/hdc.exe
Normal file
BIN
HarmonyDevTools_Python/toolchains/hdc.exe
Normal file
Binary file not shown.
BIN
HarmonyDevTools_Python/toolchains/libusb_shared.dll
Normal file
BIN
HarmonyDevTools_Python/toolchains/libusb_shared.dll
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user