概述
本工具提供了一个基于Python Tkinter的图形用户界面(GUI),用于帮助用户搜索并更新Android Studio项目中的config.properties
文件里的java.home
路径,以及workspace.xml
文件中的last_opened_file_path
路径。该工具旨在简化手动查找和编辑这些配置文件的过程,提高工作效率。
系统要求
- Python 3.x
- Tkinter库(通常随Python一起安装)
安装步骤
- 确保你的系统上已经安装了Python 3.x。
- 将上述提供的Python脚本保存到一个文件中,例如命名为
config_editor.py
。 - 打开命令行工具(如CMD、PowerShell或终端)。
- 导航到包含
config_editor.py
文件的目录。 - 运行脚本:
import tkinter as tk from tkinter import scrolledtext import os import xml.etree.ElementTree as ET import json # 定义查找配置配置文件的函数 def find_properties_files(directory): found_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.lower() == 'config.properties': found_files.append(os.path.join(root, file)) return found_files # 定义读取java.home的函数 def read_java_home(file_path): try: with open(file_path, 'r', encoding='utf-8') as file: for line in file: if line.lower().startswith('java.home='): return line.strip() except Exception as e: log_text.insert(tk.END, f"读取配置文件 {file_path} 失败: {e}\n") return None # 定义写入java.home的函数 def write_java_home(file_path, new_line): try: with open(file_path, 'r+', encoding='utf-8') as file: lines = file.readlines() file.seek(0) file.truncate() found = False for line in lines: if line.lower().startswith('java.home='): file.write(new_line + '\n') found = True else: file.write(line) if not found: file.write(new_line + '\n') except Exception as e: log_text.insert(tk.END, f"写入配置文件 {file_path} 失败: {e}\n") # 搜索按钮点击事件 def on_search(): directory = search_entry.get().strip() if not directory: directory = os.getcwd() log_text.delete(1.0, tk.END) found_files = find_properties_files(directory) if not found_files: status_label.config(text="没有找到任何config.properties配置文件") log_text.insert(tk.END, "没有找到任何config.properties配置文件\n") else: status_label.config(text=f"找到 {len(found_files)} 个config.properties配置文件") log_text.insert(tk.END, f"找到 {len(found_files)} 个config.properties配置文件\n") for file_path in found_files: log_text.insert(tk.END, f"处理配置文件: {file_path}\n") # 更新按钮点击事件 def on_update(): new_value = entry_new_value.get().strip() if not new_value: #log_text.insert(tk.END, "新的java.home路径不能为空\n") status_label.config(text=f"新的java.home路径不能为空") return log_text.delete(1.0, tk.END) directory = search_entry.get().strip() if not directory: directory = os.getcwd() log_text.insert(tk.END, f"目标路径: {directory}\n") found_files = find_properties_files(directory) if not found_files: status_label.config(text="没有找到任何config.properties配置文件") log_text.insert(tk.END, "没有找到任何config.properties配置文件\n") else: status_label.config(text=f"找到 {len(found_files)} 个config.properties配置文件") log_text.insert(tk.END, f"找到 {len(found_files)} 个config.properties配置文件\n") for file_path in found_files: log_text.insert(tk.END, f"处理配置文件: {file_path}\n") current_java_home = read_java_home(file_path) if current_java_home: log_text.insert(tk.END, f"配置文件路径: {file_path}, 当前值: {current_java_home}, 已更新: java.home={new_value}\n") else: log_text.insert(tk.END, f"配置文件路径: {file_path}, 未找到java.home属性, 已更新: java.home={new_value}\n") write_java_home(file_path, f"java.home={new_value}") # 搜索workspace.xml配置文件 def on_workspace_xml_search(): directory = search_entry.get().strip() if not directory: directory = os.getcwd() log_text.delete(1.0, tk.END) found_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.lower() == 'workspace.xml': found_files.append(os.path.join(root, file)) if not found_files: log_text.insert(tk.END, "没有找到workspace.xml配置文件\n") else: status_label.config(text=f"找到 {len(found_files)} 个workspace.xml配置文件") log_text.insert(tk.END, f"找到 {len(found_files)} 个workspace.xml配置文件\n") for file_path in found_files: log_text.insert(tk.END, f"处理配置文件: {file_path}\n") # 更新workspace.xml配置文件 def on_workspace_xml_update(): directory = search_entry.get().strip() if not directory: directory = os.getcwd() log_text.delete(1.0, tk.END) import json import os import tkinter as tk from lxml import etree # 更新workspace.xml配置文件 def on_workspace_xml_update(): directory = search_entry.get().strip() if not directory: directory = os.getcwd() # 获取新的 last_opened_file_path new_last_opened_file_path = new_last_opened_file_path_entry.get().strip() if not new_last_opened_file_path: messagebox.showerror("错误", "新的last_opened_file_path不能为空") return # 确保路径使用正斜杠 new_last_opened_file_path = new_last_opened_file_path.replace("\\", "/") # 查找workspace.xml配置文件 found_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.lower() == 'workspace.xml': found_files.append(os.path.join(root, file)) if not found_files: messagebox.showinfo("信息", "没有找到workspace.xml配置文件") return for workspace_xml_path in found_files: log_text.insert(tk.END, f"处理配置文件: {workspace_xml_path}\n") try: # 读取并解析XML配置文件 parser = etree.XMLParser(strip_cdata=False) # 保持CDATA部分不变 tree = etree.parse(workspace_xml_path, parser) root = tree.getroot() # 查找PropertiesComponent组件 properties_component = root.find(".//component[@name='PropertiesComponent']") if properties_component is None: log_text.insert(tk.END, "找不到 PropertiesComponent 组件\n") continue # 提取CDATA内容 cdata_content = properties_component.text if not cdata_content or not cdata_content.strip().startswith("<![CDATA[") or not cdata_content.strip().endswith("]]>"): log_text.insert(tk.END, "找不到 PropertiesComponent 组件或其 JSON 数据\n") continue # 去掉CDATA标记 key_to_string_json = cdata_content.strip()[len("<![CDATA["):-len("]]>")].strip() log_text.insert(tk.END, f"原始 keyToString JSON 数据: {key_to_string_json}\n") # 使用json.loads解析JSON数据 key_to_string_dict = json.loads(key_to_string_json, strict=False) # 获取旧的 last_opened_file_path old_last_opened_file_path = key_to_string_dict.get('keyToString', {}).get('last_opened_file_path', '') log_text.insert(tk.END, f"修改前: last_opened_file_path={old_last_opened_file_path}\n") # 更新last_opened_file_path key_to_string_dict.setdefault('keyToString', {})['last_opened_file_path'] = new_last_opened_file_path log_text.insert(tk.END, f"修改后: last_opened_file_path={new_last_opened_file_path}\n") # 生成新的 JSON 数据 # 保持原始 JSON 数据的格式 new_key_to_string_json = json.dumps(key_to_string_dict, ensure_ascii=False, indent=None, separators=(',', ': ')) # 构造新的CDATA内容 new_cdata_content = "<![CDATA[" + new_key_to_string_json + "]]>" # 更新CDATA内容 properties_component.text = new_cdata_content # 写回workspace.xml配置文件 tree.write(workspace_xml_path, encoding='utf-8', xml_declaration=True, pretty_print=True) log_text.insert(tk.END, f"已更新或添加last_opened_file_path: {new_last_opened_file_path} 到 {workspace_xml_path}\n") except json.JSONDecodeError as e: log_text.insert(tk.END, f"JSON 解析错误: {e}\n") except Exception as e: log_text.insert(tk.END, f"处理配置文件 {workspace_xml_path} 失败: {e}\n") import re import os import tkinter as tk from tkinter import messagebox # 更新workspace.xml配置文件 def on_workspace_xml_update(): directory = search_entry.get().strip() if not directory: directory = os.getcwd() # 获取新的 last_opened_file_path new_last_opened_file_path = new_last_opened_file_path_entry.get().strip() if not new_last_opened_file_path: #messagebox.showerror("错误", "新的last_opened_file_path不能为空") status_label.config(text=f"新的last_opened_file_path不能为空") return # 确保路径使用正斜杠 new_last_opened_file_path = new_last_opened_file_path.replace("\\", "/") # 查找workspace.xml配置文件 found_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.lower() == 'workspace.xml': found_files.append(os.path.join(root, file)) if not found_files: messagebox.showinfo("信息", "没有找到workspace.xml配置文件") return for workspace_xml_path in found_files: # 读取配置文件内容 with open(workspace_xml_path, 'r', encoding='utf-8') as file: content = file.read() # 查找包含 "last_opened_file_path" 的 JSON 字符串 pattern = r'"last_opened_file_path"\s*:\s*"([^"]+)"' match = re.search(pattern, content) if match: # 替换 "last_opened_file_path" 的值 old_value = match.group(1) content = re.sub(pattern, f'"last_opened_file_path": "{new_last_opened_file_path}"', content) # 写回配置文件 with open(workspace_xml_path, 'w', encoding='utf-8') as file: file.write(content) log_text.insert(tk.END, f"已将 {old_value} 替换为 {new_last_opened_file_path} 在 {workspace_xml_path}\n") else: log_text.insert(tk.END, f"未找到 last_opened_file_path 在 {workspace_xml_path}\n") import tkinter as tk from tkinter import scrolledtext import tkinter.font as tkFont import os import re # RGB值 background_rgb = (43, 42, 51) output_bg_rgb = (31, 31, 31) output_fg_rgb = (255, 255, 255) # 白色 button_bg_rgb = (31, 31, 31) # 按钮背景颜色 button_fg_rgb = (0, 128, 0) # 按钮文本颜色 entry_bg_rgb = (31, 31, 31) # 输入框背景颜色 entry_fg_rgb = (255, 255, 255) # 输入框文本颜色 label_bg_rgb = (43, 42, 51) # 标签背景颜色 label_fg_rgb = (255, 255, 255) # 标签文本颜色 # 辅助函数 def create_label(parent, text, **kwargs): return tk.Label( parent, text=text, font=large_font, fg=f"#{label_fg_rgb[0]:02X}{label_fg_rgb[1]:02X}{label_fg_rgb[2]:02X}", bg=f"#{label_bg_rgb[0]:02X}{label_bg_rgb[1]:02X}{label_bg_rgb[2]:02X}", **kwargs ) def create_entry(parent, **kwargs): return tk.Entry( parent, font=large_font, fg=f"#{entry_fg_rgb[0]:02X}{entry_fg_rgb[1]:02X}{entry_fg_rgb[2]:02X}", bg=f"#{entry_bg_rgb[0]:02X}{entry_bg_rgb[1]:02X}{entry_bg_rgb[2]:02X}", **kwargs ) def create_button(parent, text, command, **kwargs): return tk.Button( parent, text=text, font=large_font, fg=f"#{button_fg_rgb[0]:02X}{button_fg_rgb[1]:02X}{button_fg_rgb[2]:02X}", bg=f"#{button_bg_rgb[0]:02X}{button_bg_rgb[1]:02X}{button_bg_rgb[2]:02X}", command=command, **kwargs ) # 日志记录 def log(message): log_text.insert(tk.END, message + "\n") log_text.see(tk.END) # 自动滚动到底部 # 创建主窗口 root = tk.Tk() # 定义一个更大的字体(不加粗) large_font = tkFont.Font(family="宋体", size=13) # 调整字体大小,但不加粗 root.title("修改android-studio项目配置JDK路径和项目gradle路径") #root.title("Config Properties & Workspace XML Editor") # 设置背景颜色 root.configure(bg=f"#{background_rgb[0]:02X}{background_rgb[1]:02X}{background_rgb[2]:02X}") # 定义一个更大的字体(不加粗) large_font = tkFont.Font(family="宋体", size=13) # 调整字体大小,但不加粗 # 创建GUI组件 create_label(root, "请输入目录路径 (留空则使用当前路径),搜索config.properties中java.home值").pack(pady=5) search_entry = create_entry(root, width=50) search_entry.pack(pady=5) # 搜索config.properties按钮 search_button = create_button(root, "搜索android-studio项目配置JDK路径", on_search) search_button.pack(pady=5) # 输入新的java.home值 create_label(root, "请输入新的java.home值=android-studio项目自定义配置JDK路径").pack(pady=9) entry_new_value = create_entry(root, width=50) entry_new_value.pack(pady=5) # 更新config.properties按钮 update_button = create_button(root, "更新android-studio配置JDK路径", on_update) update_button.pack(pady=5) # 分隔符 tk.Frame(height=2, bd=1, relief=tk.SUNKEN).pack(fill=tk.X, padx=5, pady=5) # 搜索workspace.xml按钮 workspace_xml_search_button = create_button(root, "搜索workspace.xml", on_workspace_xml_search) workspace_xml_search_button.pack(pady=5) # 输入新的last_opened_file_path create_label(root, "请输入新的last_opened_file_path=你的android-studio的gradle路径").pack(pady=5) new_last_opened_file_path_entry = create_entry(root, width=50) new_last_opened_file_path_entry.pack(pady=5) # 更新workspace.xml按钮 workspace_xml_update_button = create_button(root, "更新workspace.xml=配置android-studio项目的gradle路径", on_workspace_xml_update) workspace_xml_update_button.pack(pady=5) # 状态标签 status_label = create_label(root, "") status_label.pack(pady=5) # 日志文本框 log_text = scrolledtext.ScrolledText( root, width=80, height=20, wrap=tk.WORD, font=large_font, fg=f"#{output_fg_rgb[0]:02X}{output_fg_rgb[1]:02X}{output_fg_rgb[2]:02X}", bg=f"#{output_bg_rgb[0]:02X}{output_bg_rgb[1]:02X}{output_bg_rgb[2]:02X}" ) log_text.pack(pady=5) # 运行主循环 root.mainloop()
主窗口布局
- 输入目录路径:用户可以在这里输入Android Studio项目的根目录路径。如果留空,则默认使用当前工作目录。
- 搜索
config.properties
:点击此按钮将搜索指定目录下的config.properties
文件,并显示当前的java.home
值。 - 输入新的
java.home
值:用户可以在此输入新的JDK路径。 - 更新
config.properties
:点击此按钮将更新config.properties
文件中的java.home
值为用户指定的新路径。 - 搜索
workspace.xml
:点击此按钮将搜索指定目录下的workspace.xml
文件,并显示当前的last_opened_file_path
值。 - 输入新的
last_opened_file_path
:用户可以在此输入新的Gradle路径。 - 更新
workspace.xml
:点击此按钮将更新workspace.xml
文件中的last_opened_file_path
值为用户指定的新路径。 - 日志文本框:显示操作过程中的信息和结果。
使用步骤
- 启动程序:运行
config_editor.py
后,会弹出一个窗口。 - 输入目录路径(可选):在“请输入目录路径 (留空则使用当前路径)”输入框中输入Android Studio项目的根目录路径。如果留空,则默认使用当前工作目录。
- 搜索
config.properties
:点击“搜索android-studio项目配置JDK路径”按钮。程序会在指定目录下查找config.properties
文件,并显示当前的java.home
值。 - 更新
java.home
值:- 在“请输入新的java.home值”输入框中输入新的JDK路径。
- 点击“更新android-studio配置JDK路径”按钮,程序会更新
config.properties
文件中的java.home
值。
- 搜索
workspace.xml
:点击“搜索workspace.xml”按钮。程序会在指定目录下查找workspace.xml
文件,并显示当前的last_opened_file_path
值。 - 更新
last_opened_file_path
值:- 在“请输入新的last_opened_file_path”输入框中输入新的Gradle路径。
- 点击“更新workspace.xml=配置android-studio项目的gradle路径”按钮,程序会更新
workspace.xml
文件中的last_opened_file_path
值。
- 查看日志:所有操作的结果都会显示在日志文本框中,包括成功消息和错误信息。
注意事项
- 确保你有足够的权限来读取和写入指定的文件。
- 在更新配置文件之前,请备份原始文件,以防意外发生。
- 请确保输入的路径是正确的,并且路径存在。
- 如果路径或文件名包含特殊字符,请确保它们被正确转义或引用。
通过以上步骤,你可以轻松地管理和更新Android Studio项目的配置文件,从而确保项目使用的JDK和Gradle路径是正确的。希望这个工具能帮助你提高开发效率!