主题
用 flet pack 把 Flet 应用打包成独立的桌面可执行文件——这是一个轻量的、基于 PyInstaller 的方案,可作为 flet build 的替代。用户运行打包后的应用,无需安装 Python 解释器或任何模块。
它与 flet build 的关系
这两个命令都受支持——它们分别处在「速度 vs 控制」曲线的不同位置:
flet pack | flet build | |
|---|---|---|
| 目标平台 | 仅桌面端:Windows、macOS、Linux | 桌面端、移动端(Android/iOS),以及 web |
| 工具链 | PyInstaller | Flutter SDK(自动安装) |
| 应用运行方式 | 你的 Python 代码与预构建的 Flet 桌面客户端一起运行 | Flutter 编译的应用,内嵌 Python,进程内运行 |
| Python 依赖 | 由 PyInstaller 对你的导入做静态分析来发现 | 按你声明的 应用依赖 完整安装 |
| 构建时间 | 快——没有原生编译 | 较慢——一次完整的 Flutter 构建 |
| 可定制程度 | 图标以及可执行文件/打包的元数据 | 一切:图标、启动画面、构建模板、签名与商店打包 |
想要快速产出桌面产物时,用 flet pack;面向移动端或 web,或者需要更深度的定制时,用 flet build。
与 PyInstaller 本身一样,flet pack 不是交叉编译器:针对每个目标操作系统分别运行——CI 能让这件事变得毫不费力。
前置条件
PyInstaller 负责打包,必须先安装:
bash
pip install pyinstaller打包
在包含你程序的目录下运行:
bash
flet pack your_program.py打包后的应用落在 dist 文件夹中 (--distpath 可改变它):在 Windows 和 Linux 上是单文件可执行文件, 在 macOS 上是一个 .app 打包。传入 --onedir 可改为生成单文件夹打包,而非单个文件(macOS 始终生成 .app 打包)。试着运行一下:
bash
open dist/your_program.appbash
dist\your_program.exebash
dist/your_program默认情况下,可执行文件或打包以 Python 脚本的名字命名;用 --name 修改:
bash
flet pack your_program.py --name bundle_name如果上次运行残留了非空的 build 或 dist 文件夹,flet pack 会在删除前询问——传入 --yes 可跳过所有提示 (在 CI 中很有用)。
要分发,就把 dist 文件夹的内容压缩成 zip 交给用户——他们运行它不需要安装 Python 或 Flet。
自定义图标
用 --icon 设置图标:
bash
flet pack your_program.py --icon your-icon.ico请提供目标平台原生格式的图标:Windows 用 .ico,macOS 用 .icns。它会同时应用到外层可执行文件和内嵌的 Flet 查看器,这样应用窗口、Dock/任务栏条目以及可执行文件本身都保持一致。
::: infoLinux 的处理方式不同 Linux 没法把图标放进可执行文件内部——桌面环境从已安装的桌面条目中读取它。传入一个 .png,flet pack 会替你把 条目和图标都写好供你安装;参见 Linux 任务栏身份。 :::
Linux 任务栏身份
flet pack 启动的是那个共享的、预构建的 Flet 客户端,所以如果没有额外帮助,每个打包后的应用都会以该二进制文件的名字出现在任务栏上——被归到一组,并标注为 flet。为避免这种情况,应用会以自身的身份重新启动 (参见 FLET_APP_ID):当你传入时采用 --bundle-id,否则采用可执行文件的名字。
--bundle-id 也能让你主动选择这个身份,而不是从可执行文件的名字继承——如果可执行文件名叫某个不该作为桌面条目键名的东西,这么做是值得的——比如带版本号的 my-app-1.2.3。
这就让应用拥有了属于自己的任务栏分组和标签。它的显示名称和图标来自别处:一个桌面条目,桌面环境通过 StartupWMClass 把它与窗口匹配起来。flet pack 会在可执行文件旁边写一个条目——如果你给 --icon 传了 .png,还会一并写入图标:
dist/
my-app the executable
com.example.my_app.desktop
com.example.my_app.png only when --icon is a .pngName= 来自 --product-name (回退到可执行文件的名字),Comment= 来自 --file-description。不会替你安装任何东西,因为安装会作为构建的副作用改动你的应用菜单。你自己把这两个文件复制到合适位置并刷新缓存:
bash
cp dist/com.example.my_app.desktop ~/.local/share/applications/
update-desktop-database ~/.local/share/applications
# 仅当你给 --icon 传了 .png 时才需要
mkdir -p ~/.local/share/icons/hicolor/256x256/apps
cp dist/com.example.my_app.png ~/.local/share/icons/hicolor/256x256/apps/
gtk-update-icon-cache -f -t ~/.local/share/icons/hicolor移动可执行文件会破坏 Exec=
条目指向 flet pack 构建二进制文件的位置,因为那是写入它时唯一已知的位置。如果你把可执行文件安装到了别处——/opt、~/.local/bin——请编辑 Exec= 使之匹配:
bash
sed -i 's|^Exec=.*|Exec="/opt/my-app/my-app"|' ~/.local/share/applications/com.example.my_app.desktop或者交给 flet build 打包
flet build linux 会为每个应用编译一个独立的运行器,所以身份是内置的,而不是在启动时套用。如果你想让打包工作被自动处理,而不是自己拼装,就用它。
包含静态资源
如果你的应用使用了静态资源,用 --add-data 包含它们,格式为 source:destination:
bash
flet pack your_program.py --add-data "assets:assets"这个选项可以重复传入,以包含多个文件或文件夹。
可执行文件与打包元数据
操作系统展示的关于你应用的一些细节可以定制。
在 macOS 上——打包的「关于」对话框以及 Dock/活动监视器条目:
--product-name— 打包的显示名称。--product-version— 「关于」对话框中显示的版本。--copyright— 「关于」对话框中显示的版权声明。--bundle-id— 唯一的打包标识符。

在 Windows 上——可执行文件的「详细信息」属性对话框:
--product-name— 「产品名称」字段。--product-version— 「产品版本」字段。--file-version— 「文件版本」字段,格式为n.n.n.n。--file-description— 「文件说明」字段,也是该程序在任务管理器中的 显示名称。--company-name— 「公司名称」字段。--copyright— 「版权」字段。
和图标一样,元数据会同时嵌入外层可执行文件和其中内嵌的 Flet 查看器。
更多选项
--hidden-import— 添加被动态导入、因而被 PyInstaller 静态分析遗漏的模块。--add-binary— 打包额外的二进制文件。--debug-console1— 保留一个显示 Python 输出的控制台窗口, 用于排查打包后应用的问题。--uac-admin— 启动时请求提升的权限(Windows)。--codesign-identity— 签名应用打包(macOS)。--pyinstaller-build-args— 把任何其他参数直接透传给 底层的pyinstaller命令,每次只传一个。若参数值以-开头,请用=连接, 例如--pyinstaller-build-args=--clean。--— 把其后的所有内容直接透传给pyinstaller,例如flet pack main.py -- --clean --log-level=WARN。
完整选项列表见 flet pack 参考。
在 CI 中打包
由于每个操作系统必须各自打包自己的产物,用 CI 矩阵可以一次性产出全部三个:
yaml
name: Pack Flet App
on:
push:
workflow_dispatch:
jobs:
pack:
name: Pack on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: "3.14"
- name: Install dependencies
run: pip install flet pyinstaller [^1]
- name: Pack app
run: flet pack your_program.py --yes [^2]
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: your_program-${{ matrix.os }}
path: dist- 也在这里安装你应用自身的依赖——例如
pip install -r requirements.txt。 --yes跳过关于删除先前build和dist文件夹的交互提示。
故障排查
| 症状 | 原因与修复 |
|---|---|
仅在打包后的应用内出现 ModuleNotFoundError | 该模块是动态导入的,所以 PyInstaller 的静态分析漏掉了它——用 --hidden-import <module> 重新打包。 |
| 打包后的应用退出或行为异常,且没有可见错误 | 用 --debug-console 1 重新打包,以打开一个显示 Python 输出和回溯信息的控制台窗口。 |
macOS:在其他 Mac 上出现 "App" is damaged and can't be opened | 下载的应用必须经过签名与公证,Gatekeeper 才会运行。用 --codesign-identity 签名打包,然后公证并装订——Notarization 一节解释了相关概念与命令,适用于任何已签名的应用。flet build macos 会自动完成整条链路。 |