Publishing Flet app to multiple platforms
Introduction
Flet CLI provides flet build
command that allows packaging Flet app into a standalone executable or install package for distribution.
Platform matrix
The following matrix shows which OS you should run flet build
command on in order to build a package for specific platform:
Run on / flet build | apk/aab | ipa | macos | linux | windows | web |
---|---|---|---|---|---|---|
macOS | ✅ | ✅ | ✅ | ✅ | ||
Windows | ✅ | ✅ (WSL) | ✅ | ✅ | ||
Linux | ✅ | ✅ | ✅ |
Prerequisites
Flutter SDK
Flutter SDK 3.24 or above must be installed and the path to both flutter
and dart
commands must be added to PATH
environment variable.
Follow official Flutter installation guide for your platform.
Pay attention to Flutter's own requirements for every platform, such as XCode and Cocopods on macOS, Visual Studio 2022 on Windows or additional tools and libraries on Linux.
Project structure
flet build
command assumes the following minimal Flet project structure.
/assets/
icon.png
main.py
pyproject.toml
requirements.txt
main.py
is the entry point of your Flet application with ft.app(main)
at the end. A different entry point could be specified with --module-name
argument.
assets
is an optional directory that contains application assets (images, sound, text and other files required by your app) as well as images used for package icons and splash screens.
If only icon.png
(or other supported format such as .bmp
, .jpg
, .webp
) is provided it will be used as a source image to generate all icons and splash screens for all platforms. See section below for more information about icons and splashes.
pyproject.toml
contains the application metadata, lists its dependencies and controls build process.
requirements.txt
can also be used to list app requirements. It is optional though and if both pyproject.toml
and requirements.txt
exist the latter will be ignored.
The list of project dependencies should contain at least flet
package.
Do not use pip freeze > requirements.txt
command to create requirements.txt
for the app that
will be running on mobile. As you run pip freeze
command on a desktop requirements.txt
will have
dependencies that are not intended to work on a mobile device, such as watchdog
.
Hand-pick requirements.txt
to have only direct dependencies required by your app, plus flet
.
The easiest way to start with the right project structure is to use flet create
command:
flet create myapp
where myapp
is a target directory.
flet create
app template puts main.py
and assets
into src
directory which path is controlled by tool.flet.app.path
setting in pyproject.toml
:
[tool.flet.app]
path = "src"
How it works
flet build <target_platform>
command could be run from the root of Flet app directory:
<flet_app_directory> % flet build <target_platform>
where <target_platform>
could be one of the following: apk
, aab
, ipa
, web
, macos
, windows
, linux
.
When running from a different directory you can provide the path to a directory with Flet app:
flet build <target_platform> <path_to_python_app>
Build results are copied to <python_app_directory>/build/<target_platform>
. You can specify a custom output directory with --output
option:
flet build <target_platform> --output <path-to-output-dir>
flet build
uses Flutter SDK and the number of Flutter packages to build a distribution package from your Flet app.
When you run flet build <target_platform>
command it:
- Creates a new Flutter project in
{flet_app_directory}/build/flutter
directory from https://github.com/flet-dev/flet-build-template template. Flutter app will contain a packaged Python app in the assets and useflet
andserious_python
packages to run Python app and render its UI respectively. The project is ephemeral and deleted upon completion. - Copies custom icons and splash images (see below) from
assets
directory into a Flutter project. - Generates icons for all platforms using
flutter_launcher_icons
package. - Generates splash screens for web, iOS and Android targets using
flutter_native_splash
package. - Packages Python app using
package
command ofserious_python
package.package
command installs pure and binary Python packages from https://pypi.org and https://pypi.flet.dev for selected platform. If configured,.py
files of installed packages and/or application will be compiled to.pyc
files. All files, exceptbuild
directory will be added to a package asset. - Runs
flutter build <target_platform>
command to produce an executable or an install package. - Copies build results to
{flet_app_directory}/build/<target_platform>
directory.
Including optional controls
If your app uses the following controls their packages must be added to a build command:
- Ad controls (
BannerAd
andInterstitialAd
) implemented inflet_ads
package. Audio
control implemented inflet_audio
package.AudioRecorder
control implemented inflet_audio_recorder
package.Flashlight
control implemented inflet_flashlight
package.Geolocator
control implemented inflet_geolocator
package.Lottie
control implemented inflet_lottie
package.Map
control implemented inflet_map
package.PermissionHandler
control implemented inflet_permission_handler
package.Rive
control implemented inflet_rive
package.Video
control implemented inflet_video
package.WebView
control implemented inflet_webview
package.
Use --include-packages <package_1> <package_2> ...
option to add Flutter packages with optional
Flet controls or use tool.flet.flutter.dependencies
section in pyproject.toml
.
For example, to build your Flet app with Video
and Audio
controls add --include-packages flet_video flet_audio
to your flet build
command:
flet build apk --include-packages flet_video flet_audio
or the same in pyproject.toml
:
flutter.dependencies = ["flet_video", "flet_audio"]
or an alternative syntax with versions:
[tool.flet.flutter.dependencies]
flet_video = "1.0.0"
flet_audio = "2.0.0"
or with path to the package on your disk:
[tool.flet.flutter.dependencies.my_package]
path = "/path/to/my_package"
Icons
You can customize app icons for all platforms (excluding Linux) with images in assets
directory of your Flet app.
If only icon.png
(or other supported format such as .bmp
, .jpg
, .webp
) is provided it will be used as a source image to generate all icons.
- iOS -
icon_ios.png
(or any supported image format). Recommended minimum image size is 1024 px. Image should not be transparent (have alpha channel). Defaults toicon.png
with alpha-channel automatically removed. - Android -
icon_android.png
(or any supported image format). Recommended minimum image size is 192 px. Defaults toicon.png
. - Web -
icon_web.png
(or any supported image format). Recommended minimum image size is 512 px. Defaults toicon.png
. - Windows -
icon_windows.png
(or any supported image format). ICO will be produced of 256 px size. Defaults toicon.png
. Ificon_windows.ico
file is provided it will be just copied towindows/runner/resources/app_icon.ico
unmodified. - macOS -
icon_macos.png
(or any supported image format). Recommended minimum image size is 1024 px. Defaults toicon.png
.
Splash screen
You can customize splash screens for iOS, Android and web applications with images in assets
directory of your Flet app.
If only splash.png
or icon.png
(or other supported format such as .bmp
, .jpg
, .webp
) is provided it will be used as a source image to generate all splash screen.
- iOS (light) -
splash_ios.png
(or any supported image format). Defaults tosplash.png
and thenicon.png
. - iOS (dark) -
splash_dark_ios.png
(or any supported image format). Defaults to light iOS splash, then tosplash_dark.png
, then tosplash.png
and thenicon.png
. - Android (light) -
splash_android.png
(or any supported image format). Defaults tosplash.png
and thenicon.png
. - Android (dark) -
splash_dark_android.png
(or any supported image format). Defaults to light Android splash, then tosplash_dark.png
, then tosplash.png
and thenicon.png
. - Web (light) -
splash_web.png
(or any supported image format). Defaults tosplash.png
and thenicon.png
. - Web (dark) -
splash_dark_web.png
(or any supported image format). Defaults to light web splash, thensplash_dark.png
, then tosplash.png
and thenicon.png
.
--splash-color
option specifies background color for a splash screen in light mode. Defaults to #ffffff
.
--splash-dark-color
option specifies background color for a splash screen in dark mode. Defaults to #333333
.
Configuring splash settings in 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
Entry point
By default, flet build
command assumes main.py
as the entry point of your Flet application, i.e. the file with ft.app(main)
at the end. A different entry point could be specified with --module-name
argument or in pyproject.toml
:
[tool.flet]
app.module = "main"
Compilation and cleanup
flet build
command is not compiling app .py
files into .pyc
by default which allows you to avoid (or defer?) discovery of any syntax errors in your app and successfully complete the packaging.
You can enable the compilation and cleanup with the following new options:
--compile-app
- compile app's.py
files.--compile-packages
- compile installed packages'.py
files.--cleanup-on-compile
- remove unnecessary files upon successful compilation.
Configuring compilation in pyproject.toml
:
[tool.flet]
compile.app = true # --compile-app
compile.packages = true # --compile-packages
compile.cleanup = true # --cleanup-on-compile
Permissions
flet build
command allows granular control over permissions, features and entitlements embedded into AndroidManifest.xml
, Info.plist
and .entitlements
files.
See platform guides for setting specific iOS, Android and macOS permissions.
Cross-platform permissions
There are pre-defined permissions that mapped to Info.plist
, *.entitlements
and AndroidManifest.xml
for respective platforms.
Setting cross-platform permissions:
flet build --permissions permission_1 permission_2 ...
Supported permissions:
location
camera
microphone
photo_library
iOS mapping to Info.plist
entries
location
NSLocationWhenInUseUsageDescription = This app uses location service when in use.
NSLocationAlwaysAndWhenInUseUsageDescription = This app uses location service.
camera
NSCameraUsageDescription = This app uses the camera to capture photos and videos.
microphone
NSMicrophoneUsageDescription = This app uses microphone to record sounds.
photo_library
NSPhotoLibraryUsageDescription = This app saves photos and videos to the photo library.
macOS mapping to entitlements
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 mappings
location
- permissions:
android.permission.ACCESS_FINE_LOCATION": True
android.permission.ACCESS_COARSE_LOCATION": True
android.permission.ACCESS_BACKGROUND_LOCATION": True
- features:
android.hardware.location.network": False
android.hardware.location.gps": False
- permissions:
camera
- permissions:
android.permission.CAMERA": True
- features:
android.hardware.camera": False
android.hardware.camera.any": False
android.hardware.camera.front": False
android.hardware.camera.external": False
android.hardware.camera.autofocus": False
- permissions:
microphone
- permissions:
android.permission.RECORD_AUDIO": True
android.permission.WRITE_EXTERNAL_STORAGE": True
android.permission.READ_EXTERNAL_STORAGE": True
- permissions:
photo_library
- permissions:
android.permission.READ_MEDIA_VISUAL_USER_SELECTED": True
- permissions:
Configuring cross-platform permissions in pyproject.toml
:
[tool.flet]
permissions = ["camera", "microphone"]
Versioning
You can provide a version information for built executable or package with --build-number
and --build-version
arguments. This is the information that is used to distinguish one build/release from another in App Store and Google Play and is shown to the user in about dialogs.
--build-number
- an integer number (defaults to 1
), an identifier used as an internal version number.
Each build must have a unique identifier to differentiate it from previous builds.
It is used to determine whether one build is more recent than another, with higher numbers indicating
more recent build.
--build-version
- a "x.y.z" string (defaults to 1.0.0
) used as the version number shown to users. For each new
version of your app, you will provide a version number to differentiate it from previous versions.
Configuring display version and version number in pyproject.toml
:
[project]
name = "my_app"
version = "1.0.0"
description = "My Flet app"
authors = [
{name = "John Smith", email = "[email protected]"}
]
dependencies = ["flet==0.25.0"]
[tool.flet]
build_number = 1
Customizing packaging template
To create a temporary Flutter project flet build
uses cookiecutter template stored in https://github.com/flet-dev/flet-build-template repository.
You can customize that template to suit your specific needs and then use it with flet build
.
--template
option can be used to provide the URL to the repository or path to a directory with your own template. Use gh:
prefix for GitHub repos, e.g. gh:{my-org}/{my-repo}
or provide a full path to a Git repository, e.g. https://github.com/{my-org}/{my-repo}.git
.
For Git repositories you can checkout specific branch/tag/commit with --template-ref
option.
--template-dir
option specifies a relative path to a cookiecutter template in a repository given by --template
option. When --template
option is not used, this option specifies path relative to the <user-directory>/.cookiecutters/flet-build-template
.
Configuring template in pyproject.toml
:
[tool.flet.template]
path = "gh:some-github/repo" # --template
dir = "" # --template-dir
ref = "" # --template-ref
Extra args to flutter build
command
--flutter-build-args
option allows passing extra arguments to flutter build
command called during the build process. The option can be used multiple times.
For example, if you want to add --no-tree-shake-icons
option:
flet build macos --flutter-build-args=--no-tree-shake-icons
To pass an option with a value:
flet build ipa --flutter-build-args=--export-method --flutter-build-args=development
Configuring Flutter build extra args:
[tool.flet]
flutter.build_args = [
"--some-flutter-arg-1",
"--some-flutter-arg-2"
]
Verbose logging
--verbose
or -vv
option allows to see the output of all commands during flet build
run.
We might ask for a detailed log if you need support.
Console output
All Flet apps output to stdout
and stderr
(e.g. all print()
statements or sys.stdout.write()
calls, Python logging
library) is now redirected to console.log
file with a full path to it stored in FLET_APP_CONSOLE
environment variable.
Writes to that file are unbuffered, so you can retrieve a log in your Python program at any moment with a simple:
with open(os.getenv("FLET_APP_CONSOLE"), "r") as f:
log = f.read()
AlertDialog
or any other control can be used to display the value of log
variable.
When the program is terminated by calling sys.exit()
with exit code 100
(magic code)
the entire log will be displayed in a scrollable window.
import sys
sys.exit(100)
Calling sys.exit()
with any other exit code will terminate (close) the app without displaying a log.