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