增加python版本

This commit is contained in:
DevWiki 2025-08-15 17:20:17 +08:00
parent 1f15856a68
commit c903a9e444
8 changed files with 1221 additions and 0 deletions

106
HarmonyDevTools_Python/.gitignore vendored Normal file
View 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]/

View File

@ -0,0 +1,183 @@
# HarmonyDevTools - Python版本
![](https://img.shields.io/badge/状态-稳定-red.svg)
![](https://img.shields.io/badge/启动时间-2024/06/20-green.svg)
![](https://img.shields.io/badge/优先级-NORMAL-blue.svg)
![](https://img.shields.io/badge/语言-Python-blue.svg)
本项目为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-exeGUI工具
```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`目录包含所需的工具文件。

View 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("请手动安装PyInstallerpip 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()

View 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()

View 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打包工具

View 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

Binary file not shown.

Binary file not shown.