news 2026/9/20 9:44:44

Kivy macOS 应用打包指南:Kivy SDK、Buildozer 与 PyInstaller 三种方案详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kivy macOS 应用打包指南:Kivy SDK、Buildozer 与 PyInstaller 三种方案详解
  • 跨平台
  • 移动开发
  • 桌面应用
  • UI组件

【免费下载链接】kivy

Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS

项目地址:https://gitcode.com/gh_mirrors/ki/kivy
点击查看免费下载

本篇技术指南基于 Kivy 官方文档 doc/sources/guide/packaging-osx.rst,系统讲解在 macOS 上打包 Kivy 应用的三种主流方案:官方推荐的 Kivy SDK、Buildozer 一键打包,以及 PyInstaller(配合或不配合 Homebrew)的深度定制方案。读完本文,你将掌握从安装依赖、编写 spec 文件到最终生成.app与 DMG 安装镜像的完整流程,并能结合仓库源码理解 Kivy 为 PyInstaller 提供的 hook 机制,按需裁剪打包体积。

打包方式总览

Kivy 官方为 macOS 提供了多条打包路径,它们各有适用场景:

方案适用场景特点
Kivy SDK(Kivy.app)常规应用、追求稳定所有依赖打包在虚拟环境中,不引用系统二进制,官方推荐
Buildozer快速出包、自动化一条命令完成打包,底层仍调用 Kivy SDK
PyInstaller + Homebrew需要精细控制依赖从源码编译,可在任意机器运行,需手动编辑 spec
PyInstaller(无 Homebrew)已自行安装依赖完全手写 spec,灵活度最高,工作量也最大

下文逐一展开。其中示例应用使用仓库自带的 Touch Tracer 演示程序,其源码位于 examples/demo/touchtracer/main.py,配套的 touchtracer.kv 与 particle.png 会在打包时一并收集,是贯穿全文的实战对象。

方案一:使用 Kivy SDK(推荐)

Kivy 官方发布一个名为Kivy.app的 DMG 安装包,其中内置了一个虚拟环境:既包含完整的 Python 解释器,也包含 SDL、GStreamer 等全部二进制依赖,可直接作为打包 Kivy 应用的基础。

这是最安全的打包方式,原因在于:

  • 打包出的应用只引用 DMG 内的 framework 或二进制,不包含任何对打包机器上系统二进制文件的引用
  • 与之相对,PyInstaller 会从本地 Python 安装中复制二进制,产物容易受打包机环境影响。

使用该方案时请注意两个版本前提:

  1. 该方式仅适用于 Kivy v2.0.0 及之后版本
  2. Kivy.app 以MACOSX_DEPLOYMENT_TARGET=10.9构建,即默认支持 macOS 10.9 及以上系统。值得注意的是,当前仓库的 tools/build_macos_dependencies.sh 中,依赖构建脚本已使用MACOSX_DEPLOYMENT_TARGET=10.15调用xcodebuild,同时 changelog.rst 也记录了 Xcode 14.3 在MACOSX_DEPLOYMENT_TARGET < 10.13时无法构建 SDL 的兼容性问题——若你自行构建依赖,建议按新脚本的部署目标执行。

具体操作分两条路线:一是直接基于已安装的 Kivy.app 打包,二是从零开始构建。两种方式的完整指令均记录在官方维护的kivy-sdk-packager 仓库osx目录)的 README 中,文档只给出指引,不重复贴出全部命令。

方案二:使用 Buildozer 一键打包

Buildozer 是 Kivy 官方提供的跨平台打包工具,其 macOS 支持流程如下:

pip install git+http://github.com/kivy/buildozer cd /to/where/I/Want/to/package buildozer init

buildozer init会在当前目录生成buildozer.spec配置文件。仓库中的 examples/audio/buildozer.spec 是一份完整的参考示例,其中与 macOS 打包直接相关的关键项包括:

[app] # (str) Title of your application title = Audio Example # (str) Package name package.name = audio # (str) Source code where the main.py live source.dir = . # (list) Source files to include (let empty to include all the files) source.include_exts = py,png,jpg,kv,atlas,wav # (list) Application requirements # comma separated e.g. requirements = sqlite3,kivy requirements = kivy

编辑 spec 文件时,请根据你的应用填写标题、包名、源码目录,并在requirements=一节追加额外依赖(例如requirements = kivy,pygame)。

关于requirements有两个值得注意的默认行为:

  • 默认情况下,requirements中指定的kivy 版本号会被忽略
  • 打包时,Buildozer 优先使用位于/Applications/Kivy.app的本地 Kivy.app;如果该目录不存在,则自动下载 kivy.org 上基于 Kivy master 分支的最新构建

配置完成后,执行打包命令:

buildozer osx debug

打包完成后,如果希望减小体积,可以手动移除应用运行所不需要的多余包,将产物精简到最小可用状态。

Buildozer 目前底层仍然调用 Kivy SDK 完成打包。如果你需要比 Buildozer 现有选项更精细的控制,可直接使用 SDK 方式(见方案一)。

方案三:PyInstaller + Homebrew 完整指南

当需要精细控制打包行为时,PyInstaller 是更灵活的选择。官方文档给出了一条经过验证的完整路线。

重要原则:请在你希望支持的最低 macOS 版本上进行打包,这样产物的兼容范围最广。

1. 安装 Homebrew 与 Python

首先安装 Homebrew(macOS 包管理器),然后安装 Python:

$ brew install python

若要使用 Python 3,请执行brew install python3,并将下文所有pip替换为pip3

2. 从源码重装依赖

为了让产物可以在其他机器上运行,需要确保依赖二进制不以链接形式引用本机 Homebrew 的库,因此要用--build-from-source重新安装 SDL 系依赖:

$ brew reinstall --build-from-source sdl3 sdl3_image sdl3_ttf sdl3_mixer

如果项目还依赖 GStreamer 或其他附加库,同样需要用--build-from-source重装,详见下文"附加库"一节。

3. 安装 Cython 与 Kivy

$ pip install Cython $ pip install -U kivy

Cython是 Kivy 的编译依赖(Kivy 大量使用 Cython 编写扩展模块),必须先于 Kivy 安装;-U确保升级到最新版本。

4. 安装 PyInstaller

$ pip install -U pyinstaller

5. 打包应用

使用pyinstaller直接指向应用的main.py

$ pyinstaller -y --clean --windowed --name touchtracer \ --exclude-module _tkinter \ --exclude-module Tkinter \ --exclude-module enchant \ --exclude-module twisted \ /usr/local/share/kivy-examples/demo/touchtracer/main.py

各参数含义如下:

参数作用
-y覆盖输出目录中已有文件
--clean打包前清理缓存
--windowed不弹出终端窗口,适合 GUI 应用
--name touchtracer指定应用名
--exclude-module ...显式排除 Kivy 用不到的模块,减小体积

被排除的_tkinter/Tkinter(Tk GUI)、enchant(拼写检查)、twisted(异步框架)都是 Kivy 应用常见的冗余依赖。当前仓库的 kivy/tools/packaging/pyinstaller_hooks/init.py 中同样定义了excludedimports = ['tkinter', '_tkinter', 'twisted'],与这里的命令行排除逻辑相互印证。

注意:以上命令还不会复制图片、声音等附加资源文件,这一步需要在生成的.spec文件中手动补充。

6. 编辑 spec 文件

执行上述命令后,当前目录会生成touchtracer.spec。需要修改其中的COLLECT()调用,把 Touch Tracer 的数据文件(touchtracer.kvparticle.png等)加入最终包。方法是在COLLECT中增加一个Tree()对象——它会递归搜索并打包指定目录下的所有文件:

coll = COLLECT(exe, Tree('/usr/local/share/kivy-examples/demo/touchtracer/'), a.binaries, a.zipfiles, a.datas, strip=None, upx=True, name='touchtracer')

Tree()的路径应替换为实际示例目录;对你自己的应用而言,就是存放.kv、图片、音频等资源的目录。Tree会递归包含全部文件,因此要确认该目录下没有不想发布的敏感文件

7. 构建 spec 并生成 DMG

$ pyinstaller -y --clean --windowed touchtracer.spec

构建完成后进入dist目录,用 macOS 自带的hdiutil.app封装成 DMG 镜像:

$ pushd dist $ hdiutil create ./Touchtracer.dmg -srcfolder touchtracer.app -ov $ popd
  • -srcfolder touchtracer.app:指定被封装的应用;
  • -ov:允许覆盖已存在的同名 DMG。

完成后,dist目录下就会出现Touchtracer.dmg,可直接分发安装。

附加库:GStreamer

如果项目依赖 GStreamer(如视频播放),需要以源码方式重装相关组件:

$ brew reinstall --build-from-source gstreamer gst-plugins-{base,good,bad,ugly}

若项目需要 Ogg Vorbis 支持,请在上述命令中追加--with-libvorbis选项。

此外,如果你使用的是 Homebrew 提供的 Python,在官方 Homebrew formula 合入相应改动之前,还需要手动安装带--with-pythongst-pythonformula。

GStreamer 与打包的关联在源码中也有体现:pyi_rth_kivy.py(见 kivy/tools/packaging/pyinstaller_hooks/pyi_rth_kivy.py)会在运行时把sys._MEIPASSgst-plugins子目录写入GST_PLUGIN_PATH,并把GST_REGISTRY重定向到包内,确保解包后的应用能找到 GStreamer 插件;而 hook-kivy.py 对应的__init__.py中,_find_gst_binaries()会通过gst-inspect-1.0探测插件路径,收集libgst*插件及其依赖库作为binaries传入Analysis

方案四:不使用 Homebrew 的 PyInstaller 手写 spec

如果你不希望依赖 Homebrew(例如已按 Kivy 官方"开发版"安装指南自行编译了 Kivy 及其依赖),可以完全手写 spec 文件。官方文档以testpackaging目录为例:

cd testpackaging git clone https://github.com/pyinstaller/pyinstaller

在该目录创建touchtracer.spec,写入以下内容:

# -*- mode: python -*- block_cipher = None from kivy.tools.packaging.pyinstaller_hooks import get_deps_all, hookspath, runtime_hooks a = Analysis(['/path/to/yout/folder/containing/examples/demo/touchtracer/main.py'], pathex=['/path/to/yout/folder/containing/testpackaging'], binaries=None, win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, hookspath=hookspath(), runtime_hooks=runtime_hooks(), **get_deps_all()) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, exclude_binaries=True, name='touchtracer', debug=False, strip=False, upx=True, console=False ) coll = COLLECT(exe, Tree('../kivy/examples/demo/touchtracer/'), Tree('/Library/Frameworks/SDL3_ttf.framework/Versions/A/Frameworks/FreeType.framework'), a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name='touchtracer') app = BUNDLE(coll, name='touchtracer.app', icon=None, bundle_identifier=None)

使用前必须把以下路径替换为你的实际路径:

  • Analysis中的主脚本路径/path/to/yout/folder/containing/examples/demo/touchtracer/main.py
  • pathex中的工程目录/path/to/yout/folder/containing/testpackaging
  • COLLECTTree('../kivy/examples/demo/touchtracer/')的资源目录;
  • Tree()中 FreeType framework 的路径(该路径随你的 SDL_ttf 安装位置而定)。

该 spec 的核心是利用 Kivy 官方提供的 PyInstaller 辅助模块(见 kivy/tools/packaging/pyinstaller_hooks/init.py):

  • hookspath():返回包含 Kivy 自定义 hook(hook-kivy.py)的目录,供Analysis使用;
  • runtime_hooks():返回 Kivy 运行时 hook(pyi_rth_kivy.py)路径,负责在启动时设置KIVY_DATA_DIRKIVY_MODULES_DIRGST_PLUGIN_PATH等环境变量;
  • get_deps_all():返回所有可能被间接导入的 Kivy 模块(含全部 core provider)、GStreamer 二进制与排除项,以字典形式展开为Analysishiddenimports/excludes/binaries参数。

随后执行:

pyinstaller/pyinstaller.py touchtracer.spec

touchtracer替换为你的应用名即可。完成后,dist/目录下会出现<yourapp>.app。注意BUNDLE()中的icon=None表示暂未设置图标,如需自定义应用图标可在此指定.icns文件。

源码级补充:理解 Kivy 的 PyInstaller hook 机制

方案四中使用的get_deps_all()只是冰山一角。Kivy 的 pyinstaller hooks 模块还提供了更精细的控制能力,理解它们有助于你进一步压缩打包体积、规避缺模块问题。

get_deps_minimal:按 core 模块裁剪 provider

get_deps_all()打包"所有 provider"不同,get_deps_minimal(exclude_ignored=True, **kwargs)允许你按核心模块粒度控制打包内容。其关键字参数对应 Kivy 的 core 模块:audiocameraclipboardimagespellingtextvideowindow,取值规则:

取值行为
True(默认)包含本系统当前加载的 provider
None完全排除该 core 模块(exclude_ignored=True时还会加入 excludes,防止被意外带入)
字符串或字符串列表只包含指定的 provider,如audio=['gstplayer', 'ffpyplayer']spelling='enchant'

官方示例:

a = Analysis(['..\\kivy\\examples\\demo\\touchtracer\\main.py'], ... hookspath=hookspath(), runtime_hooks=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, **get_deps_minimal(video=None, audio=None))

为什么需要 hiddenimports

PyInstaller 通过静态分析 import 语句收集依赖,但 Kivy 的大量核心模块(如视频 provider)是通过__import__等方式间接导入的,PyInstaller 无法感知,必须通过hiddenimports显式声明。get_deps_all()/get_deps_minimal()返回的字典正是为此服务的。

覆盖默认 hook

PyInstaller 自带一个 Kivy hook,它会列出所有 provider 作为 hidden imports,导致体积偏大。你可以通过hookspath()指向仓库内置的替代 hook(kivy/tools/packaging/pyinstaller_hooks/hook-kivy.py),它只保留get_factory_modules()(所有注册进 Kivy Factory 的模块)与基础kivy_modules,把 provider 的取舍完全交给get_deps_minimal()/get_deps_all()决定。也可以在命令行加--additional-hooks-dir=HOOKSPATH覆盖默认 hook 中的hiddenimportsexcludedimports全局变量。

生成自定义 hook 清单

如果想手动逐个勾选 provider,可以借助模块自带的生成器:

python -m kivy.tools.packaging.pyinstaller_hooks hook filename

该命令(实现见 kivy/tools/packaging/pyinstaller_hooks/main.py)会把get_deps_all()得到的全部模块以列表形式写入filename指定的 hook 文件(不传filename则直接打印到终端),你只需注释掉不需要的 provider 即可。

打包注意事项汇总

  1. 在最低支持的 macOS 版本上打包:PyInstaller 产物通常向下兼容有限,选择过新的构建系统可能使旧系统用户无法运行;
  2. 源码编译依赖:使用 Homebrew 方案时务必对 SDL、GStreamer 等执行--build-from-source重装,否则产物会携带对打包机 Homebrew 库的路径引用;
  3. 资源文件不会自动收集:图片、音频、.kv文件必须通过 spec 中的Tree()datas显式加入;
  4. GStreamer 需要额外配置:依赖视频播放时,除重装gstreamer及 plugins 外,运行时还需GST_PLUGIN_PATH等环境变量配合(Kivy 的 runtime hook 已自动处理);
  5. Kivy SDK 方案无需关心上述二进制细节:DMG 内虚拟环境已包含全部依赖,这也是官方推荐它的根本原因;
  6. 版本前提:Kivy SDK 打包方式仅适用于 Kivy v2.0.0 及以上,且 Kivy.app 基于MACOSX_DEPLOYMENT_TARGET=10.9构建。

至此,你可以根据项目对"稳定性"与"可控性"的需求,在 Kivy SDK、Buildozer 与 PyInstaller 之间做出选择,并依据本文的完整命令与 spec 模板,在 macOS 上产出可分发的.app与 DMG。

  • 跨平台
  • 移动开发
  • 桌面应用
  • UI组件

【免费下载链接】kivy

Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS

项目地址:https://gitcode.com/gh_mirrors/ki/kivy
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 9:44:15

大语言模型在网文与剧本创作中的评测与优化

1. 项目背景与核心价值去年接触了十几家内容创作团队后&#xff0c;我发现一个共性痛点&#xff1a;在网文和剧本创作领域&#xff0c;作者们普遍面临创作效率瓶颈。某知名网文平台数据显示&#xff0c;头部作者日均需要产出8000-10000字&#xff0c;而传统写作工具提供的帮助非…

作者头像 李华
网站建设 2026/9/20 9:41:51

MacBook卸载软件的正确姿势:从废纸篓到命令行彻底清理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 9:41:49

OpenResearch:打造可追踪、可复现的研究过程管理方法

1. 为什么我决定把研究过程做成一个“开放项目”1.1 一个让我尴尬了三天的真实问题事情发生在我整理上季度研究材料的时候。当时我准备把一份“结论”写进总结报告&#xff0c;为了严谨&#xff0c;我想回看一下当初是怎么验证的。结果是什么呢&#xff1f;笔记里只有一句“实验…

作者头像 李华
网站建设 2026/9/20 9:39:36

OpenRouter:Kimi K2.7 Code 用 TaoToken 取 Key 后跑补全延迟

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 9:38:41

从PyTorch到OM:Atlas 300V部署YOLO全流程解析

很多第一次接触昇腾生态的人&#xff0c;拿到一张Atlas 300V 24G板卡时都会愣一下——这东西长得像显卡&#xff0c;插在服务器里也像显卡&#xff0c;但它的定位、驱动方式、甚至调优思路&#xff0c;和CUDA那一套完全不是一回事。网上搜"atlas部署yolo"&#xff0c…

作者头像 李华
网站建设 2026/9/20 9:34:39

Jetson eFuse 量产烧录实战:Secure Boot 密钥配置与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华