Last active
May 3, 2026 08:05
-
-
Save roflsunriz/095dd7369862fce5becd5f93a39957a8 to your computer and use it in GitHub Desktop.
WSAInstallAPK.pyw : GUI Program that performs installing APK for WSA (Windows Android Subsystem)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import tkinter as tk | |
| from tkinter import scrolledtext, filedialog | |
| import subprocess | |
| import threading | |
| import os | |
| import json | |
| import shutil | |
| # 言語用の辞書の定義 | |
| LANGUAGES = { | |
| "ja": { | |
| "title": "Windows Android Subsystem 用 GUI APKインストールツール", | |
| "adb_folder": "adbフォルダの場所:", | |
| "apk_path": "インストールするAPKパス:", | |
| "log_label": "ログ:", | |
| "run": "実行", | |
| "exit": "終了", | |
| "browse": "参照", | |
| "language": "言語選択:", | |
| }, | |
| "en": { | |
| "title": "Windows Android Subsystem GUI APK Install Tool", | |
| "adb_folder": "adb Folder Path:", | |
| "apk_path": "APK Path:", | |
| "log_label": "Log:", | |
| "run": "Run", | |
| "exit": "Exit", | |
| "browse": "Browse", | |
| "language": "Language:", | |
| } | |
| } | |
| LOG_MESSAGES = { | |
| "ja": { | |
| "going_to_dir": "指定ディレクトリ: {adb_path} に移動中...", | |
| "error_adb": "エラー: adbパスが存在しません", | |
| "command_execute": "コマンド実行: {cmd}", | |
| "error": "エラー: {error}", | |
| "install_apk": "インストールするAPK: {apk_path}", | |
| "error_apk": "エラー: APKファイルが存在しません", | |
| "exception": "例外発生: {e}", | |
| "adb_in_path": "環境変数PATHからadbを使用しています ({adb_path})", | |
| }, | |
| "en": { | |
| "going_to_dir": "Changing current directory to: {adb_path} ...", | |
| "error_adb": "Error: adb folder does not exist!", | |
| "command_execute": "Executing command: {cmd}", | |
| "error": "Error: {error}", | |
| "install_apk": "Installing APK: {apk_path}", | |
| "error_apk": "Error: APK file does not exist!", | |
| "exception": "Exception occurred: {e}", | |
| "adb_in_path": "Using adb from PATH environment variable ({adb_path})", | |
| } | |
| } | |
| # 設定ファイルのパスを変更 | |
| SETTINGS_FILE = os.path.join(os.environ["USERPROFILE"], "mini-tools", "WSAInstallAPK", "settings.json") | |
| CONFIG_DIR = os.path.dirname(SETTINGS_FILE) | |
| def load_settings(): | |
| """設定ファイルから設定値を読み込み""" | |
| defaults = {"adb_folder": r"C:\platform-tools", "apk_path": ""} | |
| # 設定ディレクトリが存在しない場合は作成 | |
| if not os.path.exists(CONFIG_DIR): | |
| os.makedirs(CONFIG_DIR) | |
| if os.path.isfile(SETTINGS_FILE): | |
| try: | |
| with open(SETTINGS_FILE, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| defaults.update(data) | |
| except Exception as e: | |
| print("設定読み込み失敗:", e) | |
| # Check if adb is in PATH | |
| adb_in_path = shutil.which("adb") is not None | |
| return defaults, adb_in_path | |
| def save_settings(adb_folder, apk_path): | |
| """現在の設定値を設定ファイルに保存""" | |
| data = {"adb_folder": adb_folder, "apk_path": apk_path} | |
| try: | |
| with open(SETTINGS_FILE, "w", encoding="utf-8") as f: | |
| json.dump(data, f, ensure_ascii=False, indent=4) | |
| except Exception as e: | |
| print("設定保存失敗:", e) | |
| def append_log(log_widget, message): | |
| log_widget.configure(state='normal') | |
| log_widget.insert(tk.END, message + "\n") | |
| log_widget.see(tk.END) | |
| log_widget.configure(state='disabled') | |
| def run_commands(adb_path, apk_path, log_widget, run_button, language_var, adb_in_path): | |
| lang = language_var.get() | |
| trans = LOG_MESSAGES[lang] | |
| try: | |
| run_button.config(state=tk.DISABLED) | |
| if adb_in_path: | |
| adb_exe = shutil.which("adb") | |
| append_log(log_widget, trans["adb_in_path"].format(adb_path=adb_exe)) | |
| else: | |
| append_log(log_widget, trans["going_to_dir"].format(adb_path=adb_path)) | |
| if not os.path.isdir(adb_path): | |
| append_log(log_widget, trans["error_adb"]) | |
| run_button.config(state=tk.NORMAL) | |
| return | |
| connect_cmd = ["adb", "connect", "127.0.0.1:58526"] | |
| append_log(log_widget, trans["command_execute"].format(cmd=" ".join(connect_cmd))) | |
| cwd = None if adb_in_path else adb_path | |
| result = subprocess.run(connect_cmd, cwd=cwd, capture_output=True, text=True) | |
| append_log(log_widget, result.stdout) | |
| if result.stderr: | |
| append_log(log_widget, trans["error"].format(error=result.stderr)) | |
| append_log(log_widget, trans["install_apk"].format(apk_path=apk_path)) | |
| if not os.path.isfile(apk_path): | |
| append_log(log_widget, trans["error_apk"]) | |
| run_button.config(state=tk.NORMAL) | |
| return | |
| install_cmd = ["adb", "install", apk_path] | |
| append_log(log_widget, trans["command_execute"].format(cmd=" ".join(install_cmd))) | |
| result = subprocess.run(install_cmd, cwd=cwd, capture_output=True, text=True) | |
| append_log(log_widget, result.stdout) | |
| if result.stderr: | |
| append_log(log_widget, trans["error"].format(error=result.stderr)) | |
| except Exception as e: | |
| append_log(log_widget, trans["exception"].format(e=str(e))) | |
| finally: | |
| run_button.config(state=tk.NORMAL) | |
| def select_apk(entry_apk, trans): | |
| filepath = filedialog.askopenfilename(filetypes=[("APK files", "*.apk")]) | |
| if filepath: | |
| entry_apk.delete(0, tk.END) | |
| entry_apk.insert(0, filepath) | |
| def select_adb_folder(entry_adb): | |
| """adbフォルダー選択用のダイアログを開く""" | |
| folder = filedialog.askdirectory() | |
| if folder: | |
| entry_adb.delete(0, tk.END) | |
| entry_adb.insert(0, folder) | |
| def update_language(root, lbl_adb, lbl_apk, lbl_log, btn_run, btn_exit, btn_browse_apk, btn_browse_adb, lbl_lang, language_var, log_text, adb_in_path): | |
| lang = language_var.get() | |
| root.title(LANGUAGES[lang]["title"]) | |
| lbl_adb.config(text=LANGUAGES[lang]["adb_folder"]) | |
| lbl_apk.config(text=LANGUAGES[lang]["apk_path"]) | |
| lbl_log.config(text=LANGUAGES[lang]["log_label"]) | |
| btn_run.config(text=LANGUAGES[lang]["run"]) | |
| btn_exit.config(text=LANGUAGES[lang]["exit"]) | |
| btn_browse_apk.config(text=LANGUAGES[lang]["browse"]) | |
| btn_browse_adb.config(text=LANGUAGES[lang]["browse"]) | |
| lbl_lang.config(text=LANGUAGES[lang]["language"]) | |
| if adb_in_path: | |
| adb_exe = shutil.which("adb") | |
| append_log(log_text, LOG_MESSAGES[lang]["adb_in_path"].format(adb_path=adb_exe)) | |
| def main(): | |
| root = tk.Tk() | |
| # ここで language_var を生成する | |
| language_var = tk.StringVar(root, value="ja") | |
| settings, adb_in_path = load_settings() | |
| root.geometry("600x400") | |
| root.title(LANGUAGES[language_var.get()]["title"]) | |
| frame = tk.Frame(root) | |
| frame.pack(padx=10, pady=10, fill=tk.X) | |
| # 言語選択フレームの追加 | |
| lang_frame = tk.Frame(root) | |
| lang_frame.pack(padx=10, pady=5, fill=tk.X) | |
| lbl_lang = tk.Label(lang_frame, text=LANGUAGES[language_var.get()]["language"]) | |
| lbl_lang.grid(row=0, column=0, sticky=tk.W) | |
| tk.Radiobutton(lang_frame, text="日本語", variable=language_var, value="ja", | |
| command=lambda: update_language(root, lbl_adb, lbl_apk, lbl_log, btn_run, btn_exit, btn_browse_apk, btn_browse_adb, lbl_lang, language_var, log_text, adb_in_path)).grid(row=0, column=1) | |
| tk.Radiobutton(lang_frame, text="English", variable=language_var, value="en", | |
| command=lambda: update_language(root, lbl_adb, lbl_apk, lbl_log, btn_run, btn_exit, btn_browse_apk, btn_browse_adb, lbl_lang, language_var, log_text, adb_in_path)).grid(row=0, column=2) | |
| # adbフォルダ指定 | |
| lbl_adb = tk.Label(frame, text=LANGUAGES[language_var.get()]["adb_folder"]) | |
| lbl_adb.grid(row=0, column=0, sticky=tk.W) | |
| entry_adb = tk.Entry(frame, width=50) | |
| entry_adb.grid(row=0, column=1, padx=5, pady=5) | |
| entry_adb.insert(0, settings["adb_folder"]) | |
| btn_browse_adb = tk.Button(frame, text=LANGUAGES[language_var.get()]["browse"], | |
| command=lambda: select_adb_folder(entry_adb)) | |
| btn_browse_adb.grid(row=0, column=2, padx=5, pady=5) | |
| # adbがPATHにある場合、platform-toolsの入力欄とボタンを無効化 | |
| if adb_in_path: | |
| entry_adb.config(state='disabled') | |
| btn_browse_adb.config(state='disabled') | |
| # apk指定 | |
| lbl_apk = tk.Label(frame, text=LANGUAGES[language_var.get()]["apk_path"]) | |
| lbl_apk.grid(row=1, column=0, sticky=tk.W) | |
| entry_apk = tk.Entry(frame, width=50) | |
| entry_apk.grid(row=1, column=1, padx=5, pady=5) | |
| entry_apk.insert(0, settings["apk_path"]) | |
| btn_browse_apk = tk.Button(frame, text=LANGUAGES[language_var.get()]["browse"], | |
| command=lambda: select_apk(entry_apk, LANGUAGES[language_var.get()])) | |
| btn_browse_apk.grid(row=1, column=2, padx=5, pady=5) | |
| # ログエリア | |
| lbl_log = tk.Label(root, text=LANGUAGES[language_var.get()]["log_label"]) | |
| lbl_log.pack(anchor=tk.W, padx=10) | |
| log_text = scrolledtext.ScrolledText(root, state='disabled', wrap=tk.WORD, height=15) | |
| log_text.pack(padx=10, pady=5, fill=tk.BOTH, expand=True) | |
| # adbがPATHにある場合はログに出力 | |
| if adb_in_path: | |
| adb_exe = shutil.which("adb") | |
| trans = LOG_MESSAGES[language_var.get()] | |
| append_log(log_text, trans["adb_in_path"].format(adb_path=adb_exe)) | |
| button_frame = tk.Frame(root) | |
| button_frame.pack(pady=5) | |
| btn_run = tk.Button(button_frame, text=LANGUAGES[language_var.get()]["run"], width=10, | |
| command=lambda: threading.Thread(target=run_commands, args=( | |
| entry_adb.get(), entry_apk.get(), log_text, btn_run, language_var, adb_in_path)).start()) | |
| btn_run.grid(row=0, column=0, padx=5) | |
| # 終了時に設定を保存するラッパー関数に変更 | |
| def exit_program(): | |
| save_settings(entry_adb.get(), entry_apk.get()) | |
| root.destroy() | |
| btn_exit = tk.Button(button_frame, text=LANGUAGES[language_var.get()]["exit"], width=10, command=exit_program) | |
| btn_exit.grid(row=0, column=1, padx=5) | |
| root.mainloop() | |
| if __name__ == "__main__": | |
| main() | |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to use:
winget install Google.PlatformTools --source winget