基于pywebview的桌面小工具开发记录

近期工作上有一个新的需求:开发一个桌面端小工具,用来将用户端数据按照标准协议转换并输出。工作以来,B/S项目是主要工作内容,其他的基于console的工具、手机端app也有一些,但是GUI的开发还是首次。

1. 技术选型

因为前段时间用pandas做了一些数据处理,非常欣赏pandas这种数据处理、数据分析的能力,思考了下项目中对excel的处理转换pandas都可以满足,所以打算基于python来完成这个小项目。python的GUI技术/框架非常多,可以参考GUI Programming in Python.

1. 原生GUI框架

最开始考虑使用原生GUI,于是基于google做了一些初步的调研分析:

GUI技术 优点 缺点
TKinter 原生,安装包小,性能好 容易上手,界面美化困难,代码结构不好,组件少,功能少,只适合极简的小工具
PyQT5 技术成熟,功能强大,多平台通用,界面精美 复杂度高,学习成本高,商业付费,打包后程序几百兆
PyGtk 跟PyQt一样,可以实现很不错的效果,但是稍逊于PyQt,并且同样有UI设计工具Glade 更适合GNOME平台
wxPython 免费开源,提供了设计器,复杂度比PyQT5低,能力比TK强 设计器不够强大,复杂界面不适合,界面美观度不够,跨平台可能需要调试
PySimpleGUI 基于Tkinter、Remi、wxPython和PyQt的封装,文档和示例丰富,封装了api,开发效率高,适合短平快项目 封装屏蔽了底层技术的实现细节,组件在各个底层技术上不全部通用

因为这个项目是一整套商业化平台的配套工具,许可问题放弃PyQT5;同时因为终端要支持mac和windows,PyGtk不适合;放弃TK是因为它的组件和功能满足不了项目需求;剩下的wxPython或者PySimpleGUI大致是比较接近需求的方案,不过上面列出的缺点也是让我有些顾虑。

2. 基于web的GUI实现

原生GUI框架避免不了的问题就是增加了额外的学习成本,Python的GUI实现也有一些基于web的实现框架,web的界面操作能力和开发效率都不是原生GUI能比的,如果能用web来解决需求,那当然是最合适的。初步调查结果如下:

技术 优点 缺点
EEL 非常轻量级,托管本地web服务器,实现python的js的互相调用 不原生支持flask等,需要系统提前安装chrome;打包后文件大;右键菜单不能禁用;
QWebview - 基于QT,许可问题
flaskwebgui 支持flask、fastapi、django等框架 依赖chrome,活跃度低不够成熟
PyWebview 轻量级,基于系统自带浏览器,启动速度快,支持flask 框架开放的接口有限,多平台打包需要调试
electron 基于nodejs,开发效率高,跨平台,vscode高山仰止 体积和内存占用比较大,不支持xp,部分api非全平台兼容,效率不如原生

调研过程中,被electron种草,不过最终决定不改初衷,这个项目还是使用ython+PyWebview实现;但是如果pywebview在使用中遇到比较严重的坑,也做好了随时切换到nodejs+electron的心理准备;中间也曾想过,使用python+nodejs+electron来实现,这样就兼顾到了electron和pandas,不过这样做毕竟不太优雅,为了把nodejs和python黏合到一起,同时运行了两套运行时,和一个额外的socket服务,不是第一选择。

2. 开发

pywebview支持两种方式集成html/js/css,一种是使用简易的内置的web服务器,一种是使用第三方的web框架,比如flask。因为内置web服务器局限性比较大也不够灵活,项目基于flask搭建。前端UI框架因为考虑到兼容IE使用了layui;数据处理使用pandas;项目打包使用pyinstaller

项目部分结构如下:

image.png
  1. biz:python主体逻辑部分
    • biz/App.py: flask应用构建和路由
    • biz/Configs.py: 项目配置,包括环境参数、窗口参数、日志等
    • biz/JsAPI.py: python数据处理类,暴露给前端js直接调用
    • biz/WebAPI.py: flask每条路由的处理方法类,前端可以通过ajax请求路由实现调用python的全部能力,加载web页面时候使用此方法可以向前端传递一些必要参数
    • biz/WindowHandler.py: 处理window窗口事件,如on_closed、on_loaded
  2. static: 放置项目用到的js、css、imgs
  3. templates: 放html页面及组件
  4. main_mac.pymain_win.py: 项目入口,因为配置不一样区分系统
  5. build.shbuild.bat: Pyinstaller脚本,打包app/exe
1) 使用virtualenv精简打包依赖,给安装包瘦身
2)webapi方法举例,加载首页时执行的方法:
    def root(self):
    """
    渲染 index.html
    """
    logger.info('root', 'token:', webview.token)
    width=config.get_config('window.width') 
    zoom=config.get_config('window.zoom')

    return render_template('index.html', token=webview.token,width=width,zoom=zoom ,context={"name": "my_app"})
3) jsapi方法举例:
def select_out_folder(self):
    """
    选择文件夹
    """
    return self._window.create_file_dialog(webview.FOLDER_DIALOG)

3. pywebview打包

image.png

pyinstaller打包在mac上基本上比较顺利,但是在windows上出现了一些问题,记录如下:

1) 打包脚本

pyinstaller打包windows exe时,相比mac上的脚本需要引入WebBrowserInterop.x64.dll,脚本如下:

pyinstaller  src/main_win.py -F -w -y ^
        --paths "src" ^
        --name="my_app" ^
        --add-data="venv/lib/site-packages/webview/lib/WebBrowserInterop.x64.dll;webview/lib" ^
        --add-data="src/static;static" ^
        --add-data="src/templates;templates" ^
        --add-data="src/log;log" ^
        --icon="icon.ico" ^
        --clean
2) clrModule.PyInit_clr()异常
image.png

因为mac上基于python3.9开发,所以在windows上搭建了同样的环境;但是pythonnet不支持python3.9导致该问题;将python降级到3.8,问题解决。

3)ERROR:icu_util.cc(133)] Invalid file descriptor to ICU data received.

在windows平台将gui=cef修改成mshtml;考虑到兼容性和客户端的多样性,windows安装包使用mshtml是最保险的。

4) 在windows平台上使用js调用JsAPI方法时,语法报错

IE11不支持promise语法,引入blurbird.js,修改原api中promise的实现方式,具体如下:

// 原API的promise调用方式
js_api.select_excel_file().then(response => {

}).catch(err => {
    console.error(err)
})

// 基于blurbird.js实现方式
js_api.select_excel_file().then(response => {

},err => {
    console.error(err)
})
5) windows下窗口大小不包括标题栏、滚动条

打包时根据平台使用两份配置,windows窗口额外增加标题栏高度和滚动条宽度

6)在windows平台,当html使用了scale缩放后,窗口在debug模式和非debug模式大小不一致

该问题暂时通过配置特殊处理walk around

7)windows下点击关闭按钮,主进程卡死(not responding)

pywebview的一个bug,在mac平台,不执行window的on_closed事件,关闭窗口需要在on_closing事件中执行window.destroy();
但是在windows平台,在on_closing事件中执行window.destroy()会导致主进程卡死;windows平台只能在on_closed事件关闭窗口

你可能感兴趣的:(基于pywebview的桌面小工具开发记录)