跳到主要内容

将 Flet 应用发布到多个平台

简介

Flet CLI 提供了 flet build 命令,该命令允许将 Flet 应用打包为独立的可执行文件或安装包以便分发。

平台矩阵

以下矩阵显示了您应该在哪个操作系统上运行 flet build 命令,以便为特定平台构建包:

运行于 / flet buildapk/aabipamacoslinuxwindowsweb
macOS
Windows✅ (WSL)
Linux

先决条件

Flutter SDK

如果在PATH中未找到正确版本的 Flutter SDK,那么在首次运行时为任何平台构建 Flet 应用程序时,它将被自动安装。

Flutter SDK 安装在 $HOME/flutter/{version} 目录中。

项目结构

flet build 命令假定 Flet 项目具有以下最小结构。

├── README.md
├── pyproject.toml
└── src
├── assets
│ └── icon.png
└── main.py

main.py 是您的 Flet 应用的入口点,末尾带有 ft.app(main)。可以使用 --module-name 参数指定不同的入口点。

assets 是一个可选目录,其中包含应用资产(您的应用所需的图像、声音、文本和其他文件)以及用于包图标和启动屏幕的图像。

如果仅提供 icon.png(或其他支持的格式,如 .bmp.jpg.webp),它将被用作源图像来为所有平台生成所有图标和启动屏幕。有关图标和启动屏幕的更多信息,请参见下面的部分。

pyproject.toml 包含应用程序的元数据,列出其依赖项并控制构建过程。

requirements.txt 也可用于列出应用程序的需求。不过这是可选的,如果同时存在 pyproject.tomlrequirements.txt,则后者将被忽略。

项目依赖项列表中至少应包含 flet 包。

pyproject.toml
[project]
name = "myapp"
version = "0.1.0"
description = ""
readme = "README.md"
requires-python = ">=3.9"
authors = [
{ name = "Flet developer", email = "you@example.com" }
]
dependencies = [
"flet"
]

[tool.flet]
org = "com.mycompany"
product = "MyApp"
company = "My Company"
copyright = "Copyright (C) 2025 by My Company"

[tool.flet.app]
path = "src"
警告

虽然requirements.txt也可用于列出应用程序需求,但对于新项目,Flet 推荐使用pyproject.toml。如果pyproject.tomlrequirements.txt同时存在,后者将被忽略。

不要使用 pip freeze

不要使用 pip freeze > requirements.txt 命令为将在移动设备上运行的应用创建 requirements.txt。因为当您在桌面运行 pip freeze 命令时,requirements.txt 中将包含不打算在移动设备上运行的依赖项,例如 watchdog

手动选择 requirements.txt,使其仅包含您的应用所需的直接依赖项以及 flet

以正确的项目结构开始的最简单方法是使用 flet create 命令:

flet create myapp

其中 myapp 是目标目录。

工作原理

flet build <目标平台> 命令可以从 Flet 应用目录的根目录运行:

<flet_app_directory> % flet build <目标平台>

其中 <目标平台> 可以是以下之一:apkaabipawebmacoswindowslinux

当从不同的目录运行时,您可以提供 Flet 应用所在目录的路径:

flet build <目标平台> <python_app 目录路径>

构建结果将被复制到 <python_app_directory>/build/<目标平台>。您可以使用 --output 选项指定自定义输出目录:

flet build <目标平台> --output <输出目录路径>

flet build 使用 Flutter SDK 和多个 Flutter 包从您的 Flet 应用构建分发包。

当您运行 flet build <目标平台> 命令时,它会:

  • https://github.com/flet-dev/flet-build-template 模板在 {flet_app_directory}/build/flutter 目录中创建一个新的 Flutter 项目。Flutter 应用将在资产中包含一个打包的 Python 应用,并使用 fletserious_python 包分别运行 Python 应用并渲染其 UI。该项目是临时的,完成后将被删除。
  • 将自定义图标和启动图像(见下文)从 assets 目录复制到 Flutter 项目中。
  • 使用 flutter_launcher_icons 包为所有平台生成图标。
  • 使用 flutter_native_splash 包为 Web、iOS 和 Android 目标生成启动屏幕。
  • 使用 serious_python 包的 package 命令打包 Python 应用。package 命令从 https://pypi.orghttps://pypi.flet.dev 为所选平台安装纯 Python 包和二进制 Python 包。如果进行了配置,已安装包和/或应用程序的 .py 文件将被编译为 .pyc 文件。除 build 目录外的所有文件都将添加到包资产中。
  • 运行 flutter build <目标平台> 命令以生成可执行文件或安装包。
  • 将构建结果复制到 {flet_app_directory}/build/<目标平台> 目录。

包含可选控件

如果您的应用使用以下控件,则必须将其包添加到构建命令中:

  • flet_ads 包中实现的广告控件(BannerAdInterstitialAd)。
  • Audio 控件,在 flet_audio 包中实现。
  • AudioRecorder 控件,在 flet_audio_recorder 包中实现。
  • Flashlight 控件,在 flet_flashlight 包中实现。
  • Geolocator 控件,在 flet_geolocator 包中实现。
  • Lottie 控件,在 flet_lottie 包中实现。
  • Map 控件,在 flet_map 包中实现。
  • PermissionHandler 控件,在 flet_permission_handler 包中实现。
  • Rive 控件,在 flet_rive 包中实现。
  • Video 控件,在 flet_video 包中实现。
  • WebView 控件,在 flet_webview 包中实现。

使用 --include-packages <包_1> <包_2>... 选项添加带有可选 Flet 控件的 Flutter 包,或在 pyproject.toml 中使用 tool.flet.flutter.dependencies 部分。

例如,要使用 VideoAudio 控件构建您的 Flet 应用,请在 flet build 命令中添加 --include-packages flet_video flet_audio

flet build apk --include-packages flet_video flet_audio

或者在 pyproject.toml 中进行相同的设置:

flutter.dependencies = ["flet_video", "flet_audio"]

或者使用带有版本的替代语法:

[tool.flet.flutter.dependencies]
flet_video = "1.0.0"
flet_audio = "2.0.0"

或者使用您磁盘上包的路径:

[tool.flet.flutter.dependencies.my_package]
path = "/path/to/my_package"

图标

您可以使用 Flet 应用的 assets 目录中的图像为所有平台(除 Linux 外)自定义应用图标。

如果仅提供 icon.png(或其他支持的格式,如 .bmp.jpg.webp),它将被用作生成所有图标的源图像。

  • iOS - icon_ios.png(或任何支持的图像格式)。建议的最小图像大小为 1024 像素。图像不应是透明的(具有 alpha 通道)。默认为自动去除 alpha 通道的 icon.png
  • Android - icon_android.png(或任何支持的图像格式)。建议的最小图像大小为 192 像素。默认为 icon.png
  • Web - icon_web.png(或任何支持的图像格式)。建议的最小图像大小为 512 像素。默认为 icon.png
  • Windows - icon_windows.png(或任何支持的图像格式)。将生成 256 像素大小的 ICO。默认为 icon.png。如果提供了 icon_windows.ico 文件,它将直接复制到 windows/runner/resources/app_icon.ico 而不进行修改。
  • macOS - icon_macos.png(或任何支持的图像格式)。建议的最小图像大小为 1024 像素。默认为 icon.png

启动屏幕

您可以使用 Flet 应用的 assets 目录中的图像为 iOS、Android 和 Web 应用自定义启动屏幕。

如果仅提供 splash.pngicon.png(或其他支持的格式,如 .bmp.jpg.webp),它将被用作生成所有启动屏幕的源图像。

  • iOS(亮色) - splash_ios.png(或任何支持的图像格式)。默认为 splash.png,然后是 icon.png
  • iOS(暗色) - splash_dark_ios.png(或任何支持的图像格式)。默认为亮色 iOS 启动屏幕,然后是 splash_dark.png,然后是 splash.png,然后是 icon.png
  • Android(亮色) - splash_android.png(或任何支持的图像格式)。默认为 splash.png,然后是 icon.png
  • Android(暗色) - splash_dark_android.png(或任何支持的图像格式)。默认为亮色 Android 启动屏幕,然后是 splash_dark.png,然后是 splash.png,然后是 icon.png
  • Web(亮色) - splash_web.png(或任何支持的图像格式)。默认为 splash.png,然后是 icon.png
  • Web(暗色) - splash_dark_web.png(或任何支持的图像格式)。默认为亮色 Web 启动屏幕,然后是 splash_dark.png,然后是 splash.png,然后是 icon.png

--splash-color 选项指定亮色模式下启动屏幕的背景颜色。默认为 #ffffff

--splash-dark-color 选项指定暗色模式下启动屏幕的背景颜色。默认为 #333333

pyproject.toml 中配置启动屏幕设置:

[tool.flet.splash]
color = "#FFFF00" # --splash-color
dark_color = "#8B8000" # --splash-dark-color
web = false # --no-web-splash
ios = false # --no-ios-splash
android = false # --no-android-splash

启动画面

启动画面在包含 Python 应用程序的存档文件被解压到设备文件系统时显示。它在闪屏画面之后、启动画面之前显示。应用程序存档不包括第三方网站包。如果存档较小且解压速度较快,您可以保持该画面禁用状态(默认情况)。

要在pyproject.toml中为所有目标平台启用启动画面:

[tool.flet.app.boot_screen]
show = true
message = "正在为首次启动准备应用程序…"

启动画面可以仅为特定平台启用,或者自定义其消息。例如,仅为 Android 启用:

[tool.flet.android.app.boot_screen]
show = true

启动画面

启动画面在包含第三方网站包的存档文件(仅适用于 Android)被解压且 Python 应用程序正在启动时显示。启动画面在启动画面之后显示。

要在pyproject.toml中为所有目标平台启用启动画面:

[tool.flet.app.startup_screen]
show = true
message = "正在启动应用程序…"

启动画面可以仅为特定平台启用,或者自定义其消息。例如,仅为 Android 启用:

[tool.flet.android.app.startup_screen]
show = true

入口点

默认情况下,flet build 命令假定 main.py 是您的 Flet 应用的入口点,即末尾带有 ft.app(main) 的文件。可以使用 --module-name 参数或在 pyproject.toml 中指定不同的入口点:

[tool.flet]
app.module = "main"

编译和清理

默认情况下,flet build 命令不会将应用程序的 .py 文件编译为 .pyc 文件,这使您可以避免(或推迟?)在应用程序中发现任何语法错误,并成功完成打包。

您可以使用以下新选项启用编译和清理:

  • --compile-app - 编译应用程序的 .py 文件。
  • --compile-packages - 编译已安装包的 .py 文件。
  • --cleanup-on-compile - 在编译成功后删除不必要的文件。

pyproject.toml 中配置编译:

[tool.flet]
compile.app = true # --compile-app
compile.packages = true # --compile-packages
compile.cleanup = true # --cleanup-on-compile

权限

flet build 命令允许对嵌入到 AndroidManifest.xmlInfo.plist.entitlements 文件中的权限、功能和授权进行精细控制。

有关设置特定 iOSAndroidmacOS 权限的信息,请参阅平台指南。

跨平台权限

有预定义的权限,它们分别映射到各个平台的 Info.plist*.entitlementsAndroidManifest.xml

设置跨平台权限:

flet build --permissions permission_1 permission_2...

支持的权限:

  • location
  • camera
  • microphone
  • photo_library

iOS 到 Info.plist 条目的映射

  • location
    • NSLocationWhenInUseUsageDescription = 此应用在使用时使用位置服务。
    • NSLocationAlwaysAndWhenInUseUsageDescription = 此应用使用位置服务。
  • camera
    • NSCameraUsageDescription = 此应用使用相机拍摄照片和视频。
  • microphone
    • NSMicrophoneUsageDescription = 此应用使用麦克风录制声音。
  • photo_library
    • NSPhotoLibraryUsageDescription = 此应用将照片和视频保存到照片库。

macOS 到授权的映射

  • location
    • com.apple.security.personal-information.location = True
  • camera
    • com.apple.security.device.camera = True
  • microphone
    • com.apple.security.device.audio-input = True
  • photo_library
    • com.apple.security.personal-information.photos-library = True

Android 映射

  • location
    • 权限:
      • android.permission.ACCESS_FINE_LOCATION": True
      • android.permission.ACCESS_COARSE_LOCATION": True
      • android.permission.ACCESS_BACKGROUND_LOCATION": True
    • 功能:
      • android.hardware.location.network": False
      • android.hardware.location.gps": False
  • camera
    • 权限:
      • android.permission.CAMERA": True
    • 功能:
      • android.hardware.camera": False
      • android.hardware.camera.any": False
      • android.hardware.camera.front": False
      • android.hardware.camera.external": False
      • android.hardware.camera.autofocus": False
  • microphone
    • 权限:
      • android.permission.RECORD_AUDIO": True
      • android.permission.WRITE_EXTERNAL_STORAGE": True
      • android.permission.READ_EXTERNAL_STORAGE": True
  • photo_library
    • 权限:
      • android.permission.READ_MEDIA_VISUAL_USER_SELECTED": True

pyproject.toml 中配置跨平台权限:

[tool.flet]
permissions = ["camera", "microphone"]

版本控制

你可以使用--build-number--build-version参数为构建的可执行文件或软件包提供版本信息。这些信息用于在 App Store 和 Google Play 中区分不同的构建/发布版本,并在关于对话框中向用户显示。

--build-number - 一个整数(默认为1),用作内部版本号的标识符。每个构建必须有一个唯一的标识符,以便与以前的构建区分开来。它用于确定一个构建是否比另一个构建更新,数字越大表示构建越新。

--build-version - 一个“x.y.z”字符串(默认为1.0.0),用作向用户显示的版本号。对于你的应用的每个新版本,你将提供一个版本号以与以前的版本区分开来。

pyproject.toml中配置显示版本和版本号:

[project]
name = "my_app"
version = "1.0.0"
description = "My Flet app"
authors = [
{name = "John Smith", email = "john@email.com"}
]
dependencies = ["flet==0.25.0"]

[tool.flet]
build_number = 1

自定义打包模板

为了创建一个临时的 Flutter 项目,flet build使用存储在 https://github.com/flet-dev/flet-build-template 仓库中的 cookiecutter 模板。

你可以根据自己的特定需求自定义该模板,然后在flet build中使用它。

--template选项可用于提供仓库的 URL 或包含你自己模板的目录路径。对于 GitHub 仓库,使用gh:前缀,例如gh:{我的组织}/{我的仓库},或者提供 Git 仓库的完整路径,例如https://github.com/{我的组织}/{我的仓库}.git

对于 Git 仓库,你可以使用--template-ref选项检出特定的分支/标签/提交。

--template-dir选项指定由--template选项给出的仓库中 cookiecutter 模板的相对路径。当不使用--template选项时,此选项指定相对于<用户目录>/.cookiecutters/flet-build-template的路径。

pyproject.toml中配置模板:

[tool.flet.template]
path = "gh:some-github/repo" # --template
dir = "" # --template-dir
ref = "" # --template-ref

flutter build命令的额外参数

--flutter-build-args选项允许在构建过程中向flutter build命令传递额外的参数。该选项可以多次使用。

例如,如果你想添加--no-tree-shake-icons选项:

flet build macos --flutter-build-args=--no-tree-shake-icons

要传递带有值的选项:

flet build ipa --flutter-build-args=--export-method --flutter-build-args=development

pyproject.toml中配置 Flutter 构建额外参数:

[tool.flet]
flutter.build_args = [
"--some-flutter-arg-1",
"--some-flutter-arg-2"
]

详细日志记录

--verbose-vv选项允许在flet build运行期间查看所有命令的输出。如果你需要支持,我们可能会要求提供详细的日志。

控制台输出

所有 Flet 应用程序输出到stdoutstderr(例如所有print()语句或sys.stdout.write()调用,Python 的logging库)现在都被重定向到console.log文件,其完整路径存储在FLET_APP_CONSOLE环境变量中。

对该文件的写入是无缓冲的,因此你可以在任何时候使用以下简单的代码在你的 Python 程序中检索日志:

with open(os.getenv("FLET_APP_CONSOLE"), "r") as f:
log = f.read()

AlertDialog或任何其他控件可用于显示log变量的值。

当程序通过使用退出代码100(魔法代码)调用sys.exit()终止时,整个日志将显示在一个可滚动的窗口中。

import sys
sys.exit(100)

使用任何其他退出代码调用sys.exit()将终止(关闭)应用程序而不显示日志。