十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kivy Windows 应用打包实战:基于 PyInstaller 生成可执行程序

Kivy Windows 应用打包实战:基于 PyInstaller 生成可执行程序 Kivy Windows 应用打包实战基于 PyInstaller 生成可执行程序【免费下载链接】kivyOpen source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS项目地址: https://gitcode.com/gh_mirrors/ki/kivy本文是 Kivy 官方打包指南中 Windows 平台部分的深度实战讲解完整覆盖从环境准备、基础目录型打包、单文件打包、数据文件捆绑到 GStreamer 视频应用打包的完整流程并结合本仓库源码kivy/tools/packaging/pyinstaller_hooks/剖析 PyInstaller hook 的工作机制与瘦身方法。读完本文你将能够独立把一个 Kivy 应用含自定义图标、KV 文件、图片资源甚至视频依赖打包为可在 Windows 上双击运行的.exe程序。适用范围与前置条件按官方文档说明本文档仅适用于Kivy 1.9.1 及以上版本且打包过程只能在 Windows 操作系统内完成无法跨平台交叉打包 Windows 程序。文档中给出的流程已在 Windows 上使用 Kivywheels安装方式验证通过其他安装方式如源码编译、conda 等的处理见文末「备选安装方式」一节。打包产物是 32 位还是 64 位取决于你运行打包命令的Python 解释器位数与 Kivy 本身无关。因此如需 64 位程序请使用 64 位 Python 执行打包。环境准备依赖清单打包前需要准备两个核心依赖最新版 Kivy按官方 Windows 安装指南见 doc/sources/gettingstarted/installation.rst以 wheels 方式安装。wheels 方式会一并安装kivy_deps系列二进制依赖包sdl3、glew等这些包暴露的dep_bins属性是后续 spec 文件配置的关键。PyInstaller 3.1通过pip install --upgrade pyinstaller安装。3.1 版本起 PyInstaller 官方自带 Kivy 的 hook使得基础打包开箱即用。PyInstaller 默认 hook 是什么PyInstaller 通过静态分析只能找到直接import的模块而 Kivy 大量核心功能video、audio、spelling、window 等是间接导入的——Kivy 在运行时才根据平台和配置动态加载对应的 provider。默认 hook 的作用就是把这些间接依赖补充进打包清单让 PyInstaller 不至于漏掉它们。默认 hook 会添加全部核心模块audio、video、spelling 等及其依赖这保证了开箱即用的正确性但代价是产物偏大。如果你希望裁剪体积或默认 hook 未被安装就需要使用 Kivy 提供的备选 hook见下文「覆盖默认 hook」一节。无论采用哪种 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。下文统一用examples-path指代示例根目录。第一步生成初始 spec在命令行确保python可用后创建一个用于存放打包产物的文件夹例如TouchApp进入该目录后执行python -m PyInstaller --name touchtracer examples-path\demo\touchtracer\main.py这条命令会基于main.py生成touchtracer.spec规格文件。若希望给可执行文件附加自定义图标可先将icon.png转换为.ico格式如使用 ConvertICO 等在线工具放入 touchtracer 目录后再带上--icon参数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()调用为其添加 touchtracer 的数据文件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 一并加入产物。这与仓库自带测试 spec 的写法完全一致见 kivy/tests/pyinstaller/simple_widget/main.spec。第三步构建并定位产物在TouchApp目录执行python -m PyInstaller touchtracer.spec构建完成后编译产物位于TouchApp\dist\touchtracer目录其中包含可执行的touchtracer.exe及配套资源文件。整个dist\touchtracer文件夹即可整体分发。单文件应用--onefile若希望分发时只有一个独立可执行文件可在上述流程基础上改用--onefile模式python -m PyInstaller --onefile --name touchtracer examples-path\demo\touchtracer\main.py此时生成的 spec 中依赖与数据需要加到EXE()命令的参数里而不是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后产物位于TouchApp\dist目录且只有一个可执行文件。捆绑数据文件处理临时解包目录单文件模式下程序运行时会先把自身解压到系统临时目录Kivy 的资源查找机制默认不知道这个临时位置导致图片、数据库等外部数据文件无法被定位。官方给出了两处修改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 文件等资源时会按顺序遍历内部的resource_paths列表默认包含当前目录、脚本所在目录、Kivy 安装目录等resource_add_path就是向这个列表追加搜索路径从而让 Kivy 能感知到 PyInstaller 的解包目录。2. 按 PyInstaller 文档包含数据文件数据文件的包含方式遵循 PyInstaller 官方文档通过--add-data或 spec 中datas/Tree()配置随后按前述流程重新打包即可。打包视频应用加入 GStreamerKivy 的视频播放默认依赖 GStreamer官方指南以 examples/widgets/videoplayer.py 为例演示。创建VideoPlayer文件夹并进入后执行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包裹未安装时自动跳过避免打包脚本在缺少可选依赖的环境下直接报错。覆盖默认 hook按需裁剪、缩小体积默认 hook 会把 Kivy所有核心 provider 打入包内。若未安装默认 hook或希望裁剪掉不需要的模块例如完全不用音视频以缩小体积可以使用 Kivy 自带的备选 hook 机制相关实现全部位于 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等环境变量指向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 的全部内容若想排除音频与视频 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默认可省略包含当前系统加载该核心模块时实际导入的 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 生成器可产出一份逐行列出全部 provider 模块的 hook 文件随后手动注释掉不需要的模块即可实现最细粒度的裁剪python -m kivy.tools.packaging.pyinstaller_hooks hook filenamefilename为要生成的 hook 文件路径省略时则把内容打印到终端。生成逻辑见 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 配置流程不变。验证与调试建议仓库在 kivy/tests/pyinstaller 下维护了simple_widget与video_widget两套可运行的 PyInstaller 打包测试用例其 spec 是上文所有配置的最佳实践参照可直接作为模板使用。打包完成后若程序启动即崩溃优先检查Tree()是否覆盖了 KV 文件与图片等数据资源、dep_bins的 DLL 是否齐全、是否启用了备选 hook 却漏掉了运行时实际使用的 provider。单文件模式运行时报找不到资源请确认主程序中已按「捆绑数据文件」一节调用resource_add_path(sys._MEIPASS)。视频应用报 GStreamer 相关错误时可检查pyi_rth_kivy.py注入的GST_PLUGIN_PATH与GST_REGISTRY是否指向正确解包路径必要时用环境变量显式指定GST_PLUGIN_PATH指向插件目录。通过以上流程从最简单的目录型分发、单文件 exe到带数据资源与 GStreamer 视频依赖的完整应用你都能基于 PyInstaller 与 Kivy 自带的 hook 体系在 Windows 上稳定产出可分发程序并按需裁剪核心模块以控制体积。【免费下载链接】kivyOpen source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS项目地址: https://gitcode.com/gh_mirrors/ki/kivy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表