基于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事件關閉窗口

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容