Compare commits

..

14 Commits
1.1.0 ... 1.2.3

Author SHA1 Message Date
fde7a0d255 1.2.3——修复小问题 2021-08-02 08:01:23 +08:00
38b19ed2d2 1.2.2 2021-07-11 14:45:11 +08:00
dcc92846be Up 2021-07-11 13:03:33 +08:00
ec8e48aff3 Over 2021-07-11 08:55:28 +08:00
35db9dc361 1.2.2 test 2021-07-07 15:46:35 +08:00
2da3e3962b 1.2.2 test 2021-07-07 15:44:22 +08:00
d749ece476 1.2.1: change deb package too 2021-07-02 20:38:34 +08:00
7beb35d1de 1.2.1: change deb package 2021-07-02 20:28:57 +08:00
de71e3b01e 1.2.1:a little update 2021-07-02 20:19:23 +08:00
0dd7858097 1.2.1 2021-07-02 20:05:01 +08:00
81e2346fc8 update README.md. 2021-06-08 08:01:21 +08:00
1b74fcde2f 微调 2021-06-06 18:00:21 +08:00
b07d24202e 1.2.0 2021-06-06 11:54:38 +08:00
85cf28d552 改了一下deb包 2021-06-03 19:11:13 +08:00
11 changed files with 516 additions and 891 deletions

View File

@@ -1,23 +1,51 @@
# uengine 运行器 # 我图标的获取有问题,继续深造去了为什么图标是xml,可以使用其他替代品,链接:https://bbs.deepin.org/zh/post/222874
# uengine 运行器 1.2.1
#### 介绍 #### 介绍
使用 Python3 的 tkinter 构建 使用 Python3 的 tkinter 构建
测试平台UOS 家庭版) 测试平台UOS 家庭版deepin 20.2.2 待测试
(自己美术功底太差,图标直接用 anbox 的了) (自己美术功底太差,图标直接用 anbox 的了)
#### 软件架构 #### 软件架构
i386 和 amd64 i386 和 amd64
#### 更新内容
1.2.1更新内容:
※1、进行了安装方式的修改不使用 adb修复原无法安装和卸载的问题
2、进行了部分优化
3、进行了功能缩水
4、修复 deb 打包错误。
1.2.0更新内容:
1、支持安装自动添加快捷方式、卸载删除快捷方式
2、支持使用包名或 APK 文件卸载程序;
3、支持查看安装的所有包名
4、进行了部分优化
#### 源码安装教程 #### 源码安装教程
1. 安装所需依赖 1. 安装所需依赖
``` ```
sudo apt install python3 python3-tk git adb sudo apt install python3 python3-tk git python3-pip aapt uengine
pip3 install pillow
pip3 install ttkthemes
pip3 install pillow -U
pip3 install ttkthemes -U
``` ```
2. 下载本程序 2. 下载本程序
@@ -29,18 +57,30 @@ git clone https://gitee.com/gfdgd-xi/uengine-runner.git
3. 运行本程序 3. 运行本程序
``` ```
cd uengine-runner sudo cp uengine-runner /opt/apps -rv
chmod 777 main.py chmod 777 /opt/apps/uengine-runner/main.py
sudo cp /opt/apps/uengine-runner/main.py /usr/bin/uengine-runner
./main.py ./main.py
``` ```
4. 卸载本程序
```
sudo rm /usr/bin/uengine-runner -v
sudo rm /opt/apps/uengine-runner/ -rfv
pip3 uninstall pillow
pip3 uninstall ttkthemes
```
#### 使用说明 #### 使用说明
提示: 提示:
1、需要你有使用 root 权限的能力;
None 2、需要安装 uengine 才能使用。
如果想要连接其他手机,请使用 1.2.0 以前的版本,可以使用 adb 连接。
#### 特技 #### 特技
……

View File

@@ -1,9 +1,9 @@
Package: spark-uengine-runner Package: spark-uengine-runner
Version: 1.0.0 Version: 1.2.3
Maintainer: gfdgd xi <3025613752@qq.com> Maintainer: gfdgd xi <3025613752@qq.com>
Homepage: https://gitee.com/gfdgd-xi/uengine-runner Homepage: https://gitee.com/gfdgd-xi/uengine-runner
Architecture: all Architecture: all
Priority: optional Priority: optional
Depends: python3, python3-tk, adb, python3-pip Depends: python3, python3-tk, python3-pip, aapt, uengine, python3-pil, python3-pil.imagetk
Description: gfdgd xi make's uengine runner Description: gfdgd xi make's uengine runner

View File

@@ -1,5 +1,4 @@
# !/bin/sh # !/bin/sh
sudo pip3 install --upgrade pip # python3 -m pip install --upgrade pillow
sudo pip3 install --upgrade virtualenv # 依赖已经有设置,可以舍去
pip3 install pillow python3 -m pip install --upgrade ttkthemes
pip3 install ttkthemes

View File

@@ -2,9 +2,9 @@
# 使用系统默认的 python3 运行 # 使用系统默认的 python3 运行
########################################################################################### ###########################################################################################
# 作者gfdgd xi # 作者gfdgd xi
# 版本1.1.0 # 版本1.2.3
# 更新时间2021年5月30 # 更新时间2021年8月2
# 感谢anbox 和 统信 # 感谢anbox、deepin 和 UOS
# 基于 Python3 的 tkinter 构建 # 基于 Python3 的 tkinter 构建
########################################################################################### ###########################################################################################
################# #################
@@ -15,6 +15,7 @@ import sys
import time import time
import json import json
import shutil import shutil
import zipfile
import traceback import traceback
import threading import threading
import webbrowser import webbrowser
@@ -22,44 +23,52 @@ import subprocess
import ttkthemes import ttkthemes
import tkinter as tk import tkinter as tk
import tkinter.ttk as ttk import tkinter.ttk as ttk
import tkinter.tix as tix
import tkinter.messagebox as messagebox import tkinter.messagebox as messagebox
import tkinter.filedialog as filedialog import tkinter.filedialog as filedialog
import PIL.Image as Image import PIL.Image as Image
import PIL.ImageTk as ImageTk import PIL.ImageTk as ImageTk
def KillAdbProgress(): # 卸载程序
DisabledAndEnbled(True) def UninstallProgram(package: "apk 包名")->"卸载程序":
Return = GetCommandReturn("killall adb") try:
if Return is "": global fineUninstallApkHistory
Return = "进程已经杀死!" Return = GetCommandReturn("pkexec /usr/bin/uengine-session-launch-helper -- uengine uninstall --pkg='{}'".format(package))
messagebox.showinfo(title="tips", message=Return) if os.path.exists("{}/.local/share/applications/{}.desktop".format(get_home(), package)):
DisabledAndEnbled(False) os.remove("{}/.local/share/applications/{}.desktop".format(get_home(), package))
if os.path.exists("{}/{}.desktop".format(get_desktop_path(), package)):
os.remove("{}/{}.desktop".format(get_desktop_path(), package))
fineUninstallApkHistory.append(combobox3.get())
combobox3['value'] = fineUninstallApkHistory
write_txt(get_home() + "/.config/uengine-runner/FindUninstallApkHistory.json", str(json.dumps(ListToDictionary(fineUninstallApkHistory)))) # 将历史记录的数组转换为字典并写入
return Return
except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
def Button1Click(): def ButtonClick7():
if combobox2.get() is "": path = filedialog.askopenfilename(title="选择 Apk", filetypes=[("APK 文件", "*.apk"), ("所有文件", "*.*")], initialdir=json.loads(readtxt(get_home() + "/.config/uengine-runner/FindUninstallApk.json"))["path"])
messagebox.showerror(title="提示", message="信息没有填写完整,无法继续连接 IP") if path != "" and path != "()":
try:
combobox3.set(path)
write_txt(get_home() + "/.config/uengine-runner/FindUninstallApk.json", json.dumps({"path": os.path.dirname(path)})) # 写入配置文件
except:
pass
def ButtonClick8():
if combobox3.get() is "":
messagebox.showerror(title="提示", message="信息没有填写完整,无法继续卸载 APK")
return return
DisabledAndEnbled(True) DisabledAndEnbled(True)
threading.Thread(target=ConnectPhoneIp).start() if os.path.exists(combobox3.get()):
path = GetApkPackageName(combobox3.get())
def ConnectPhoneIp(): else:
global phoneIp path = combobox3.get()
messagebox.showinfo(title="提示", message=GetCommandReturn("adb connect '{}'".format(combobox2.get()))) UninstallProgram(path)
phoneIp.append(combobox2.get()) messagebox.showinfo(message="操作执行完毕!", title="提示")
combobox2['value'] = phoneIp
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", str(json.dumps(ListToDictionary(phoneIp)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False) DisabledAndEnbled(False)
def ConnectPhoneIpDefult(): # 浏览窗口
global phoneIp def FindApk()->"浏览窗口":
messagebox.showinfo(title="提示", message=GetCommandReturn("adb connect '192.168.250.2'"))
phoneIp.append(combobox2.get())
combobox2['value'] = phoneIp
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", str(json.dumps(ListToDictionary(phoneIp)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False)
def FindApk():
path = filedialog.askopenfilename(title="选择 Apk", filetypes=[("APK 文件", "*.apk"), ("所有文件", "*.*")], initialdir=json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApk.json"))["path"]) path = filedialog.askopenfilename(title="选择 Apk", filetypes=[("APK 文件", "*.apk"), ("所有文件", "*.*")], initialdir=json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApk.json"))["path"])
if path != "" and path != "()": if path != "" and path != "()":
try: try:
@@ -75,55 +84,56 @@ def Button3Install():
DisabledAndEnbled(True) DisabledAndEnbled(True)
threading.Thread(target=InstallApk, args=(combobox1.get(),)).start() threading.Thread(target=InstallApk, args=(combobox1.get(),)).start()
def AdbRun(): # 安装应用
Return = GetCommandReturn("adb devices").replace("\n", "").replace("List of devices attached", "").replace("* daemon not running; starting now at tcp:5037", "").replace("* daemon started successfully", "") def InstallApk(path: "apk 路径", quit: "是否静默安装" = False):
if Return is "": try:
return False global findApkHistory
return True commandReturn = GetCommandReturn("pkexec /usr/bin/uengine-session-launch-helper -- uengine install --apk='{}'".format(path))
iconSavePath = "{}/.local/share/icons/hicolor/256x256/apps/{}.png".format(get_home(), GetApkPackageName(path))
def AdbConnect(): SaveApkIcon(path, iconSavePath)
return GetCommandReturn("adb devices") BuildUengineDesktop(GetApkPackageName(path), GetApkActivityName(path), GetApkChineseLabel(path), iconSavePath,
"{}/{}.desktop".format(get_desktop_path(), GetApkPackageName(path)))
def InstallApk(path): BuildUengineDesktop(GetApkPackageName(path), GetApkActivityName(path), GetApkChineseLabel(path), iconSavePath,
global findApkHistory "{}/.local/share/applications/{}.desktop".format(get_home(), GetApkPackageName(path)))
if not AdbRun(): if quit:
messagebox.showinfo(title="提示", message="你没有使用 adb 连接任何设备") print(commandReturn)
DisabledAndEnbled(False) return
return messagebox.showinfo(title="提示", message="操作完成!")
messagebox.showinfo(title="提示", message=GetCommandReturn("adb install '{}'".format(path))) findApkHistory.append(combobox1.get())
findApkHistory.append(combobox1.get()) combobox1['value'] = findApkHistory
combobox1['value'] = findApkHistory write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", str(json.dumps(ListToDictionary(findApkHistory)))) # 将历史记录的数组转换为字典并写入
write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", str(json.dumps(ListToDictionary(findApkHistory)))) # 将历史记录的数组转换为字典并写入 except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
DisabledAndEnbled(False) DisabledAndEnbled(False)
def DisabledAndEnbled(choose): # 禁用或启动所有控件
def DisabledAndEnbled(choose: "启动或者禁用")->"禁用或启动所有控件":
userChoose = {True: tk.DISABLED, False: tk.NORMAL} userChoose = {True: tk.DISABLED, False: tk.NORMAL}
a = userChoose[choose] a = userChoose[choose]
combobox1.configure(state=a) combobox1.configure(state=a)
combobox2.configure(state=a) combobox3.configure(state=a)
button1.configure(state=a)
button2.configure(state=a) button2.configure(state=a)
button3.configure(state=a) button3.configure(state=a)
button4.configure(state=a)
button5.configure(state=a) button5.configure(state=a)
button6.configure(state=a) button7.configure(state=a)
button8.configure(state=a)
# 需引入 subprocess # 需引入 subprocess
def GetCommandReturn(cmd): # 运行系统命令并获取返回值
def GetCommandReturn(cmd: "命令")->"运行系统命令并获取返回值":
# cmd 是要获取输出的命令 # cmd 是要获取输出的命令
return subprocess.getoutput(cmd) return subprocess.getoutput(cmd)
def Button5Click(): def Button5Click():
threading.Thread(target=OpenUengineProgramList).start() threading.Thread(target=OpenUengineProgramList).start()
def OpenUengineProgramList(): # 打开“uengine 所有程序列表”
def OpenUengineProgramList()->"打开“uengine 所有程序列表”":
os.system("/usr/bin/uengine-launch.sh --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity") os.system("/usr/bin/uengine-launch.sh --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity")
def ShowAdbConnect():
messagebox.showinfo(title="提示", message=AdbConnect())
# 显示“关于这个程序”窗口 # 显示“关于这个程序”窗口
def about_this_program(): def about_this_program()->"显示“关于这个程序”窗口":
global about global about
global title global title
global iconPath global iconPath
@@ -143,24 +153,25 @@ def about_this_program():
mess.mainloop() mess.mainloop()
# 显示“提示”窗口 # 显示“提示”窗口
def helps(): def helps()->"显示“提示”窗口":
global tips global tips
messagebox.showinfo(title="提示", message=tips) messagebox.showinfo(title="提示", message=tips)
# 显示更新内容窗口 # 显示更新内容窗口
def UpdateThings(): def UpdateThings()->"显示更新内容窗口":
messagebox.showinfo(title="更新内容", message=updateThings) messagebox.showinfo(title="更新内容", message=updateThings)
# 打开程序官网 # 打开程序官网
def OpenProgramURL(): def OpenProgramURL()->"打开程序官网":
webbrowser.open_new_tab(programUrl) webbrowser.open_new_tab(programUrl)
# 重启本应用程序 # 重启本应用程序
def ReStartProgram(): def ReStartProgram()->"重启本应用程序":
python = sys.executable python = sys.executable
os.execl(python, python, * sys.argv) os.execl(python, python, * sys.argv)
def CleanProgramHistory(): # 清理历史记录
def CleanProgramHistory()->"清理历史记录":
try: try:
if messagebox.askokcancel(title="警告", message="删除后将无法恢复,你确定吗?\n删除后软件将会自动重启。"): if messagebox.askokcancel(title="警告", message="删除后将无法恢复,你确定吗?\n删除后软件将会自动重启。"):
shutil.rmtree(get_home() + "/.config/uengine-runner") shutil.rmtree(get_home() + "/.config/uengine-runner")
@@ -170,10 +181,11 @@ def CleanProgramHistory():
messagebox.showerror(title="错误", message=traceback.format_exc()) messagebox.showerror(title="错误", message=traceback.format_exc())
# 获取用户主目录 # 获取用户主目录
def get_home(): def get_home()->"获取用户主目录":
return os.path.expanduser('~') return os.path.expanduser('~')
def SendUengineAndroidListForDesktop(): # 发送“启动 uengine 所有程序”的 .desktop 文件到桌面
def SendUengineAndroidListForDesktop()->"发送“启动 uengine 所有程序”的 .desktop 文件到桌面":
global desktop global desktop
global desktopName global desktopName
DisabledAndEnbled(True) DisabledAndEnbled(True)
@@ -190,7 +202,7 @@ def SendUengineAndroidListForDesktop():
DisabledAndEnbled(False) DisabledAndEnbled(False)
# 获取用户桌面目录 # 获取用户桌面目录
def get_desktop_path(): def get_desktop_path()->"获取用户桌面目录":
for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件 for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件
desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0没有返回 -1 desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0没有返回 -1
if desktop_index != -1: # 如果有对应项 if desktop_index != -1: # 如果有对应项
@@ -204,7 +216,8 @@ def get_desktop_path():
get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~) get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~)
return get # 返回目录 return get # 返回目录
def SendUengineAndroidListForLauncher(): # 发送“启动 uengine 所有程序”的 .desktop 文件到启动器
def SendUengineAndroidListForLauncher()->"发送“启动 uengine 所有程序”的 .desktop 文件到启动器":
DisabledAndEnbled(True) DisabledAndEnbled(True)
try: try:
if os.path.exists("{}/.local/share/applications/{}".format(get_home(), desktopName)): if os.path.exists("{}/.local/share/applications/{}".format(get_home(), desktopName)):
@@ -222,59 +235,154 @@ def SendUengineAndroidListForLauncher():
DisabledAndEnbled(False) DisabledAndEnbled(False)
# 数组转字典 # 数组转字典
def ListToDictionary(list): def ListToDictionary(list: "需要转换的数组")->"数组转字典":
dictionary = {} dictionary = {}
for i in range(len(list)): for i in range(len(list)):
dictionary[i] = list[i] dictionary[i] = list[i]
return dictionary return dictionary
# 读取文本文档 # 读取文本文档
def readtxt(path): def readtxt(path: "路径")->"读取文本文档":
f = open(path, "r") # 设置文件对象 f = open(path, "r") # 设置文件对象
str = f.read() # 获取内容 str = f.read() # 获取内容
f.close() # 关闭文本对象 f.close() # 关闭文本对象
return str # 返回结果 return str # 返回结果
# 写入文本文档 # 写入文本文档
def write_txt(path, things): def write_txt(path: "路径", things: "内容")->"写入文本文档":
file = open(path, 'w', encoding='UTF-8') # 设置文件对象 file = open(path, 'w', encoding='UTF-8') # 设置文件对象
file.write(things) # 写入文本 file.write(things) # 写入文本
file.close() # 关闭文本对象 file.close() # 关闭文本对象
def ShowUseProgram(): # 显示本程序所有使用的程序
def ShowUseProgram()->"显示本程序所有使用的程序":
global title global title
global useProgram global useProgram
messagebox.showinfo(title="{} 使用的程序列表(部分)".format(title), message=useProgram) messagebox.showinfo(title="{} 使用的程序列表(部分)".format(title), message=useProgram)
# 获取 aapt 的所有信息
def GetApkInformation(apkFilePath: "apk 所在路径")->"获取 aapt 的所有信息":
return GetCommandReturn("aapt dump badging '{}'".format(apkFilePath))
# 获取 apk Activity
def GetApkActivityName(apkFilePath: "apk 所在路径")->"获取 apk Activity":
info = GetApkInformation(apkFilePath)
for line in info.split('\n'):
if "launchable-activity" in line:
line = line[0: line.index("label='")]
line = line.replace("launchable-activity: ", "")
line = line.replace("'", "")
line = line.replace(" ", "")
line = line.replace("name=", "")
line = line.replace("label=", "")
line = line.replace("icon=", "")
return line
# 获取 apk 包名
def GetApkPackageName(apkFilePath: "apk 所在路径")->"获取 apk 包名":
info = GetApkInformation(apkFilePath)
for line in info.split('\n'):
if "package:" in line:
line = line[0: line.index("versionCode='")]
line = line.replace("package:", "")
line = line.replace("name=", "")
line = line.replace("'", "")
line = line.replace(" ", "")
return line
# 生成 uengine 启动文件到桌面
def BuildUengineDesktop(packageName: "软件包名", activityName: "activity", showName: "显示名称", iconPath: "程序图标所在目录", savePath:".desktop 文件保存路径")->"生成 uengine 启动文件到桌面":
things = '''[Desktop Entry]
Categories=app;
Encoding=UTF-8
Exec=/usr/bin/uengine-launch.sh --action=android.intent.action.MAIN --package={} --component={}
GenericName={}
Icon={}
MimeType=
Name={}
StartupWMClass={}
Terminal=false
Type=Application
'''.format(packageName, activityName, showName, iconPath, showName, showName)
write_txt(savePath, things)
# 获取软件的中文名称
def GetApkChineseLabel(apkFilePath)->"获取软件的中文名称":
info = GetApkInformation(apkFilePath)
for line in info.split('\n'):
if "application-label:" in line:
line = line.replace("application-label:", "")
line = line.replace("'", "")
return line
# 获取图标在包内的路径
def GetApkIconInApk(apkFilePath)->"获取图标在包内的路径":
info = GetApkInformation(apkFilePath)
for line in info.split('\n'):
if "application:" in line:
line = line[line.index("icon='"): -1]
line = line.replace("icon='", "")
if "'" in line:
line = line[0: line.index("'")]
return line
# 获取 apk 文件的图标(部分程序不支持)
def SaveApkIcon(apkFilePath, iconSavePath)->"获取 apk 文件的图标(部分程序不支持)":
zip = zipfile.ZipFile(apkFilePath)
iconData = zip.read(GetApkIconInApk(apkFilePath))
with open(iconSavePath, 'w+b') as saveIconFile:
saveIconFile.write(iconData)
# 获取用户桌面目录
def get_desktop_path()->"获取用户桌面目录":
for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件
desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0没有返回 -1
if desktop_index != -1: # 如果有对应项
break # 结束循环
if desktop_index == -1: # 如果是提前结束,值一定≠-1如果是没有提前结束值一定-1
return -1
else:
get = line[17:-2] # 截取桌面目录路径
get_index = get.find("$HOME") # 寻找是否有对应的项,需要替换内容
if get != -1: # 如果有
get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~)
return get # 返回目录
# 获取用户主目录
def get_home()->"获取用户主目录":
return os.path.expanduser('~')
########################### ###########################
# 程序信息 # 程序信息
########################### ###########################
programUrl = "https://gitee.com/gfdgd-xi/uengine-runner" programUrl = "https://gitee.com/gfdgd-xi/uengine-runner"
version = "1.1.0" version = "1.2.3"
goodRunSystem = "Linux" goodRunSystem = "Linuxdeepin/UOS"
aaptVersion = GetCommandReturn("aapt version")
about = '''一个基于 Python3 的 tkinter 制作的 uengine APK 安装器 about = '''一个基于 Python3 的 tkinter 制作的 uengine APK 安装器
版本:{} 版本:{}
适用平台:{} 适用平台:{}
tkinter 版本:{} tkinter 版本:{}
aapt 版本:{}
程序官网:{} 程序官网:{}
©2021-{} gfdgd xi'''.format(version, goodRunSystem, tk.TkVersion, programUrl, time.strftime("%Y")) ©2021-{} gfdgd xi'''.format(version, goodRunSystem, tk.TkVersion, aaptVersion,programUrl, time.strftime("%Y"))
tips = '''提示: tips = '''提示:
1、先连接设备再安装应用 1、需要你有使用 root 权限的能力;
2、支持连接其他 Android 系统操作(需要进行设置)''' 2、需要安装 uengine 才能使用;
updateThingsString = '''1、修改了因编写时出现的中、英文混用的情况 3、如果报错是有关产生 .deksotp 文件有关,一般可以打开程序列表安装。
2、支持一键连接默认 IP 如果想要连接其他手机,请使用 1.2.0 以前的版本,可以使用 adb 连接。'''
3、修复在不连接设备直接选择 apk 安装时会卡住的问题 updateThingsString = '''※1、修改了 deb 的打包,防止部分需要库没有安装;
4、修复在把“uengine 程序菜单”发送到桌面或启动器如果询问覆盖时点击取消会卡住的问题 2、修改了一个弱智错误'''
5、修改了程序界面为白色调不和标题栏冲突矛盾'''
title = "uengine 运行器 {}".format(version) title = "uengine 运行器 {}".format(version)
updateTime = "2021年5月30日" updateTime = "2021年8月2日"
updateThings = "{} 更新内容:\n{}\n更新时间{}".format(version, updateThingsString, updateTime, time.strftime("%Y")) updateThings = "{} 更新内容:\n{}\n更新时间{}".format(version, updateThingsString, updateTime, time.strftime("%Y"))
iconPath = "/opt/apps/uengine-runner/icon.png" iconPath = "{}/icon.png".format(os.path.split(os.path.realpath(__file__))[0])
desktop = "/opt/apps/uengine-runner/UengineAndroidProgramList.desktop" desktop = "/opt/apps/uengine-runner/UengineAndroidProgramList.desktop"
desktopName = "UengineAndroidProgramList.desktop" desktopName = "UengineAndroidProgramList.desktop"
useProgram = '''1、uengineanbox useProgram = '''1、uengineanbox
2、Python3 2、Python3
3、tkintertkinter.tk、ttkthemes 和 tkinter.ttk 3、tkintertkinter.tk、ttkthemes 和 tkinter.ttk
4、aapt
……''' ……'''
########################### ###########################
@@ -282,23 +390,28 @@ useProgram = '''1、uengineanbox
########################### ###########################
if not os.path.exists(get_home() + "/.config/uengine-runner"): # 如果没有配置文件夹 if not os.path.exists(get_home() + "/.config/uengine-runner"): # 如果没有配置文件夹
os.mkdir(get_home() + "/.config/uengine-runner") # 创建配置文件夹 os.mkdir(get_home() + "/.config/uengine-runner") # 创建配置文件夹
if not os.path.exists(get_home() + "/.config/uengine-runner/PhoneIp.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindApkHistory.json"): # 如果没有配置文件 if not os.path.exists(get_home() + "/.config/uengine-runner/FindApkHistory.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", json.dumps({})) # 创建配置文件 write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindUninstallApkHistory.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindUninstallApkHistory.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindApk.json"): # 如果没有配置文件 if not os.path.exists(get_home() + "/.config/uengine-runner/FindApk.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindApk.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件 write_txt(get_home() + "/.config/uengine-runner/FindApk.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindUninstallApk.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindUninstallApk.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件
########################### ###########################
# 设置变量 # 设置变量
########################### ###########################
findApkHistory = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApkHistory.json")).values()) findApkHistory = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApkHistory.json")).values())
phoneIp = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/PhoneIp.json")).values()) fineUninstallApkHistory = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/FindUninstallApkHistory.json")).values())
########################### ###########################
# 窗口创建 # 窗口创建
########################### ###########################
win = tk.Tk() win = tk.Tk() # 创建窗口
# 设置窗口所需的全局变量
checkButtonBool1 = tk.BooleanVar()
# 设置窗口
style = ttkthemes.ThemedStyle(win) style = ttkthemes.ThemedStyle(win)
style.set_theme("adapta") style.set_theme("adapta")
window = ttk.Frame(win) window = ttk.Frame(win)
@@ -306,31 +419,30 @@ win.attributes('-alpha', 0.5)
win.title(title) win.title(title)
win.resizable(0, 0) win.resizable(0, 0)
win.iconphoto(False, tk.PhotoImage(file=iconPath)) win.iconphoto(False, tk.PhotoImage(file=iconPath))
# 创建控件
frame1 = ttk.Frame(window) frame1 = ttk.Frame(window)
frame2 = ttk.Frame(window) frame2 = ttk.Frame(window)
frame3 = ttk.Frame(window)
label1 = ttk.Label(window, text="要安装的 apk 路径:") label1 = ttk.Label(window, text="要安装的 apk 路径:")
label2 = ttk.Label(window, text="要连接的设备的 IP默认 IP 为 192.168.250.2") label3 = ttk.Label(window, text="要卸载的包名或程序对应的 APK 文件")
combobox1 = ttk.Combobox(window, width=100) combobox1 = ttk.Combobox(window, width=100)
combobox2 = ttk.Combobox(window, width=100) combobox3 = ttk.Combobox(window, width=100)
button1 = ttk.Button(frame1, text="连接设备", command=ConnectPhoneIp)
button2 = ttk.Button(window, text="浏览", command=FindApk) button2 = ttk.Button(window, text="浏览", command=FindApk)
button3 = ttk.Button(frame2, text="安装", command=Button3Install) button3 = ttk.Button(frame2, text="安装", command=Button3Install)
button4 = ttk.Button(frame1, text="关闭 adb 软件进程", command=KillAdbProgress)
button5 = ttk.Button(frame2, text="打开 uengine 应用列表", command=Button5Click) button5 = ttk.Button(frame2, text="打开 uengine 应用列表", command=Button5Click)
button6 = ttk.Button(frame1, text="连接默认 IP", command=ConnectPhoneIpDefult) button7 = ttk.Button(window, text="浏览", command=ButtonClick7)
menu = tk.Menu(window, background="white") # 设置菜单栏 button8 = ttk.Button(frame3, text="卸载", command=ButtonClick8)
# 设置菜单栏
menu = tk.Menu(window, background="white")
programmenu = tk.Menu(menu, tearoff=0, background="white") # 设置“程序”菜单栏 programmenu = tk.Menu(menu, tearoff=0, background="white") # 设置“程序”菜单栏
adb = tk.Menu(menu, tearoff=0, background="white")
uengine = tk.Menu(menu, tearoff=0, background="white") uengine = tk.Menu(menu, tearoff=0, background="white")
help = tk.Menu(menu, tearoff=0, background="white") # 设置“帮助”菜单栏 help = tk.Menu(menu, tearoff=0, background="white") # 设置“帮助”菜单栏
menu.add_cascade(label="程序", menu=programmenu) menu.add_cascade(label="程序", menu=programmenu)
menu.add_cascade(label="adb", menu=adb)
menu.add_cascade(label="uengine", menu=uengine) menu.add_cascade(label="uengine", menu=uengine)
menu.add_cascade(label="帮助", menu=help) menu.add_cascade(label="帮助", menu=help)
programmenu.add_command(label="清空软件历史记录", command=CleanProgramHistory) programmenu.add_command(label="清空软件历史记录", command=CleanProgramHistory)
programmenu.add_separator() # 设置分界线 programmenu.add_separator() # 设置分界线
programmenu.add_command(label="退出程序", command=window.quit) # 设置“退出程序”项 programmenu.add_command(label="退出程序", command=window.quit) # 设置“退出程序”项
adb.add_command(label="adb 连接的设备", command=ShowAdbConnect)
uengine.add_command(label="发送 uengine 应用列表到桌面", command=SendUengineAndroidListForDesktop) uengine.add_command(label="发送 uengine 应用列表到桌面", command=SendUengineAndroidListForDesktop)
uengine.add_command(label="发送 uengine 应用列表到启动器", command=SendUengineAndroidListForLauncher) uengine.add_command(label="发送 uengine 应用列表到启动器", command=SendUengineAndroidListForLauncher)
help.add_command(label="程序官网", command=OpenProgramURL) # 设置“程序官网”项 help.add_command(label="程序官网", command=OpenProgramURL) # 设置“程序官网”项
@@ -342,24 +454,23 @@ help.add_command(label="关于这个程序", command=about_this_program) # 设
menu.configure(activebackground="white") menu.configure(activebackground="white")
help.configure(activebackground="white") help.configure(activebackground="white")
uengine.configure(activebackground="white") uengine.configure(activebackground="white")
adb.configure(activebackground="white")
programmenu.configure(activebackground="white") programmenu.configure(activebackground="white")
# 设置控件 # 设置控件
combobox2['value'] = phoneIp combobox3['value'] = fineUninstallApkHistory
combobox1['value'] = findApkHistory combobox1['value'] = findApkHistory
# # 显示控件
win.config(menu=menu) # 显示菜单栏 win.config(menu=menu) # 显示菜单栏
label1.grid(row=2, column=0) label1.grid(row=2, column=0)
label2.grid(row=0, column=0) label3.grid(row=4, column=0)
combobox1.grid(row=2, column=1) combobox1.grid(row=2, column=1)
combobox2.grid(row=0, column=1) combobox3.grid(row=4, column=1)
button1.grid(column=0, row=0)
button2.grid(row=2, column=2) button2.grid(row=2, column=2)
button3.grid(row=0, column=0) button3.grid(row=0, column=0)
button4.grid(column=1, row=0)
button5.grid(row=0, column=1) button5.grid(row=0, column=1)
button6.grid(row=0, column=3) button7.grid(row=4, column=2)
button8.grid(row=0, column=1)
frame1.grid(row=1, columnspa=3) frame1.grid(row=1, columnspa=3)
frame2.grid(row=3, columnspa=3) frame2.grid(row=3, columnspa=3)
frame3.grid(row=5, columnspa=3)
window.pack() window.pack()
win.mainloop() win.mainloop()

View File

@@ -1,365 +0,0 @@
#!/usr/bin/env python3
# 使用系统默认的 python3 运行
###########################################################################################
# 作者gfdgd xi
# 版本1.1.0
# 更新时间2021年5月30日
# 感谢anbox 和 统信
# 基于 Python3 的 tkinter 构建
###########################################################################################
#################
# 引入所需的库
#################
import os
import sys
import time
import json
import shutil
import traceback
import threading
import webbrowser
import subprocess
import ttkthemes
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.tix as tix
import tkinter.messagebox as messagebox
import tkinter.filedialog as filedialog
import PIL.Image as Image
import PIL.ImageTk as ImageTk
def KillAdbProgress():
DisabledAndEnbled(True)
Return = GetCommandReturn("killall adb")
if Return is "":
Return = "进程已经杀死!"
messagebox.showinfo(title="tips", message=Return)
DisabledAndEnbled(False)
def Button1Click():
if combobox2.get() is "":
messagebox.showerror(title="提示", message="信息没有填写完整,无法继续连接 IP")
return
DisabledAndEnbled(True)
threading.Thread(target=ConnectPhoneIp).start()
def ConnectPhoneIp():
global phoneIp
messagebox.showinfo(title="提示", message=GetCommandReturn("adb connect '{}'".format(combobox2.get())))
phoneIp.append(combobox2.get())
combobox2['value'] = phoneIp
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", str(json.dumps(ListToDictionary(phoneIp)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False)
def ConnectPhoneIpDefult():
global phoneIp
messagebox.showinfo(title="提示", message=GetCommandReturn("adb connect '192.168.250.2'"))
phoneIp.append(combobox2.get())
combobox2['value'] = phoneIp
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", str(json.dumps(ListToDictionary(phoneIp)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False)
def FindApk():
path = filedialog.askopenfilename(title="选择 Apk", filetypes=[("APK 文件", "*.apk"), ("所有文件", "*.*")], initialdir=json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApk.json"))["path"])
if path != "" and path != "()":
try:
combobox1.set(path)
write_txt(get_home() + "/.config/uengine-runner/FindApk.json", json.dumps({"path": os.path.dirname(path)})) # 写入配置文件
except:
pass
def Button3Install():
if combobox1.get() is "":
messagebox.showerror(title="提示", message="信息没有填写完整,无法继续安装 APK")
return
DisabledAndEnbled(True)
threading.Thread(target=InstallApk, args=(combobox1.get(),)).start()
def AdbRun():
Return = GetCommandReturn("adb devices").replace("\n", "").replace("List of devices attached", "").replace("* daemon not running; starting now at tcp:5037", "").replace("* daemon started successfully", "")
if Return is "":
return False
return True
def AdbConnect():
return GetCommandReturn("adb devices")
def InstallApk(path):
global findApkHistory
if not AdbRun():
messagebox.showinfo(title="提示", message="你没有使用 adb 连接任何设备")
DisabledAndEnbled(False)
return
messagebox.showinfo(title="提示", message=GetCommandReturn("adb install '{}'".format(path)))
findApkHistory.append(combobox1.get())
combobox1['value'] = findApkHistory
write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", str(json.dumps(ListToDictionary(findApkHistory)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False)
def DisabledAndEnbled(choose):
userChoose = {True: tk.DISABLED, False: tk.NORMAL}
a = userChoose[choose]
combobox1.configure(state=a)
combobox2.configure(state=a)
button1.configure(state=a)
button2.configure(state=a)
button3.configure(state=a)
button4.configure(state=a)
button5.configure(state=a)
button6.configure(state=a)
# 需引入 subprocess
def GetCommandReturn(cmd):
# cmd 是要获取输出的命令
return subprocess.getoutput(cmd)
def Button5Click():
threading.Thread(target=OpenUengineProgramList).start()
def OpenUengineProgramList():
os.system("/usr/bin/uengine-launch.sh --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity")
def ShowAdbConnect():
messagebox.showinfo(title="提示", message=AdbConnect())
# 显示“关于这个程序”窗口
def about_this_program():
global about
global title
global iconPath
mess = tk.Toplevel()
message = ttk.Frame(mess)
mess.resizable(0, 0)
mess.title("关于 {}".format(title))
mess.iconphoto(False, tk.PhotoImage(file=iconPath))
img = ImageTk.PhotoImage(Image.open(iconPath))
label1 = ttk.Label(message, image=img)
label2 = ttk.Label(message, text=about)
button1 = ttk.Button(message, text="确定", command=mess.withdraw)
label1.pack()
label2.pack()
button1.pack(side="bottom")
message.pack()
mess.mainloop()
# 显示“提示”窗口
def helps():
global tips
messagebox.showinfo(title="提示", message=tips)
# 显示更新内容窗口
def UpdateThings():
messagebox.showinfo(title="更新内容", message=updateThings)
# 打开程序官网
def OpenProgramURL():
webbrowser.open_new_tab(programUrl)
# 重启本应用程序
def ReStartProgram():
python = sys.executable
os.execl(python, python, * sys.argv)
def CleanProgramHistory():
try:
if messagebox.askokcancel(title="警告", message="删除后将无法恢复,你确定吗?\n删除后软件将会自动重启。"):
shutil.rmtree(get_home() + "/.config/uengine-runner")
ReStartProgram()
except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
# 获取用户主目录
def get_home():
return os.path.expanduser('~')
def SendUengineAndroidListForDesktop():
global desktop
global desktopName
DisabledAndEnbled(True)
try:
if os.path.exists("{}/{}".format(get_desktop_path(), desktopName)):
if not messagebox.askokcancel(title="提示", message="桌面已经存在快捷方式,你确定要覆盖吗?"):
DisabledAndEnbled(False)
return
shutil.copy(desktop, get_desktop_path())
messagebox.showinfo(title="提示", message="发送成功!")
except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
DisabledAndEnbled(False)
# 获取用户桌面目录
def get_desktop_path():
for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件
desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0没有返回 -1
if desktop_index != -1: # 如果有对应项
break # 结束循环
if desktop_index == -1: # 如果是提前结束,值一定≠-1如果是没有提前结束值一定-1
return -1
else:
get = line[17:-2] # 截取桌面目录路径
get_index = get.find("$HOME") # 寻找是否有对应的项,需要替换内容
if get != -1: # 如果有
get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~)
return get # 返回目录
def SendUengineAndroidListForLauncher():
DisabledAndEnbled(True)
try:
if os.path.exists("{}/.local/share/applications/{}".format(get_home(), desktopName)):
if not messagebox.askokcancel(title="提示", message="启动器已经存在快捷方式,你确定要覆盖吗?"):
DisabledAndEnbled(False)
return
if not os.path.exists("{}/.local/share/applications/".format(get_home())):
os.makedirs("{}/.local/share/applications/".format(get_home()))
shutil.copy(desktop, "{}/.local/share/applications/{}".format(get_home(), desktopName))
os.system("chmod 755 {}/.local/share/applications/{}".format(get_home(), desktopName))
messagebox.showinfo(title="提示", message="发送成功!")
except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
DisabledAndEnbled(False)
# 数组转字典
def ListToDictionary(list):
dictionary = {}
for i in range(len(list)):
dictionary[i] = list[i]
return dictionary
# 读取文本文档
def readtxt(path):
f = open(path, "r") # 设置文件对象
str = f.read() # 获取内容
f.close() # 关闭文本对象
return str # 返回结果
# 写入文本文档
def write_txt(path, things):
file = open(path, 'w', encoding='UTF-8') # 设置文件对象
file.write(things) # 写入文本
file.close() # 关闭文本对象
def ShowUseProgram():
global title
global useProgram
messagebox.showinfo(title="{} 使用的程序列表(部分)".format(title), message=useProgram)
###########################
# 程序信息
###########################
programUrl = "https://gitee.com/gfdgd-xi/uengine-runner"
version = "1.1.0"
goodRunSystem = "Linux"
about = '''一个基于 Python3 的 tkinter 制作的 uengine APK 安装器
版本:{}
适用平台:{}
tkinter 版本:{}
程序官网:{}
©2021-{} gfdgd xi'''.format(version, goodRunSystem, tk.TkVersion, programUrl, time.strftime("%Y"))
tips = '''提示:
1、先连接设备再安装应用
2、支持连接其他 Android 系统操作(需要进行设置)'''
updateThingsString = '''1、修改了因编写时出现的中、英文混用的情况
2、支持一键连接默认 IP
3、修复在不连接设备直接选择 apk 安装时会卡住的问题
4、修复在把“uengine 程序菜单”发送到桌面或启动器如果询问覆盖时点击取消会卡住的问题
5、修改了程序界面为白色调不和标题栏冲突矛盾'''
title = "uengine 运行器 {}".format(version)
updateTime = "2021年5月30日"
updateThings = "{} 更新内容:\n{}\n更新时间{}".format(version, updateThingsString, updateTime, time.strftime("%Y"))
iconPath = "/opt/apps/uengine-runner/icon.png"
desktop = "/opt/apps/uengine-runner/UengineAndroidProgramList.desktop"
desktopName = "UengineAndroidProgramList.desktop"
useProgram = '''1、uengineanbox
2、Python3
3、tkintertkinter.tk、ttkthemes 和 tkinter.ttk
……'''
###########################
# 加载配置
###########################
if not os.path.exists(get_home() + "/.config/uengine-runner"): # 如果没有配置文件夹
os.mkdir(get_home() + "/.config/uengine-runner") # 创建配置文件夹
if not os.path.exists(get_home() + "/.config/uengine-runner/PhoneIp.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindApkHistory.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindApk.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindApk.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件
###########################
# 设置变量
###########################
findApkHistory = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApkHistory.json")).values())
phoneIp = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/PhoneIp.json")).values())
###########################
# 窗口创建
###########################
win = tk.Tk()
style = ttkthemes.ThemedStyle(win)
style.set_theme("adapta")
window = ttk.Frame(win)
win.attributes('-alpha', 0.5)
win.title(title)
win.resizable(0, 0)
win.iconphoto(False, tk.PhotoImage(file=iconPath))
frame1 = ttk.Frame(window)
frame2 = ttk.Frame(window)
label1 = ttk.Label(window, text="要安装的 apk 路径:")
label2 = ttk.Label(window, text="要连接的设备的 IP默认 IP 为 192.168.250.2")
combobox1 = ttk.Combobox(window, width=100)
combobox2 = ttk.Combobox(window, width=100)
button1 = ttk.Button(frame1, text="连接设备", command=ConnectPhoneIp)
button2 = ttk.Button(window, text="浏览", command=FindApk)
button3 = ttk.Button(frame2, text="安装", command=Button3Install)
button4 = ttk.Button(frame1, text="关闭 adb 软件进程", command=KillAdbProgress)
button5 = ttk.Button(frame2, text="打开 uengine 应用列表", command=Button5Click)
button6 = ttk.Button(frame1, text="连接默认 IP", command=ConnectPhoneIpDefult)
menu = tk.Menu(window, background="white") # 设置菜单栏
programmenu = tk.Menu(menu, tearoff=0, background="white") # 设置“程序”菜单栏
adb = tk.Menu(menu, tearoff=0, background="white")
uengine = tk.Menu(menu, tearoff=0, background="white")
help = tk.Menu(menu, tearoff=0, background="white") # 设置“帮助”菜单栏
menu.add_cascade(label="程序", menu=programmenu)
menu.add_cascade(label="adb", menu=adb)
menu.add_cascade(label="uengine", menu=uengine)
menu.add_cascade(label="帮助", menu=help)
programmenu.add_command(label="清空软件历史记录", command=CleanProgramHistory)
programmenu.add_separator() # 设置分界线
programmenu.add_command(label="退出程序", command=window.quit) # 设置“退出程序”项
adb.add_command(label="adb 连接的设备", command=ShowAdbConnect)
uengine.add_command(label="发送 uengine 应用列表到桌面", command=SendUengineAndroidListForDesktop)
uengine.add_command(label="发送 uengine 应用列表到启动器", command=SendUengineAndroidListForLauncher)
help.add_command(label="程序官网", command=OpenProgramURL) # 设置“程序官网”项
help.add_separator()
help.add_command(label="小提示", command=helps) # 设置“小提示”项
help.add_command(label="更新内容", command=UpdateThings) # 设置“更新内容”项
help.add_command(label="这个程序使用的程序列表(部分)", command=ShowUseProgram) # 设置“更新内容”项
help.add_command(label="关于这个程序", command=about_this_program) # 设置“关于这个程序”项
menu.configure(activebackground="white")
help.configure(activebackground="white")
uengine.configure(activebackground="white")
adb.configure(activebackground="white")
programmenu.configure(activebackground="white")
# 设置控件
combobox2['value'] = phoneIp
combobox1['value'] = findApkHistory
#
win.config(menu=menu) # 显示菜单栏
label1.grid(row=2, column=0)
label2.grid(row=0, column=0)
combobox1.grid(row=2, column=1)
combobox2.grid(row=0, column=1)
button1.grid(column=0, row=0)
button2.grid(row=2, column=2)
button3.grid(row=0, column=0)
button4.grid(column=1, row=0)
button5.grid(row=0, column=1)
button6.grid(row=0, column=3)
frame1.grid(row=1, columnspa=3)
frame2.grid(row=3, columnspa=3)
window.pack()
win.mainloop()

View File

@@ -0,0 +1 @@
/opt/apps/uengine-runner/uengine-runner

View File

@@ -0,0 +1,11 @@
[Desktop Entry]
Categories=System;
Comment=uengineanbox 程序菜单
Encoding=UTF-8
Exec=/usr/bin/uengine-launch.sh --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity
Icon=/opt/apps/uengine-runner/icon.png
MimeType=
Name=uengine 程序菜单
StartupWMClass=uengine 程序菜单
Terminal=false
Type=Application

325
main.py
View File

@@ -2,9 +2,9 @@
# 使用系统默认的 python3 运行 # 使用系统默认的 python3 运行
########################################################################################### ###########################################################################################
# 作者gfdgd xi # 作者gfdgd xi
# 版本1.1.0 # 版本1.2.3
# 更新时间2021年5月30 # 更新时间2021年8月2
# 感谢anbox 和 统信 # 感谢anbox、deepin 和 UOS
# 基于 Python3 的 tkinter 构建 # 基于 Python3 的 tkinter 构建
########################################################################################### ###########################################################################################
################# #################
@@ -15,6 +15,7 @@ import sys
import time import time
import json import json
import shutil import shutil
import zipfile
import traceback import traceback
import threading import threading
import webbrowser import webbrowser
@@ -22,44 +23,52 @@ import subprocess
import ttkthemes import ttkthemes
import tkinter as tk import tkinter as tk
import tkinter.ttk as ttk import tkinter.ttk as ttk
import tkinter.tix as tix
import tkinter.messagebox as messagebox import tkinter.messagebox as messagebox
import tkinter.filedialog as filedialog import tkinter.filedialog as filedialog
import PIL.Image as Image import PIL.Image as Image
import PIL.ImageTk as ImageTk import PIL.ImageTk as ImageTk
def KillAdbProgress(): # 卸载程序
DisabledAndEnbled(True) def UninstallProgram(package: "apk 包名")->"卸载程序":
Return = GetCommandReturn("killall adb") try:
if Return is "": global fineUninstallApkHistory
Return = "进程已经杀死!" Return = GetCommandReturn("pkexec /usr/bin/uengine-session-launch-helper -- uengine uninstall --pkg='{}'".format(package))
messagebox.showinfo(title="tips", message=Return) if os.path.exists("{}/.local/share/applications/{}.desktop".format(get_home(), package)):
DisabledAndEnbled(False) os.remove("{}/.local/share/applications/{}.desktop".format(get_home(), package))
if os.path.exists("{}/{}.desktop".format(get_desktop_path(), package)):
os.remove("{}/{}.desktop".format(get_desktop_path(), package))
fineUninstallApkHistory.append(combobox3.get())
combobox3['value'] = fineUninstallApkHistory
write_txt(get_home() + "/.config/uengine-runner/FindUninstallApkHistory.json", str(json.dumps(ListToDictionary(fineUninstallApkHistory)))) # 将历史记录的数组转换为字典并写入
return Return
except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
def Button1Click(): def ButtonClick7():
if combobox2.get() is "": path = filedialog.askopenfilename(title="选择 Apk", filetypes=[("APK 文件", "*.apk"), ("所有文件", "*.*")], initialdir=json.loads(readtxt(get_home() + "/.config/uengine-runner/FindUninstallApk.json"))["path"])
messagebox.showerror(title="提示", message="信息没有填写完整,无法继续连接 IP") if path != "" and path != "()":
try:
combobox3.set(path)
write_txt(get_home() + "/.config/uengine-runner/FindUninstallApk.json", json.dumps({"path": os.path.dirname(path)})) # 写入配置文件
except:
pass
def ButtonClick8():
if combobox3.get() is "":
messagebox.showerror(title="提示", message="信息没有填写完整,无法继续卸载 APK")
return return
DisabledAndEnbled(True) DisabledAndEnbled(True)
threading.Thread(target=ConnectPhoneIp).start() if os.path.exists(combobox3.get()):
path = GetApkPackageName(combobox3.get())
def ConnectPhoneIp(): else:
global phoneIp path = combobox3.get()
messagebox.showinfo(title="提示", message=GetCommandReturn("adb connect '{}'".format(combobox2.get()))) UninstallProgram(path)
phoneIp.append(combobox2.get()) messagebox.showinfo(message="操作执行完毕!", title="提示")
combobox2['value'] = phoneIp
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", str(json.dumps(ListToDictionary(phoneIp)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False) DisabledAndEnbled(False)
def ConnectPhoneIpDefult(): # 浏览窗口
global phoneIp def FindApk()->"浏览窗口":
messagebox.showinfo(title="提示", message=GetCommandReturn("adb connect '192.168.250.2'"))
phoneIp.append(combobox2.get())
combobox2['value'] = phoneIp
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", str(json.dumps(ListToDictionary(phoneIp)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False)
def FindApk():
path = filedialog.askopenfilename(title="选择 Apk", filetypes=[("APK 文件", "*.apk"), ("所有文件", "*.*")], initialdir=json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApk.json"))["path"]) path = filedialog.askopenfilename(title="选择 Apk", filetypes=[("APK 文件", "*.apk"), ("所有文件", "*.*")], initialdir=json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApk.json"))["path"])
if path != "" and path != "()": if path != "" and path != "()":
try: try:
@@ -75,55 +84,56 @@ def Button3Install():
DisabledAndEnbled(True) DisabledAndEnbled(True)
threading.Thread(target=InstallApk, args=(combobox1.get(),)).start() threading.Thread(target=InstallApk, args=(combobox1.get(),)).start()
def AdbRun(): # 安装应用
Return = GetCommandReturn("adb devices").replace("\n", "").replace("List of devices attached", "").replace("* daemon not running; starting now at tcp:5037", "").replace("* daemon started successfully", "") def InstallApk(path: "apk 路径", quit: "是否静默安装" = False):
if Return is "": try:
return False global findApkHistory
return True commandReturn = GetCommandReturn("pkexec /usr/bin/uengine-session-launch-helper -- uengine install --apk='{}'".format(path))
iconSavePath = "{}/.local/share/icons/hicolor/256x256/apps/{}.png".format(get_home(), GetApkPackageName(path))
def AdbConnect(): SaveApkIcon(path, iconSavePath)
return GetCommandReturn("adb devices") BuildUengineDesktop(GetApkPackageName(path), GetApkActivityName(path), GetApkChineseLabel(path), iconSavePath,
"{}/{}.desktop".format(get_desktop_path(), GetApkPackageName(path)))
def InstallApk(path): BuildUengineDesktop(GetApkPackageName(path), GetApkActivityName(path), GetApkChineseLabel(path), iconSavePath,
global findApkHistory "{}/.local/share/applications/{}.desktop".format(get_home(), GetApkPackageName(path)))
if not AdbRun(): if quit:
messagebox.showinfo(title="提示", message="你没有使用 adb 连接任何设备") print(commandReturn)
DisabledAndEnbled(False) return
return messagebox.showinfo(title="提示", message="操作完成!")
messagebox.showinfo(title="提示", message=GetCommandReturn("adb install '{}'".format(path))) findApkHistory.append(combobox1.get())
findApkHistory.append(combobox1.get()) combobox1['value'] = findApkHistory
combobox1['value'] = findApkHistory write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", str(json.dumps(ListToDictionary(findApkHistory)))) # 将历史记录的数组转换为字典并写入
write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", str(json.dumps(ListToDictionary(findApkHistory)))) # 将历史记录的数组转换为字典并写入 except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
DisabledAndEnbled(False) DisabledAndEnbled(False)
def DisabledAndEnbled(choose): # 禁用或启动所有控件
def DisabledAndEnbled(choose: "启动或者禁用")->"禁用或启动所有控件":
userChoose = {True: tk.DISABLED, False: tk.NORMAL} userChoose = {True: tk.DISABLED, False: tk.NORMAL}
a = userChoose[choose] a = userChoose[choose]
combobox1.configure(state=a) combobox1.configure(state=a)
combobox2.configure(state=a) combobox3.configure(state=a)
button1.configure(state=a)
button2.configure(state=a) button2.configure(state=a)
button3.configure(state=a) button3.configure(state=a)
button4.configure(state=a)
button5.configure(state=a) button5.configure(state=a)
button6.configure(state=a) button7.configure(state=a)
button8.configure(state=a)
# 需引入 subprocess # 需引入 subprocess
def GetCommandReturn(cmd): # 运行系统命令并获取返回值
def GetCommandReturn(cmd: "命令")->"运行系统命令并获取返回值":
# cmd 是要获取输出的命令 # cmd 是要获取输出的命令
return subprocess.getoutput(cmd) return subprocess.getoutput(cmd)
def Button5Click(): def Button5Click():
threading.Thread(target=OpenUengineProgramList).start() threading.Thread(target=OpenUengineProgramList).start()
def OpenUengineProgramList(): # 打开“uengine 所有程序列表”
def OpenUengineProgramList()->"打开“uengine 所有程序列表”":
os.system("/usr/bin/uengine-launch.sh --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity") os.system("/usr/bin/uengine-launch.sh --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity")
def ShowAdbConnect():
messagebox.showinfo(title="提示", message=AdbConnect())
# 显示“关于这个程序”窗口 # 显示“关于这个程序”窗口
def about_this_program(): def about_this_program()->"显示“关于这个程序”窗口":
global about global about
global title global title
global iconPath global iconPath
@@ -143,24 +153,25 @@ def about_this_program():
mess.mainloop() mess.mainloop()
# 显示“提示”窗口 # 显示“提示”窗口
def helps(): def helps()->"显示“提示”窗口":
global tips global tips
messagebox.showinfo(title="提示", message=tips) messagebox.showinfo(title="提示", message=tips)
# 显示更新内容窗口 # 显示更新内容窗口
def UpdateThings(): def UpdateThings()->"显示更新内容窗口":
messagebox.showinfo(title="更新内容", message=updateThings) messagebox.showinfo(title="更新内容", message=updateThings)
# 打开程序官网 # 打开程序官网
def OpenProgramURL(): def OpenProgramURL()->"打开程序官网":
webbrowser.open_new_tab(programUrl) webbrowser.open_new_tab(programUrl)
# 重启本应用程序 # 重启本应用程序
def ReStartProgram(): def ReStartProgram()->"重启本应用程序":
python = sys.executable python = sys.executable
os.execl(python, python, * sys.argv) os.execl(python, python, * sys.argv)
def CleanProgramHistory(): # 清理历史记录
def CleanProgramHistory()->"清理历史记录":
try: try:
if messagebox.askokcancel(title="警告", message="删除后将无法恢复,你确定吗?\n删除后软件将会自动重启。"): if messagebox.askokcancel(title="警告", message="删除后将无法恢复,你确定吗?\n删除后软件将会自动重启。"):
shutil.rmtree(get_home() + "/.config/uengine-runner") shutil.rmtree(get_home() + "/.config/uengine-runner")
@@ -170,10 +181,11 @@ def CleanProgramHistory():
messagebox.showerror(title="错误", message=traceback.format_exc()) messagebox.showerror(title="错误", message=traceback.format_exc())
# 获取用户主目录 # 获取用户主目录
def get_home(): def get_home()->"获取用户主目录":
return os.path.expanduser('~') return os.path.expanduser('~')
def SendUengineAndroidListForDesktop(): # 发送“启动 uengine 所有程序”的 .desktop 文件到桌面
def SendUengineAndroidListForDesktop()->"发送“启动 uengine 所有程序”的 .desktop 文件到桌面":
global desktop global desktop
global desktopName global desktopName
DisabledAndEnbled(True) DisabledAndEnbled(True)
@@ -190,7 +202,7 @@ def SendUengineAndroidListForDesktop():
DisabledAndEnbled(False) DisabledAndEnbled(False)
# 获取用户桌面目录 # 获取用户桌面目录
def get_desktop_path(): def get_desktop_path()->"获取用户桌面目录":
for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件 for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件
desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0没有返回 -1 desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0没有返回 -1
if desktop_index != -1: # 如果有对应项 if desktop_index != -1: # 如果有对应项
@@ -204,7 +216,8 @@ def get_desktop_path():
get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~) get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~)
return get # 返回目录 return get # 返回目录
def SendUengineAndroidListForLauncher(): # 发送“启动 uengine 所有程序”的 .desktop 文件到启动器
def SendUengineAndroidListForLauncher()->"发送“启动 uengine 所有程序”的 .desktop 文件到启动器":
DisabledAndEnbled(True) DisabledAndEnbled(True)
try: try:
if os.path.exists("{}/.local/share/applications/{}".format(get_home(), desktopName)): if os.path.exists("{}/.local/share/applications/{}".format(get_home(), desktopName)):
@@ -222,59 +235,154 @@ def SendUengineAndroidListForLauncher():
DisabledAndEnbled(False) DisabledAndEnbled(False)
# 数组转字典 # 数组转字典
def ListToDictionary(list): def ListToDictionary(list: "需要转换的数组")->"数组转字典":
dictionary = {} dictionary = {}
for i in range(len(list)): for i in range(len(list)):
dictionary[i] = list[i] dictionary[i] = list[i]
return dictionary return dictionary
# 读取文本文档 # 读取文本文档
def readtxt(path): def readtxt(path: "路径")->"读取文本文档":
f = open(path, "r") # 设置文件对象 f = open(path, "r") # 设置文件对象
str = f.read() # 获取内容 str = f.read() # 获取内容
f.close() # 关闭文本对象 f.close() # 关闭文本对象
return str # 返回结果 return str # 返回结果
# 写入文本文档 # 写入文本文档
def write_txt(path, things): def write_txt(path: "路径", things: "内容")->"写入文本文档":
file = open(path, 'w', encoding='UTF-8') # 设置文件对象 file = open(path, 'w', encoding='UTF-8') # 设置文件对象
file.write(things) # 写入文本 file.write(things) # 写入文本
file.close() # 关闭文本对象 file.close() # 关闭文本对象
def ShowUseProgram(): # 显示本程序所有使用的程序
def ShowUseProgram()->"显示本程序所有使用的程序":
global title global title
global useProgram global useProgram
messagebox.showinfo(title="{} 使用的程序列表(部分)".format(title), message=useProgram) messagebox.showinfo(title="{} 使用的程序列表(部分)".format(title), message=useProgram)
# 获取 aapt 的所有信息
def GetApkInformation(apkFilePath: "apk 所在路径")->"获取 aapt 的所有信息":
return GetCommandReturn("aapt dump badging '{}'".format(apkFilePath))
# 获取 apk Activity
def GetApkActivityName(apkFilePath: "apk 所在路径")->"获取 apk Activity":
info = GetApkInformation(apkFilePath)
for line in info.split('\n'):
if "launchable-activity" in line:
line = line[0: line.index("label='")]
line = line.replace("launchable-activity: ", "")
line = line.replace("'", "")
line = line.replace(" ", "")
line = line.replace("name=", "")
line = line.replace("label=", "")
line = line.replace("icon=", "")
return line
# 获取 apk 包名
def GetApkPackageName(apkFilePath: "apk 所在路径")->"获取 apk 包名":
info = GetApkInformation(apkFilePath)
for line in info.split('\n'):
if "package:" in line:
line = line[0: line.index("versionCode='")]
line = line.replace("package:", "")
line = line.replace("name=", "")
line = line.replace("'", "")
line = line.replace(" ", "")
return line
# 生成 uengine 启动文件到桌面
def BuildUengineDesktop(packageName: "软件包名", activityName: "activity", showName: "显示名称", iconPath: "程序图标所在目录", savePath:".desktop 文件保存路径")->"生成 uengine 启动文件到桌面":
things = '''[Desktop Entry]
Categories=app;
Encoding=UTF-8
Exec=/usr/bin/uengine-launch.sh --action=android.intent.action.MAIN --package={} --component={}
GenericName={}
Icon={}
MimeType=
Name={}
StartupWMClass={}
Terminal=false
Type=Application
'''.format(packageName, activityName, showName, iconPath, showName, showName)
write_txt(savePath, things)
# 获取软件的中文名称
def GetApkChineseLabel(apkFilePath)->"获取软件的中文名称":
info = GetApkInformation(apkFilePath)
for line in info.split('\n'):
if "application-label:" in line:
line = line.replace("application-label:", "")
line = line.replace("'", "")
return line
# 获取图标在包内的路径
def GetApkIconInApk(apkFilePath)->"获取图标在包内的路径":
info = GetApkInformation(apkFilePath)
for line in info.split('\n'):
if "application:" in line:
line = line[line.index("icon='"): -1]
line = line.replace("icon='", "")
if "'" in line:
line = line[0: line.index("'")]
return line
# 获取 apk 文件的图标(部分程序不支持)
def SaveApkIcon(apkFilePath, iconSavePath)->"获取 apk 文件的图标(部分程序不支持)":
zip = zipfile.ZipFile(apkFilePath)
iconData = zip.read(GetApkIconInApk(apkFilePath))
with open(iconSavePath, 'w+b') as saveIconFile:
saveIconFile.write(iconData)
# 获取用户桌面目录
def get_desktop_path()->"获取用户桌面目录":
for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件
desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0没有返回 -1
if desktop_index != -1: # 如果有对应项
break # 结束循环
if desktop_index == -1: # 如果是提前结束,值一定≠-1如果是没有提前结束值一定-1
return -1
else:
get = line[17:-2] # 截取桌面目录路径
get_index = get.find("$HOME") # 寻找是否有对应的项,需要替换内容
if get != -1: # 如果有
get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~)
return get # 返回目录
# 获取用户主目录
def get_home()->"获取用户主目录":
return os.path.expanduser('~')
########################### ###########################
# 程序信息 # 程序信息
########################### ###########################
programUrl = "https://gitee.com/gfdgd-xi/uengine-runner" programUrl = "https://gitee.com/gfdgd-xi/uengine-runner"
version = "1.1.0" version = "1.2.3"
goodRunSystem = "Linux" goodRunSystem = "Linuxdeepin/UOS"
aaptVersion = GetCommandReturn("aapt version")
about = '''一个基于 Python3 的 tkinter 制作的 uengine APK 安装器 about = '''一个基于 Python3 的 tkinter 制作的 uengine APK 安装器
版本:{} 版本:{}
适用平台:{} 适用平台:{}
tkinter 版本:{} tkinter 版本:{}
aapt 版本:{}
程序官网:{} 程序官网:{}
©2021-{} gfdgd xi'''.format(version, goodRunSystem, tk.TkVersion, programUrl, time.strftime("%Y")) ©2021-{} gfdgd xi'''.format(version, goodRunSystem, tk.TkVersion, aaptVersion,programUrl, time.strftime("%Y"))
tips = '''提示: tips = '''提示:
1、先连接设备再安装应用 1、需要你有使用 root 权限的能力;
2、支持连接其他 Android 系统操作(需要进行设置)''' 2、需要安装 uengine 才能使用;
updateThingsString = '''1、修改了因编写时出现的中、英文混用的情况 3、如果报错是有关产生 .deksotp 文件有关,一般可以打开程序列表安装。
2、支持一键连接默认 IP 如果想要连接其他手机,请使用 1.2.0 以前的版本,可以使用 adb 连接。'''
3、修复在不连接设备直接选择 apk 安装时会卡住的问题 updateThingsString = '''※1、修改了 deb 的打包,防止部分需要库没有安装;
4、修复在把“uengine 程序菜单”发送到桌面或启动器如果询问覆盖时点击取消会卡住的问题 2、修改了一个弱智错误'''
5、修改了程序界面为白色调不和标题栏冲突矛盾'''
title = "uengine 运行器 {}".format(version) title = "uengine 运行器 {}".format(version)
updateTime = "2021年5月30" updateTime = "2021年8月2"
updateThings = "{} 更新内容:\n{}\n更新时间:{}".format(version, updateThingsString, updateTime, time.strftime("%Y")) updateThings = "{} 更新内容:\n{}\n更新时间:{}".format(version, updateThingsString, updateTime, time.strftime("%Y"))
iconPath = "/opt/apps/uengine-runner/icon.png" iconPath = "{}/icon.png".format(os.path.split(os.path.realpath(__file__))[0])
desktop = "/opt/apps/uengine-runner/UengineAndroidProgramList.desktop" desktop = "/opt/apps/uengine-runner/UengineAndroidProgramList.desktop"
desktopName = "UengineAndroidProgramList.desktop" desktopName = "UengineAndroidProgramList.desktop"
useProgram = '''1、uengineanbox useProgram = '''1、uengineanbox
2、Python3 2、Python3
3、tkintertkinter.tk、ttkthemes 和 tkinter.ttk 3、tkintertkinter.tk、ttkthemes 和 tkinter.ttk
4、aapt
……''' ……'''
########################### ###########################
@@ -282,23 +390,28 @@ useProgram = '''1、uengineanbox
########################### ###########################
if not os.path.exists(get_home() + "/.config/uengine-runner"): # 如果没有配置文件夹 if not os.path.exists(get_home() + "/.config/uengine-runner"): # 如果没有配置文件夹
os.mkdir(get_home() + "/.config/uengine-runner") # 创建配置文件夹 os.mkdir(get_home() + "/.config/uengine-runner") # 创建配置文件夹
if not os.path.exists(get_home() + "/.config/uengine-runner/PhoneIp.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindApkHistory.json"): # 如果没有配置文件 if not os.path.exists(get_home() + "/.config/uengine-runner/FindApkHistory.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", json.dumps({})) # 创建配置文件 write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindUninstallApkHistory.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindUninstallApkHistory.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindApk.json"): # 如果没有配置文件 if not os.path.exists(get_home() + "/.config/uengine-runner/FindApk.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindApk.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件 write_txt(get_home() + "/.config/uengine-runner/FindApk.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindUninstallApk.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindUninstallApk.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件
########################### ###########################
# 设置变量 # 设置变量
########################### ###########################
findApkHistory = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApkHistory.json")).values()) findApkHistory = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApkHistory.json")).values())
phoneIp = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/PhoneIp.json")).values()) fineUninstallApkHistory = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/FindUninstallApkHistory.json")).values())
########################### ###########################
# 窗口创建 # 窗口创建
########################### ###########################
win = tk.Tk() win = tk.Tk() # 创建窗口
# 设置窗口所需的全局变量
checkButtonBool1 = tk.BooleanVar()
# 设置窗口
style = ttkthemes.ThemedStyle(win) style = ttkthemes.ThemedStyle(win)
style.set_theme("adapta") style.set_theme("adapta")
window = ttk.Frame(win) window = ttk.Frame(win)
@@ -306,31 +419,30 @@ win.attributes('-alpha', 0.5)
win.title(title) win.title(title)
win.resizable(0, 0) win.resizable(0, 0)
win.iconphoto(False, tk.PhotoImage(file=iconPath)) win.iconphoto(False, tk.PhotoImage(file=iconPath))
# 创建控件
frame1 = ttk.Frame(window) frame1 = ttk.Frame(window)
frame2 = ttk.Frame(window) frame2 = ttk.Frame(window)
frame3 = ttk.Frame(window)
label1 = ttk.Label(window, text="要安装的 apk 路径:") label1 = ttk.Label(window, text="要安装的 apk 路径:")
label2 = ttk.Label(window, text="连接的设备的 IP默认 IP 为 192.168.250.2") label3 = ttk.Label(window, text="卸载的包名或程序对应的 APK 文件")
combobox1 = ttk.Combobox(window, width=100) combobox1 = ttk.Combobox(window, width=100)
combobox2 = ttk.Combobox(window, width=100) combobox3 = ttk.Combobox(window, width=100)
button1 = ttk.Button(frame1, text="连接设备", command=ConnectPhoneIp)
button2 = ttk.Button(window, text="浏览", command=FindApk) button2 = ttk.Button(window, text="浏览", command=FindApk)
button3 = ttk.Button(frame2, text="安装", command=Button3Install) button3 = ttk.Button(frame2, text="安装", command=Button3Install)
button4 = ttk.Button(frame1, text="关闭 adb 软件进程", command=KillAdbProgress)
button5 = ttk.Button(frame2, text="打开 uengine 应用列表", command=Button5Click) button5 = ttk.Button(frame2, text="打开 uengine 应用列表", command=Button5Click)
button6 = ttk.Button(frame1, text="连接默认 IP", command=ConnectPhoneIpDefult) button7 = ttk.Button(window, text="浏览", command=ButtonClick7)
menu = tk.Menu(window, background="white") # 设置菜单栏 button8 = ttk.Button(frame3, text="卸载", command=ButtonClick8)
# 设置菜单栏
menu = tk.Menu(window, background="white")
programmenu = tk.Menu(menu, tearoff=0, background="white") # 设置“程序”菜单栏 programmenu = tk.Menu(menu, tearoff=0, background="white") # 设置“程序”菜单栏
adb = tk.Menu(menu, tearoff=0, background="white")
uengine = tk.Menu(menu, tearoff=0, background="white") uengine = tk.Menu(menu, tearoff=0, background="white")
help = tk.Menu(menu, tearoff=0, background="white") # 设置“帮助”菜单栏 help = tk.Menu(menu, tearoff=0, background="white") # 设置“帮助”菜单栏
menu.add_cascade(label="程序", menu=programmenu) menu.add_cascade(label="程序", menu=programmenu)
menu.add_cascade(label="adb", menu=adb)
menu.add_cascade(label="uengine", menu=uengine) menu.add_cascade(label="uengine", menu=uengine)
menu.add_cascade(label="帮助", menu=help) menu.add_cascade(label="帮助", menu=help)
programmenu.add_command(label="清空软件历史记录", command=CleanProgramHistory) programmenu.add_command(label="清空软件历史记录", command=CleanProgramHistory)
programmenu.add_separator() # 设置分界线 programmenu.add_separator() # 设置分界线
programmenu.add_command(label="退出程序", command=window.quit) # 设置“退出程序”项 programmenu.add_command(label="退出程序", command=window.quit) # 设置“退出程序”项
adb.add_command(label="adb 连接的设备", command=ShowAdbConnect)
uengine.add_command(label="发送 uengine 应用列表到桌面", command=SendUengineAndroidListForDesktop) uengine.add_command(label="发送 uengine 应用列表到桌面", command=SendUengineAndroidListForDesktop)
uengine.add_command(label="发送 uengine 应用列表到启动器", command=SendUengineAndroidListForLauncher) uengine.add_command(label="发送 uengine 应用列表到启动器", command=SendUengineAndroidListForLauncher)
help.add_command(label="程序官网", command=OpenProgramURL) # 设置“程序官网”项 help.add_command(label="程序官网", command=OpenProgramURL) # 设置“程序官网”项
@@ -342,24 +454,23 @@ help.add_command(label="关于这个程序", command=about_this_program) # 设
menu.configure(activebackground="white") menu.configure(activebackground="white")
help.configure(activebackground="white") help.configure(activebackground="white")
uengine.configure(activebackground="white") uengine.configure(activebackground="white")
adb.configure(activebackground="white")
programmenu.configure(activebackground="white") programmenu.configure(activebackground="white")
# 设置控件 # 设置控件
combobox2['value'] = phoneIp combobox3['value'] = fineUninstallApkHistory
combobox1['value'] = findApkHistory combobox1['value'] = findApkHistory
# # 显示控件
win.config(menu=menu) # 显示菜单栏 win.config(menu=menu) # 显示菜单栏
label1.grid(row=2, column=0) label1.grid(row=2, column=0)
label2.grid(row=0, column=0) label3.grid(row=4, column=0)
combobox1.grid(row=2, column=1) combobox1.grid(row=2, column=1)
combobox2.grid(row=0, column=1) combobox3.grid(row=4, column=1)
button1.grid(column=0, row=0)
button2.grid(row=2, column=2) button2.grid(row=2, column=2)
button3.grid(row=0, column=0) button3.grid(row=0, column=0)
button4.grid(column=1, row=0)
button5.grid(row=0, column=1) button5.grid(row=0, column=1)
button6.grid(row=0, column=3) button7.grid(row=4, column=2)
button8.grid(row=0, column=1)
frame1.grid(row=1, columnspa=3) frame1.grid(row=1, columnspa=3)
frame2.grid(row=3, columnspa=3) frame2.grid(row=3, columnspa=3)
frame3.grid(row=5, columnspa=3)
window.pack() window.pack()
win.mainloop() win.mainloop()

Binary file not shown.

View File

@@ -0,0 +1,16 @@
[Desktop Entry]
Categories=system;Utility;
Encoding=UTF-8
Exec=uengine-runner -ci %F
GenericName=APK 安装uengine
GenericName[zh_CN]=APK 安装uengine
Icon=/opt/apps/uengine-runner/icon.png
MimeType=application/apk;
Name=APK 安装uengine
Name[zh_CN]=APK 安装uengine
NoDisplay=true
OnlyShowIn=Unity;
StartupNotify=false
StartupWMClass=APK 安装uengine
Terminal=false
Type=Application

View File

@@ -1,299 +0,0 @@
#!/usr/bin/env python3
# 使用系统默认的 python3 运行
###########################################################################################
# 作者gfdgd xi
# 版本1.0.0
# 更新时间2021年
# 感谢:
# 基于 Python3 的 tkinter 构建
###########################################################################################
#################
# 引入所需的库
#################
import os
import sys
import time
import json
import shutil
import traceback
import threading
import webbrowser
import subprocess
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
import tkinter.filedialog as filedialog
import PIL.Image as Image
import PIL.ImageTk as ImageTk
def KillAdbProgress():
DisabledAndEnbled(True)
Return = GetCommandReturn("killall adb")
if Return is "":
Return = "OK!"
messagebox.showinfo(title="tips", message=Return)
DisabledAndEnbled(False)
def Button1Click():
if combobox2.get() is "":
messagebox.showerror(title="Tips", message="Don't input right things in ComboBox")
return
DisabledAndEnbled(True)
threading.Thread(target=ConnectPhoneIp).start()
def ConnectPhoneIp():
global phoneIp
messagebox.showinfo(title="tips", message=GetCommandReturn("adb connect '{}'".format(combobox2.get())))
phoneIp.append(combobox2.get())
combobox2['value'] = phoneIp
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", str(json.dumps(ListToDictionary(phoneIp)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False)
def FindApk():
path = filedialog.askopenfilename(title="选择 Apk", filetypes=[("APK 文件", "*.apk"), ("所有文件", "*.*")], initialdir=json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApk.json"))["path"])
if not path is "":
combobox1.set(path)
write_txt(get_home() + "/.config/uengine-runner/FindApk.json", json.dumps({"path": os.path.dirname(path)})) # 写入配置文件
def Button3Install():
if combobox1.get() is "":
messagebox.showerror(title="Tips", message="Don't input right things in ComboBox")
return
DisabledAndEnbled(True)
threading.Thread(target=InstallApk, args=(combobox1.get(),)).start()
def InstallApk(path):
global findApkHistory
messagebox.showinfo(title="Tips", message=GetCommandReturn("adb install '{}'".format(path)))
findApkHistory.append(combobox1.get())
combobox1['value'] = findApkHistory
write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", str(json.dumps(ListToDictionary(findApkHistory)))) # 将历史记录的数组转换为字典并写入
DisabledAndEnbled(False)
def DisabledAndEnbled(choose):
userChoose = {True: tk.DISABLED, False: tk.NORMAL}
a = userChoose[choose]
combobox1.configure(state=a)
combobox2.configure(state=a)
button1.configure(state=a)
button2.configure(state=a)
button3.configure(state=a)
button4.configure(state=a)
button5.configure(state=a)
# 需引入 subprocess
def GetCommandReturn(cmd):
# cmd 是要获取输出的命令
return subprocess.getoutput(cmd)
def Button5Click():
threading.Thread(target=OpenUengineProgramList).start()
def OpenUengineProgramList():
os.system("/usr/bin/uengine-launch.sh --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity")
# 显示“关于这个程序”窗口
def about_this_program():
global about
global title
global iconPath
message = tk.Toplevel()
message.title("关于 {}".format(title))
message.iconphoto(False, tk.PhotoImage(file=iconPath))
img = ImageTk.PhotoImage(Image.open(iconPath))
label1 = ttk.Label(message, image=img)
label2 = ttk.Label(message, text=about)
button1 = ttk.Button(message, text="确定", command=message.withdraw)
label1.pack()
label2.pack()
button1.pack(side="bottom")
message.mainloop()
# 显示“提示”窗口
def helps():
global tips
messagebox.showinfo(title="提示", message=tips)
# 显示更新内容窗口
def UpdateThings():
messagebox.showinfo(title="更新内容", message=updateThings)
# 打开程序官网
def OpenProgramURL():
webbrowser.open_new_tab(programUrl)
# 重启本应用程序
def ReStartProgram():
python = sys.executable
os.execl(python, python, * sys.argv)
def CleanProgramHistory():
try:
if messagebox.askokcancel(title="警告", message="删除后将无法恢复,你确定吗?\n删除后软件将会自动重启。"):
shutil.rmtree(get_home() + "/.config/uengine-runner")
ReStartProgram()
except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
# 获取用户主目录
def get_home():
return os.path.expanduser('~')
def SendUengineAndroidListForDesktop():
global desktop
global desktopName
DisabledAndEnbled(True)
try:
if os.path.exists("{}/{}".format(get_desktop_path(), desktopName)):
if not messagebox.askokcancel(title="提示", message="桌面已经存在快捷方式,你确定要覆盖吗?"):
return
shutil.copy(desktop, get_desktop_path())
messagebox.showinfo(title="提示", message="发送成功!")
except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
DisabledAndEnbled(False)
# 获取用户桌面目录
def get_desktop_path():
for line in open(get_home() + "/.config/user-dirs.dirs"): # 以行来读取配置文件
desktop_index = line.find("XDG_DESKTOP_DIR=\"") # 寻找是否有对应项,有返回 0没有返回 -1
if desktop_index != -1: # 如果有对应项
break # 结束循环
if desktop_index == -1: # 如果是提前结束,值一定≠-1如果是没有提前结束值一定-1
return -1
else:
get = line[17:-2] # 截取桌面目录路径
get_index = get.find("$HOME") # 寻找是否有对应的项,需要替换内容
if get != -1: # 如果有
get = get.replace("$HOME", get_home()) # 则把其替换为用户目录(~)
return get # 返回目录
def SendUengineAndroidListForLauncher():
DisabledAndEnbled(True)
try:
if os.path.exists("{}/.local/share/applications/{}".format(get_home(), desktopName)):
if not messagebox.askokcancel(title="提示", message="启动器已经存在快捷方式,你确定要覆盖吗?"):
return
if not os.path.exists("{}/.local/share/applications/".format(get_home())):
os.makedirs("{}/.local/share/applications/".format(get_home()))
shutil.copy(desktop, "{}/.local/share/applications/{}".format(get_home(), desktopName))
os.system("chmod 755 {}/.local/share/applications/{}".format(get_home(), desktopName))
messagebox.showinfo(title="提示", message="发送成功!")
except:
traceback.print_exc()
messagebox.showerror(title="错误", message=traceback.format_exc())
DisabledAndEnbled(False)
# 数组转字典
def ListToDictionary(list):
dictionary = {}
for i in range(len(list)):
dictionary[i] = list[i]
return dictionary
# 读取文本文档
def readtxt(path):
f = open(path, "r") # 设置文件对象
str = f.read() # 获取内容
f.close() # 关闭文本对象
return str # 返回结果
# 写入文本文档
def write_txt(path, things):
file = open(path, 'w', encoding='UTF-8') # 设置文件对象
file.write(things) # 写入文本
file.close() # 关闭文本对象
###########################
# 程序信息
###########################
programUrl = "https://gitee.com/gfdgd-xi/uengine-runner"
version = "1.0.0"
goodRunSystem = "Linux"
about = '''一个基于 Python3 的 tkinter 制作的 uengine APK 安装器
版本:{}
适用平台:{}
tkinter 版本:{}
程序官网:{}
©2021-{} gfdgd xi'''.format(version, goodRunSystem, tk.TkVersion, programUrl, time.strftime("%Y"))
tips = '''提示:
1、None'''
updateThingsString = ''''''
title = "uengine 运行器 {}".format(version)
updateTime = "2021年"
updateThings = "{} 更新内容:\n{}\n更新时间{}".format(version, updateThingsString, updateTime, time.strftime("%Y"))
iconPath = "/opt/apps/uengine-runner/icon.png"
desktop = "/opt/apps/uengine-runner/UengineAndroidProgramList.desktop"
desktopName = "UengineAndroidProgramList.desktop"
###########################
# 加载配置
###########################
if not os.path.exists(get_home() + "/.config/uengine-runner"): # 如果没有配置文件夹
os.mkdir(get_home() + "/.config/uengine-runner") # 创建配置文件夹
if not os.path.exists(get_home() + "/.config/uengine-runner/PhoneIp.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/PhoneIp.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindApkHistory.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindApkHistory.json", json.dumps({})) # 创建配置文件
if not os.path.exists(get_home() + "/.config/uengine-runner/FindApk.json"): # 如果没有配置文件
write_txt(get_home() + "/.config/uengine-runner/FindApk.json", json.dumps({"path": "~"})) # 写入(创建)一个配置文件
###########################
# 设置变量
###########################
findApkHistory = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/FindApkHistory.json")).values())
phoneIp = list(json.loads(readtxt(get_home() + "/.config/uengine-runner/PhoneIp.json")).values())
###########################
# 窗口创建
###########################
window = tk.Tk()
window.title(title)
window.iconphoto(False, tk.PhotoImage(file=iconPath))
frame1 = ttk.Frame(window)
frame2 = ttk.Frame(window)
label1 = ttk.Label(window, text="要安装的 apk 路径:")
label2 = ttk.Label(window, text="要连接的设备的 IP默认 IP 为 192.168.250.2")
combobox1 = ttk.Combobox(window, width=100)
combobox2 = ttk.Combobox(window, width=100)
button1 = ttk.Button(frame1, text="连接设备", command=ConnectPhoneIp)
button2 = ttk.Button(window, text="浏览", command=FindApk)
button3 = ttk.Button(frame2, text="安装", command=Button3Install)
button4 = ttk.Button(frame1, text="Kill Adb Progress", command=KillAdbProgress)
button5 = ttk.Button(frame2, text="Open uengine Program List", command=Button5Click)
menu = tk.Menu(window) # 设置菜单栏
programmenu = tk.Menu(menu, tearoff=0) # 设置“程序”菜单栏
menu.add_cascade(label="程序", menu=programmenu)
programmenu.add_command(label="清空软件历史记录", command=CleanProgramHistory)
programmenu.add_separator() # 设置分界线
programmenu.add_command(label="退出程序", command=window.quit) # 设置“退出程序”项
uengine = tk.Menu(menu, tearoff=0)
menu.add_cascade(label="uengine", menu=uengine)
uengine.add_command(label="发送 uengine 应用列表到桌面", command=SendUengineAndroidListForDesktop)
uengine.add_command(label="发送 uengine 应用列表到启动器", command=SendUengineAndroidListForLauncher)
help = tk.Menu(menu, tearoff=0) # 设置“帮助”菜单栏
menu.add_cascade(label="帮助", menu=help)
help.add_command(label="程序官网", command=OpenProgramURL) # 设置“程序官网”项
help.add_separator()
help.add_command(label="小提示", command=helps) # 设置“小提示”项
help.add_command(label="更新内容", command=UpdateThings) # 设置“更新内容”项
help.add_command(label="关于这个程序", command=about_this_program) # 设置“关于这个程序”项
# 设置控件
combobox2['value'] = phoneIp
combobox1['value'] = findApkHistory
#
window.config(menu=menu) # 显示菜单栏
label1.grid(row=2, column=0)
label2.grid(row=0, column=0)
combobox1.grid(row=2, column=1)
combobox2.grid(row=0, column=1)
button1.grid(column=0, row=0)
button2.grid(row=2, column=2)
button3.grid(row=0, column=0)
button4.grid(column=1, row=0)
button5.grid(row=0, column=1)
frame1.grid(row=1, columnspa=3)
frame2.grid(row=3, columnspa=3)
window.mainloop()

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB