:基于 PyInstaller 生成可執(zhí)行程序)
Kivy Windows 應用打包實戰(zhàn)基于 PyInstaller 生成可執(zhí)行程序【免費下載鏈接】kivyOpen source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS項目地址: https://gitcode.com/gh_mirrors/ki/kivy本文是 Kivy 官方打包指南中 Windows 平臺部分的深度實戰(zhàn)講解完整覆蓋從環(huán)境準備、基礎目錄型打包、單文件打包、數(shù)據(jù)文件捆綁到 GStreamer 視頻應用打包的完整流程并結合本倉庫源碼kivy/tools/packaging/pyinstaller_hooks/剖析 PyInstaller hook 的工作機制與瘦身方法。讀完本文你將能夠獨立把一個 Kivy 應用含自定義圖標、KV 文件、圖片資源甚至視頻依賴打包為可在 Windows 上雙擊運行的.exe程序。適用范圍與前置條件按官方文檔說明本文檔僅適用于Kivy 1.9.1 及以上版本且打包過程只能在 Windows 操作系統(tǒng)內(nèi)完成無法跨平臺交叉打包 Windows 程序。文檔中給出的流程已在 Windows 上使用 Kivywheels安裝方式驗證通過其他安裝方式如源碼編譯、conda 等的處理見文末「備選安裝方式」一節(jié)。打包產(chǎn)物是 32 位還是 64 位取決于你運行打包命令的Python 解釋器位數(shù)與 Kivy 本身無關。因此如需 64 位程序請使用 64 位 Python 執(zhí)行打包。環(huán)境準備依賴清單打包前需要準備兩個核心依賴最新版 Kivy按官方 Windows 安裝指南見 doc/sources/gettingstarted/installation.rst以 wheels 方式安裝。wheels 方式會一并安裝kivy_deps系列二進制依賴包sdl3、glew等這些包暴露的dep_bins屬性是后續(xù) spec 文件配置的關鍵。PyInstaller 3.1通過pip install --upgrade pyinstaller安裝。3.1 版本起 PyInstaller 官方自帶 Kivy 的 hook使得基礎打包開箱即用。PyInstaller 默認 hook 是什么PyInstaller 通過靜態(tài)分析只能找到直接import的模塊而 Kivy 大量核心功能video、audio、spelling、window 等是間接導入的——Kivy 在運行時才根據(jù)平臺和配置動態(tài)加載對應的 provider。默認 hook 的作用就是把這些間接依賴補充進打包清單讓 PyInstaller 不至于漏掉它們。默認 hook 會添加全部核心模塊audio、video、spelling 等及其依賴這保證了開箱即用的正確性但代價是產(chǎn)物偏大。如果你希望裁剪體積或默認 hook 未被安裝就需要使用 Kivy 提供的備選 hook見下文「覆蓋默認 hook」一節(jié)。無論采用哪種 hookGStreamer 等原生 DLL 都仍需通過 spec 中的Tree()手動打包見「打包視頻應用」。打包一個簡單應用以 touchtracer 為例官方指南以touchtracer示例項目為演示對象。該示例位于倉庫 examples/demo/touchtracer 目錄主入口為 main.py并依賴touchtracer.kv、particle.png、icon.png等資源文件。在 wheels 安裝方式下這些示例位于python\share\kivy-examples從 GitHub 源碼安裝時則位于kivy\examples。下文統(tǒng)一用examples-path指代示例根目錄。第一步生成初始 spec在命令行確保python可用后創(chuàng)建一個用于存放打包產(chǎn)物的文件夾例如TouchApp進入該目錄后執(zhí)行python -m PyInstaller --name touchtracer examples-path\demo\touchtracer\main.py這條命令會基于main.py生成touchtracer.spec規(guī)格文件。若希望給可執(zhí)行文件附加自定義圖標可先將icon.png轉(zhuǎn)換為.ico格式如使用 ConvertICO 等在線工具放入 touchtracer 目錄后再帶上--icon參數(shù)python -m PyInstaller --name touchtracer --icon examples-path\demo\touchtracer\icon.ico examples-path\demo\touchtracer\main.py其余 PyInstaller 選項請查閱 PyInstaller 官方手冊。第二步編輯 spec 加入 Kivy 依賴生成的touchtracer.spec位于TouchApp目錄。用編輯器打開在spec 文件開頭加入假設使用默認的 SDL3 后端from kivy_deps import sdl3, glew隨后找到COLLECT()調(diào)用為其添加 touchtracer 的數(shù)據(jù)文件touchtracer.kv、particle.png等。做法是新增一個Tree()對象指向示例目錄——Tree()會遞歸搜索并打包該目錄下的所有文件coll COLLECT(exe, Tree(examples-path\\demo\\touchtracer\\), a.binaries, a.zipfiles, a.datas, *[Tree(p) for p in (sdl3.dep_bins glew.dep_bins)], stripFalse, upxTrue, nametouchtracer)關鍵點在于*[Tree(p) for p in (sdl3.dep_bins glew.dep_bins)]它遍歷kivy_deps.sdl3與kivy_deps.glew兩個包的dep_bins路徑列表把 SDL3、GLEW 所需的全部 DLL 一并加入產(chǎn)物。這與倉庫自帶測試 spec 的寫法完全一致見 kivy/tests/pyinstaller/simple_widget/main.spec。第三步構建并定位產(chǎn)物在TouchApp目錄執(zhí)行python -m PyInstaller touchtracer.spec構建完成后編譯產(chǎn)物位于TouchApp\dist\touchtracer目錄其中包含可執(zhí)行的touchtracer.exe及配套資源文件。整個dist\touchtracer文件夾即可整體分發(fā)。單文件應用--onefile若希望分發(fā)時只有一個獨立可執(zhí)行文件可在上述流程基礎上改用--onefile模式python -m PyInstaller --onefile --name touchtracer examples-path\demo\touchtracer\main.py此時生成的 spec 中依賴與數(shù)據(jù)需要加到EXE()命令的參數(shù)里而不是COLLECT()exe EXE(pyz, Tree(examples-path\\demo\\touchtracer\\), a.scripts, a.binaries, a.zipfiles, a.datas, *[Tree(p) for p in (sdl3.dep_bins glew.dep_bins)], upxTrue, nametouchtracer)按相同方式構建python -m PyInstaller touchtracer.spec后產(chǎn)物位于TouchApp\dist目錄且只有一個可執(zhí)行文件。捆綁數(shù)據(jù)文件處理臨時解包目錄單文件模式下程序運行時會先把自身解壓到系統(tǒng)臨時目錄Kivy 的資源查找機制默認不知道這個臨時位置導致圖片、數(shù)據(jù)庫等外部數(shù)據(jù)文件無法被定位。官方給出了兩處修改1. 主程序加入資源路徑在main.py中補充導入若尚未存在import os, sys from kivy.resources import resource_add_path, resource_find并在入口處判斷sys._MEIPASSPyInstaller 注入的臨時解包路徑變量if __name__ __main__: if hasattr(sys, _MEIPASS): resource_add_path(os.path.join(sys._MEIPASS)) TouchtracerApp().run()resource_add_path與resource_find是 Kivy 資源管理機制的核心 API定義于 kivy/resources.py。Kivy 在查找圖片、KV 文件等資源時會按順序遍歷內(nèi)部的resource_paths列表默認包含當前目錄、腳本所在目錄、Kivy 安裝目錄等resource_add_path就是向這個列表追加搜索路徑從而讓 Kivy 能感知到 PyInstaller 的解包目錄。2. 按 PyInstaller 文檔包含數(shù)據(jù)文件數(shù)據(jù)文件的包含方式遵循 PyInstaller 官方文檔通過--add-data或 spec 中datas/Tree()配置隨后按前述流程重新打包即可。打包視頻應用加入 GStreamerKivy 的視頻播放默認依賴 GStreamer官方指南以 examples/widgets/videoplayer.py 為例演示。創(chuàng)建VideoPlayer文件夾并進入后執(zhí)行python -m PyInstaller --name gstvideo examples-path\widgets\videoplayer.py同樣編輯生成的gstvideo.spec這次在開頭同時引入 gstreamer 依賴from kivy_deps import sdl3, glew, gstreamer在COLLECT()中加入視頻資源目錄的Tree()并把 gstreamer 的dep_bins追加進依賴列表coll COLLECT(exe, Tree(examples-path\\widgets), a.binaries, a.zipfiles, a.datas, *[Tree(p) for p in (sdl3.dep_bins glew.dep_bins gstreamer.dep_bins)], stripFalse, upxTrue, namegstvideo)構建python -m PyInstaller gstvideo.spec后gstvideo.exe位于VideoPlayer\dist\gstvideo運行即可播放視頻。值得一提的是倉庫的 video_widget 測試 spec 展示了更健壯的依賴收集寫法對ffpyplayer、gstreamer這類可選依賴使用try/except ImportError包裹未安裝時自動跳過避免打包腳本在缺少可選依賴的環(huán)境下直接報錯。覆蓋默認 hook按需裁剪、縮小體積默認 hook 會把 Kivy所有核心 provider 打入包內(nèi)。若未安裝默認 hook或希望裁剪掉不需要的模塊例如完全不用音視頻以縮小體積可以使用 Kivy 自帶的備選 hook 機制相關實現(xiàn)全部位于 kivy/tools/packaging/pyinstaller_hookshookspath()返回備選 hook 所在目錄即本倉庫的pyinstaller_hooks目錄。該備選 hookhook-kivy.py不默認包含任何 provider僅加入 Factory 注冊模塊與基礎 kivy 模塊。runtime_hooks()返回運行時 hook 路徑pyi_rth_kivy.py。它負責在程序啟動時設置KIVY_DATA_DIR、KIVY_MODULES_DIR、GST_PLUGIN_PATH、GST_REGISTRY等環(huán)境變量指向sys._MEIPASS下的kivy_install目錄。只有當 PyInstaller 未自帶默認 hook 時才必須顯式提供覆蓋默認 hook 場景下通常無需修改它。get_deps_all()返回hiddenimports、excludes、binaries三個鍵的字典等價于默認 hook 的完整行為——收集kivy.core下所有可能的 provider可用于生成一份完整清單。get_deps_minimal(**kwargs)只收集運行時實際加載的 provider并支持按核心模塊精確裁剪詳見下文。在 spec 中啟用備選 hook先在 spec 開頭導入from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal, get_deps_all, hookspath, runtime_hooks再把Analysis修改為a Analysis([examples-path\\demo\\touchtracer\\main.py], ... hookspathhookspath(), runtime_hooksruntime_hooks(), ... **get_deps_all())上述寫法等價于默認 hook 的全部內(nèi)容若想排除音頻與視頻 provider、其余核心模塊按運行時實際加載收集則改為a Analysis([examples-path\\demo\\touchtracer\\main.py], ... hookspathhookspath(), runtime_hooksruntime_hooks(), ... **get_deps_minimal(videoNone, audioNone))get_deps_minimal接受的核心模塊關鍵字為audio, camera, clipboard, image, spelling, text, video, window各取值的含義見init.py 的文檔字符串取值行為True默認可省略包含當前系統(tǒng)加載該核心模塊時實際導入的 providerNone完全排除該核心模塊由于exclude_ignored默認開啟還會把它加入excludes防止被 PyInstaller 意外捎帶進去字符串或字符串列表只包含指定 provider如audio[gstplayer, ffpyplayer]、spellingenchantget_deps_minimal返回的字典同樣含hiddenimports、excludes、binaries三鍵可直接以**展開傳給Analysis。其中binaries僅在包含gstplayer時會收集 GStreamer 插件與依賴庫其余情況若exclude_ignored開啟還會把kivy.lib.gstplayer加入排除列表進一步防止冗余打包。生成可手編輯的完整 hook 清單pyinstaller_hooks還附帶一個 hook 生成器可產(chǎn)出一份逐行列出全部 provider 模塊的 hook 文件隨后手動注釋掉不需要的模塊即可實現(xiàn)最細粒度的裁剪python -m kivy.tools.packaging.pyinstaller_hooks hook filenamefilename為要生成的 hook 文件路徑省略時則把內(nèi)容打印到終端。生成邏輯見 kivy/tools/packaging/pyinstaller_hooks/main.py它基于get_deps_all()[hiddenimports]輸出并拼接在備選 hook-kivy.py 的hiddenimports列表之后。將該文件放到--additional-hooks-dir指定目錄即可覆蓋默認 hook 的hiddenimports/excludedimports全局變量。備選安裝方式非 wheels上述示例中的*[Tree(p) for p in (sdl3.dep_bins glew.dep_bins gstreamer.dep_bins)]依賴kivy_deps系列 wheels 包。若 Kivy 不是通過 wheels 安裝的這些包不存在from kivy_deps import sdl3會直接導入失敗。此時需要手動定位 SDL3、GLEW、GStreamer 等原生 DLL 的實際安裝位置將這些目錄以同樣的方式傳給Tree()例如Tree(C:\\path\\to\\sdl3\\bin)其余 spec 配置流程不變。驗證與調(diào)試建議倉庫在 kivy/tests/pyinstaller 下維護了simple_widget與video_widget兩套可運行的 PyInstaller 打包測試用例其 spec 是上文所有配置的最佳實踐參照可直接作為模板使用。打包完成后若程序啟動即崩潰優(yōu)先檢查Tree()是否覆蓋了 KV 文件與圖片等數(shù)據(jù)資源、dep_bins的 DLL 是否齊全、是否啟用了備選 hook 卻漏掉了運行時實際使用的 provider。單文件模式運行時報找不到資源請確認主程序中已按「捆綁數(shù)據(jù)文件」一節(jié)調(diào)用resource_add_path(sys._MEIPASS)。視頻應用報 GStreamer 相關錯誤時可檢查pyi_rth_kivy.py注入的GST_PLUGIN_PATH與GST_REGISTRY是否指向正確解包路徑必要時用環(huán)境變量顯式指定GST_PLUGIN_PATH指向插件目錄。通過以上流程從最簡單的目錄型分發(fā)、單文件 exe到帶數(shù)據(jù)資源與 GStreamer 視頻依賴的完整應用你都能基于 PyInstaller 與 Kivy 自帶的 hook 體系在 Windows 上穩(wěn)定產(chǎn)出可分發(fā)程序并按需裁剪核心模塊以控制體積?!久赓M下載鏈接】kivyOpen source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS項目地址: https://gitcode.com/gh_mirrors/ki/kivy創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考