NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #2251 most downloaded on pub.dev
Write entire Flutter app in Python or add server-driven UI experience into existing Flutter app.
Last release 8 days ago
30 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 58 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
4 years old
96 releases · first in 2022
One column per quarter.
Add FletApp.wait_idle(idle_ms, timeout_ms) : a host app can wait until an embedded app has rendered its UI and gone quiet - for example before taking
FletApp.wait_idle(idle_ms, timeout_ms): a host app can wait until an embedded app has rendered its UI and gone quiet - for example before taking a screenshot of it or reading its output after a restart. It returns idle, error (the app failed to start or crashed) or timeout, and costs nothing unless a call is pending (#6901) by @FeodorFitsner.TextField.on_paste_files: pasted files (a screenshot, an image copied from a web page, files copied in the OS file manager) arrive as name, mime_type and bytes, e.g. to attach them to a chat message. On the web it uses the browser's paste event, so it works in every browser, Safari included, with no clipboard permission prompt; on desktop, Ctrl/Cmd+V reports a clipboard image (#6901) by @FeodorFitsner.Dropdown.expanded_insets having no effect when expand is set (#6895, #6896) by @xsalaices.Tabs ignoring a new selected_index set together with a new length - e.g. inserting a tab before the selected one and moving selected_index to follow it selected the inserted tab instead (#6901) by @FeodorFitsner.TextField its focus and cursor, a list its scroll position) when a sibling before them in a Column, Row or other multi-child control became visible or hidden: children were matched by position, so the shift rebuilt them. Children are now matched by control id (#6901) by @FeodorFitsner.FilePicker.upload() with several files uploading the wrong file to each URL: after the first upload, each file's id pointed at the next picked file, so a file's bytes went to another file's URL and the last file never uploaded (its caller waited forever). Picked files now keep their id across upload() calls, and files that can't be found report an upload error (#6901) by @FeodorFitsner.FletApp.on_error not firing when the embedded app crashes in main() or in an event handler - the error only showed inside the embedded app. The host is now notified, as on_error documents (#6901) by @FeodorFitsner.Full Changelog: v1.0.2...v1.0.3
FletBackend.waitIdle() for embedded backends: completes with idle once the app has rendered and gone quiet, error if it crashes or fails to start, or timeout. FletApp gains onBackendCreated to reach the embedded backend, and the FletApp control answers a wait_idle method call. A crash in an embedded backend is now also reported to the host's errorsHandler (#6901) by @FeodorFitsner.paste_files event to TextField: while a field with a handler is focused, files pasted into it are read from the browser's paste event on the web (listenPastedFiles()), or from the clipboard image on Ctrl/Cmd+V on desktop, and sent as name, mime_type and bytes (#6901) by @FeodorFitsner.ControlWidget built by Control.buildWidgets() with a new ControlIdKey(control.id), so Flutter matches children by identity instead of position: a sibling inserted before a control, or one whose visibility changes, no longer rebuilds it and resets its state (#6901) by @FeodorFitsner.TabsControl recreating its TabController at the old index when length and selected_index change in the same update (#6901) by @FeodorFitsner.FilePickerService uploading picked files to the wrong URLs: picked files are kept by their selection id across upload calls, and each file is claimed before any upload starts (takeUploadTargets()). A file that can't be found reports an upload error (#6901) by @FeodorFitsner.Update serious_python to 5.0.0 . flet build now passes each exclude path and cleanup glob to it as a separate option, so paths containing commas are e
5.0.0. flet build now passes each exclude path and cleanup glob to it as a separate option, so paths containing commas are excluded correctly and brace globs such as **/{tests,docs} in a cleanup.app_files or cleanup.package_files list work (serious-python#253, #6890) by @FeodorFitsner.identifier to Semantics so native accessibility tools and widget tests can match a stable ID (Android resource-id, iOS accessibilityIdentifier, web flt-semantics-identifier) instead of visible labels, plus Tester.find_by_semantics_identifier() (#6832) by @mccre110.flet run and ft.run() now print a warning with the desktop client's path when they use one from a previous flet build in build/<platform>, so an outdated client that lacks an extension is easy to spot (#6821) by @ndonkoHenri.flet build and flet debug pass the arguments that follow a -- separator to Flutter, e.g. flet build apk -- --obfuscate --split-debug-info=build/symbols, as an alternative to repeating --flutter-build-args (#6879) by @ndonkoHenri.flet pack passes the arguments that follow a -- separator to PyInstaller, e.g. flet pack main.py -- --clean, as an alternative to repeating --pyinstaller-build-args (#6879) by @ndonkoHenri.flet test passes the arguments that follow a -- separator to pytest, e.g. flet test -k screenshot -- -x --maxfail=1 (#6879) by @ndonkoHenri.Fix the Android SDK auto-installation failing on Windows (#6522, #6892) by @ndonkoHenri.
Fix InteractiveViewer failing to render when alignment is set (#6744, #6887) by @ndonkoHenri.
flet-charts: Fix ScatterChart failing to render when a ScatterChartSpot has x_error or y_error set. Error ranges are now set with the new ChartErrorRange type and drawn as error bars in the color of their spot (#6885) by @ndonkoHenri.
Fix iOS apps that use sqlite3 stopping with Assertion failed: (0), function isBulkReadStatement when run from Xcode on iOS 18 and later, by turning off Xcode's Thread Performance Checker in the scheme generated by flet build (#5480, #6882) by @ndonkoHenri.
Fix Button(icon=...) and other material buttons rendering an error box when content is not set. Icon-only buttons now render the icon centered (#6886, #6889) by @FeodorFitsner.
Fix flet debug, flet build, flet test, flet emulators and flet run rejecting a positional argument typed after an option on Python 3.10, 3.11, 3.12.0-3.12.6 and 3.13.0 - flet debug ios --device-id X my_app failed with unrecognized arguments: my_app - by backporting the upstream argparse fix (CPython gh-59317). Also, an app path pointing to a file such as main.py is now rejected with a clear error instead of crashing on main.py/build, and a bad app path fails before the Flutter toolchain is set up (#6840, #6875) by @ndonkoHenri.
Fix --android-extract-packages keeping only the values of its last occurrence when repeated. Like the other list options of flet build, repeating it now adds to the list (#6875) by @ndonkoHenri.
Fix --flutter-build-args handing a value that starts with - to Flet instead of Flutter - --flutter-build-args --verbose turned on Flet's own verbose output - and overriding build_args from pyproject.toml with an empty list. Such an occurrence now fails with a hint to attach the value using =, e.g. --flutter-build-args=--obfuscate (#6879) by @ndonkoHenri.
Fix --pyinstaller-build-args handing a value that starts with - to Flet instead of PyInstaller - --pyinstaller-build-args -y turned on Flet's own -y - or rejecting it as unrecognized. Such an occurrence now fails with a hint to attach the value using = or to pass it after -- (#6879) by @ndonkoHenri.
Fix flet build packaging virtual environments, .git, .flet and other development files into the app. Hidden entries in the app root (a leading ., or the hidden attribute on Windows), virtual environments detected by pyvenv.cfg, and __pycache__ directories are now excluded by default, and the build prints what was excluded (#6839, #6890) by @FeodorFitsner.
Compatibility: .env and other dot-prefixed files in the app root are no longer packaged. Keep them with --include .env or include = [".env"] under [tool.flet.app], or turn default exclusions off with --no-default-excludes / default_excludes = false. Apps built with earlier versions may already contain .venv or .flet.
Fix an empty list or table under [tool.flet.<PLATFORM>] falling back to the global [tool.flet] value. app.exclude, source_packages, dev_packages, target_arch, extract_packages, cleanup.app_files, cleanup.package_files and flutter.build_args now treat [] or {} in a platform section as "none for this platform" (#6890) by @FeodorFitsner.
AuthorizationService and GitHubOAuthProvider using HTTPX client methods and built-in JSON parsing (#6870) by @osamalzabidi.Full Changelog: v1.0.1...v1.0.2
Semantics.identifier through to Flutter's Semantics widget and add Tester.findBySemanticsIdentifier() so tests can match nodes by native accessibility identifier (#6832) by @mccre110.Button, FilledButton, FilledTonalButton, OutlinedButton and TextButton rendering an error box when icon is set without content. ButtonControl now uses the .icon(...) constructors only when both icon and content are provided; otherwise it builds the plain button with whichever one is set as its child, so icon-only buttons render the icon centered (#6886, #6889) by @FeodorFitsner.Update python-build to 20260921 and serious_python to 4.7.1 , bringing Pyodide 0.27.8 , 0.29.5 , and 314.0.7 for Python 3.12, 3.13, and 3.14, respecti
20260921 and serious_python to 4.7.1, bringing Pyodide 0.27.8, 0.29.5, and 314.0.7 for Python 3.12, 3.13, and 3.14, respectively. CPython versions and wheel platform tags are unchanged (python-build#42, serious-python#249) by @FeodorFitsner.Fix macOS crashes during native scientific imports and NumPy operations by increasing the embedded Python worker stack to at least 8 MiB, via serious_python 4.7.1 and dart_bridge 1.10.0 (serious-python#85, dart-bridge#21) by @AeneasTews.
Fix service properties and event handlers set in init() after super().init() being omitted from registration. Services now register after init() returns, so handlers are available for events raised during client initialization. Failed registrations also no longer leave invalid entries that break later registrations (#6736, #6858) by @ndonkoHenri.
Compatibility: init() overrides now register even without calling super().init(). Use ft.context.page inside init(); self.page and self.update() are only available after attachment. Fields set in init() now participate in serialization, so keep Python-only state in undeclared attributes or fields with metadata={"skip": True}.
Fix ListTile layout and click events inside a Row with unbounded width (#6854, #6861) by @FeodorFitsner.
Fix child components losing click events when passed as control arguments to a component that re-renders (#6857, #6859) by @FeodorFitsner.
Fix RawImage.render() stalling until the acknowledgement timeout in packaged Windows apps by waking the Python event loop when frame acknowledgements arrive (#6847, #6860) by @FeodorFitsner.
Full Changelog: v1.0.0...v1.0.1
No changes in the flet Dart package; version bumped for release coordination with the Python-side fix for child components losing click events after wrapper re-renders (#6857, #6859).
…3.12.14 additionally bundles libexpat 2.8.3 for CVE-2026-72522 , which 3.13.15 and 3.14.7 shipped a week too early to carry. serious_python 4.6.0 trac…
action property that performs gesture-gated work without a round trip to Python. Browsers only let a page open a file picker, write to the clipboard, show a share sheet or open a new tab while they are still handling the user's click or key press. Sending that click to your Python code and acting on the reply takes longer than the permission lasts, so on iOS Safari those operations were silently ignored while Android and desktop browsers let them through - which made a browser rule look like a Flet bug. Button, Container, IconButton, ListTile, CupertinoButton, CupertinoListTile, FloatingActionButton, OutlinedButton, TextButton and TextSpan now accept action - a single ClientAction or a list of them - which the client performs inside the original gesture, before your on_click handler is even notified: ft.Button("Open", action=ft.OpenUrl("https://flet.dev", target=ft.UrlTarget.BLANK)). Because an action runs before your code sees the click, its arguments have to be known in advance; to act on a value computed at click time, set it on the control ahead of the click. url is unchanged and keeps working exactly as before by @FeodorFitsner.flet build linux. Linux was the one platform flet build shipped without an icon — flutter_launcher_icons has no Linux generator, so assets/icon.png was silently ignored and built apps ran with a generic icon. The resolved icon (icon_linux.png, falling back to icon.png or the default Flet icon) is now bundled as data/app_icon.png and set as the window icon on startup, which taskbars and window switchers pick up on X11 and XWayland. Because Wayland has no window-icon protocol — desktops resolve icons from an installed desktop entry matching the app id — the bundle also ships a ready-to-install freedesktop tree: share/applications/<bundle_id>.desktop (name from --product, comment from --description, StartupWMClass set) plus the icon at share/icons/hicolor/<size>/apps/<bundle_id>.png. The entry's application categories default to Utility and are configurable with --linux-categories or [tool.flet.linux].categories, and the runner now sets its program name to the bundle ID (matching upstream Flutter's runner template) so the running app maps to that entry on both Wayland and X11. See the new App icon docs (#2269) by @ndonkoHenri.flet build macos. Select a distribution lane with --macos-distribution (or [tool.flet.macos.signing].distribution): developer-id signs every bundled binary with your Developer ID certificate — hardened runtime, entitlements, secure timestamp — then notarizes and staples the app for direct distribution, while app-store produces a sandboxed app with your provisioning profile embedded, packaged into an installer-signed .pkg ready for App Store Connect and TestFlight. Signing identities are auto-discovered from the keychain when not explicitly configured (via CLI options, pyproject.toml — including per-lane [tool.flet.macos.signing.<lane>] subtables — or environment variables), and the whole configuration is validated before the build starts, so a typo'd identity, expired certificate, or missing store prerequisite fails in seconds instead of after the full build. See the new Code signing, Notarization, and Mac App Store docs (#2347, #4543, #6702) by @ndonkoHenri.flet-local-auth extension with a LocalAuthentication service for on-device biometric and credential authentication on Android, iOS, macOS, and Windows via the local_auth Flutter plugin. Linux and Web are not supported (#3192, #6823).EXC_BAD_ACCESS - reported by the OS as an application crash even though the app had finished its work. Your Python code runs on its own thread alongside Flutter, and a normal process exit runs __cxa_finalize (DLL_PROCESS_DETACH on Windows), destroying the C++ statics inside every loaded C extension module while that thread is still executing inside one of them; the reported case died in matplotlib's ft2font looking up a pybind11 type-caster map that had just been destructed, but numpy, Pillow and Flutter's own Skia statics are torn down by the same pass. Both exit paths were affected: closing the window on desktop, and sys.exit() on every native platform - the latter is the worse of the two, because Flet's sys.exit posts the exit code to the Dart side and returns, so the interpreter is still fully alive (running on into Py_Finalize()) when Dart tears the process down. The desktop runners now _exit (TerminateProcess on Windows, since _exit/ExitProcess still run DLL_PROCESS_DETACH and would not help), and the sys.exit path routes through a new serious_python_hard_exit in dart_bridge 1.9.0, reached via serious_python 4.7.0 with the bundled python-build snapshot re-pinned to 20260908 (no CPython or Pyodide versions change). Exit codes are preserved. The trade-off is now a documented contract: Python atexit handlers, __del__ finalizers and unflushed buffered writes are not guaranteed to run on exit - persist what matters before exiting rather than relying on shutdown cleanup. SharedPreferences writes are unaffected and were verified to survive both paths. See How a built app terminates by @FeodorFitsner.flet run -v now turns on the framework's own logging, and -vv raises it to debug. The flag was accepted and documented as "enable verbose output", but nothing mapped it to a log level, so every logger.info in Flet's web transport — web root, assets directory, session and upload activity — was unreachable and the command printed nothing at all. flet run passes the level to the app through the new FLET_LOG_LEVEL variable; an app that configures logging itself keeps the setup it chose. The web root now also names FLET_WEB_PATH when that is where it came from, matching what the desktop client already reports for FLET_VIEW_PATH. flet run itself now configures logging too, not just the app it starts, so the desktop client resolution — which of build/<platform>, FLET_VIEW_PATH or the cached client won — is visible as well (#6835) by @ndonkoHenri.FLET_WEB_PATH now works with a flet build web output, so an app with third-party extensions can be served by flet run --web and ft.run(export_asgi_app=True). Those commands serve the prebuilt web client shipped in the flet-web package, whose extension list is fixed when Flet is released — so a third-party control renders as Unknown control: <Type> there, however the app was built. Pointing FLET_WEB_PATH at a built client should have solved that, but a built page bakes flet.pyodide = true into its config and carried no injection point, so it kept trying to start Python in the browser and never connected. The build template now carries the injection marker, and the runtime config states the mode explicitly instead of relying on the page's own default — mirroring flet run on desktop, which already prefers a client from a previous flet build (#6835) by @ndonkoHenri.DataChannels is no longer structured-cloned on its way to the Python worker. The Dart side has always built a postMessage transfer list from the packet's own buffer, but the JavaScript jsSend it calls accepted only two parameters, so the third was dropped and every frame was copied. jsSend now takes the transfer list and hands it to postMessage, making the hand-off zero-copy as intended; each packet is freshly allocated per send and never read back, so detaching the buffer is safe (#6829) by @ndonkoHenri.flet build web no longer compiles and ships a dart2wasm build that the page can never load. Flutter emits that output for the skwasm renderer only, while the generated flutter_bootstrap.js pins flutterConfig.renderer to whatever web_renderer resolved to — so under the default canvaskit the loader skipped it on every page load, leaving main.dart.wasm and main.dart.mjs (~7.3 MB) in the output as files nothing requests. --wasm is now passed only when the resolved renderer is auto or skwasm, the two cases where the loader can actually select it; --no-wasm and [tool.flet.web] wasm = false are unchanged (#6828) by @ndonkoHenri.icons/loading-animation.png in the assets directory. The logo disappears on Flutter's first frame; [tool.flet.boot_screen] configures the subsequent startup screen (#6824) by @FeodorFitsner.flet run --web no longer logs assets_dir does not exist: ... for an app that simply has no assets directory. assets_dir defaults to "assets" whether or not the app has one, so the resolved path was handed downstream regardless — the desktop view ignored it silently while the web server complained, which is why the same app warned only with --web, about a directory the user never asked for. A resolved path that does not exist is now dropped at the source, making both views behave the same. A path set explicitly through FLET_ASSETS_DIR, or passed straight to FletStaticFiles when mounting on FastAPI, is always deliberate and still reports a missing directory by @FeodorFitsner..github/scripts/generate_brand_assets.py) instead of being maintained by hand across three pipelines. That surfaced a real defect in what flet build shipped: the default icon.png framed the mark at 72.9% of the canvas, outside the 66.7% that Android guarantees is visible in an adaptive icon's foreground layer — so every flet build apk produced a launcher icon cropped under circular masks, and the Android 12 splash, which clips to a circle of the same ratio, lost its edges too. The default is now framed at 60% and both render whole. Two knock-on changes worth knowing about: flet create no longer ships assets/splash_android.png, because icon.png now fits the splash circle on its own and the extra file silently won the fallback chain — replacing only icon.png gave you your own launcher icon but kept the Flet logo on the splash; and the default PWA theme_color moved from #0175C2 (Flutter's stock blue, which matched no Flet brand colour) to #FF005F, still overridable with --pwa-theme-color or [tool.flet.web].pwa_theme_color (#6816) by @FeodorFitsner.flet build generates app icons and splash screens itself, replacing flutter_launcher_icons and flutter_native_splash. Both Dart tools are gone from generated projects, along with the two pubspec.yaml config blocks that fed them; generation now runs through a new flet-platform-assets package (Pillow only, no other dependencies), and everything whose content is fixed at render time ships as a template file so the generator writes only pixels. This fixes a splash that was already broken, not just a quality gap: cookiecutter re-renders the project with overwrite_if_exists=True after the Dart tools run, restoring every file the template ships, while the change-detection stamp still recorded the earlier run — so generation was skipped on every later build and the reverted files stayed reverted. The result was that LaunchImage{,@2x,@3x}.png stayed 1x1 placeholders and Contents.json stayed light-only (the correctly generated LaunchImageDark* files were left orphaned, referenced by nothing), and launch_background.xml stayed stock white — so iOS showed no launch image at all and Android below 12 showed a plain white screen; only Android 12+ worked, because values-v31/styles.xml happens to be the one file the template does not ship. Alongside the fix, several long-standing output defects go away: web/favicon.png is 32x32 instead of a hardcoded 16x16; macOS icons get Apple's inset squircle and drop shadow instead of a plain full-bleed resize; maskable web icons are opaque and actually differ from the normal ones instead of being byte-identical copies; the Windows .ico carries 16/32/48/256 instead of a single 256 entry; apple-touch-icon-192.png is generated at last, though index.html has always linked to it; the Android 12 splash icon is fitted to the circle the platform crops it to, on the canvas the platform specifies, instead of being passed through for the user to pad by hand; web splash images are always .png, so a .webp source no longer produces a <picture> srcset pointing at files that were never written; and every downscale is done with premultiplied alpha, which removes the dark halo that any logo with soft transparent edges used to pick up. Splash bitmap sizes are unchanged and asserted against a real flutter_native_splash build, so existing apps keep the on-screen size they have today by @FeodorFitsner.flet create now ships a full-bleed assets/icon.png, and flet build linux gets the default icon it was missing. The template icon framed the mark at 60% of its canvas, which spent about 40% of every favicon, Windows .ico entry and Linux icon on empty space — those three surfaces apply no mask at all. It is now edge-to-edge, and flet build computes the margin iOS, macOS and Android need, so a new app's favicon fills its 32 pixels instead of two thirds of them. The build template also ships a Linux icon theme for the first time: an app that supplies no icon of its own already fell back to the Flet logo on iOS, macOS, Windows, web and Android, but produced a Linux bundle with no icon at all. The Flet client's own Linux icons are framed tight for the same reason by @FeodorFitsner.assets/icon.png now works everywhere: Flet computes each platform's margin instead of asking you to pick one. No single framing can satisfy every platform - web, Windows and Linux apply no mask and want the artwork edge to edge, while iOS, macOS and Android each mask the edges away and need margin - so an icon padded to survive Android wasted about 40% of every favicon, and a full-bleed one lost 24% of itself to Android's circular mask. Supply a full-bleed icon.png and it is used as-is on the unmasked platforms, then shrunk to suit each of the other three: 60% of the canvas for iOS, 68% for macOS (which Flet then insets into the squircle tile, landing at 55%), and for Android to 85% of the launcher's mask radius, measured radially because a circle clips artwork that passes an axis test. The web needs all three cases at once, so its maskable icons are framed to the safe zone the spec defines — a circle 80% of the icon's width — and apple-touch-icon, which becomes an iOS home-screen icon, is framed exactly like the native one, while the favicon and the plain Icon-*.png keep every pixel because nothing masks them. Framing only ever shrinks, so an icon you already padded is untouched, and it is skipped entirely for an opaque source, which is a finished icon rather than a glyph on a canvas and would otherwise be ringed with background colour. Supplying icon_ios.png, icon_macos.png or icon_android.png opts that platform out completely and uses your file exactly as given. flet build also warns when a source is smaller than the largest icon it is about to make — 1024px for iOS and macOS, less elsewhere — since anything below that is enlarged and looks soft, most visibly in an App Store listing by @FeodorFitsner.[tool.flet.web] pwa_background_color falls through to [tool.flet.splash] color instead of defaulting to white on its own. A browser paints the in-page splash from the page, but an installed PWA paints its launch screen from manifest.json, so the two were driven by different keys — colouring your splash left a white flash in front of it on the home screen by @FeodorFitsner.[tool.flet] icon_background sets the colour behind your icon wherever transparency cannot survive. assets/icon.png is meant to be transparent, but three surfaces reject an alpha channel: iOS, because the App Store checks for one; the macOS tile, which has to be opaque to read as a tile at all; and the maskable web icons, which render with black corners on some Android launchers otherwise. All three were hardcoded to white while Android's equivalent (adaptive_icon_background) was configurable, so an app with a dark brand had no way to avoid a white square on Apple platforms. The new key resolves platform-specific over global — [tool.flet.macos] icon_background overrides [tool.flet] icon_background — matching how the splash colours already resolve, and defaults to white so nothing changes for anyone who does not set it. Android's adaptive-icon background falls through to it as well, so one colour covers every platform; [tool.flet.android] adaptive_icon_background still overrides it. An unparsable colour warns and falls back rather than failing the build by @FeodorFitsner.flet build linux ships a proper icon theme, and flet run on Linux finally has a window icon. flutter_launcher_icons never had a Linux generator — requested since 2022 — so flet build linux installed a single file, often a 1024px image, into hicolor/256x256/; a directory that claims one size while holding another is rescaled wrongly by the icon cache, and every small panel size was downscaled from it on the fly. Each of the eight hicolor sizes is now rendered at the size its directory declares. Separately, the Flet client itself (flet run) shipped no Linux icon at all and its runner had no icon reference, so it has always shown a generic placeholder; it now carries the same generated icon set and sets its program name to the application id, so desktop environments map the running app to its desktop entry by @FeodorFitsner.FilePicker gained an on_result event, called when files are selected through a PickFiles action. A PickFiles action opens the dialog on the client before your code sees the click, so the selection cannot be returned to the caller the way pick_files() returns it - it arrives here instead. The picked files stay associated with the FilePicker, so they can be passed straight to upload() by @FeodorFitsner.flet build ipa now validates the configured provisioning profile before the build starts, instead of letting Xcode fail at the signing step minutes later with "No profile for team 'X' matching 'Y' found" — a message that cannot say what is installed. The profile is resolved the same way Xcode's PROVISIONING_PROFILE_SPECIFIER does (by name or UUID, across both directories Xcode reads), and is additionally checked for expiry, team match, and bundle-id coverage. A name that matches nothing now fails in seconds, listing the installed profiles with their teams and UUIDs so a typo — or a profile that was downloaded but never installed — is immediately obvious (#5100, #6796) by @ndonkoHenri.flet build ipa now reports the artifact it actually produced. An unsigned build yields only an .xcarchive, yet the command announced "Successfully built your .ipa bundle" and pointed at an output directory holding no .ipa; it now names the .xcarchive and explains that Xcode exports an .ipa only for a signed app. A failed export is also caught properly: flutter build ipa exits 0 when Xcode's export step fails, and the existing check for it inspected captured output — which is empty whenever -v is used, so verbose builds reported the failure as success. The check now looks for the .ipa itself (#6796) by @ndonkoHenri.flet publish now read the FLET_WEB_RENDERER, FLET_WEB_ROUTE_URL_STRATEGY, and FLET_WEB_NO_CDN environment variables as fallbacks behind the CLI options and [tool.flet.web] pyproject keys, matching the [env: ...] notation the options already advertised, by @ndonkoHenri.flet build web and flet publish no longer bundle CanvasKit and Pyodide when CDN mode is on (the default), taking a minimal web build from 71 MB to 19 MB. In CDN mode Flutter loads CanvasKit from gstatic.com and Flet points pyodideUrl at jsdelivr, so both copies were dead weight the browser never requested — yet flutter build web always emits canvaskit/ (~37 MB), and ensure_pyodide() ran unconditionally in both commands, downloading and copying a further ~15 MB. Neither is fetched, so nothing about how a CDN-mode app loads changes; verified with a network log showing the built app pulling chromium/canvaskit.{js,wasm} from gstatic and the full Pyodide runtime from jsdelivr, with no request to a local canvaskit/ or pyodide/ path. --no-cdn (or [tool.flet.web] cdn = false) still bundles everything and is unchanged. flet build also clears a pyodide/ left in the reused Flutter project by an earlier --no-cdn build, so switching modes doesn't silently keep shipping it by @FeodorFitsner.flet.canvasKitBaseUrl and flet.fontFallbackBaseUrl are now honored whenever they are set, instead of only when flet.noCdn is true. Previously flutter_bootstrap.js applied both inside if (flet.noCdn), so a host serving its own copy of the runtime — a CDN-restricted network, an air-gapped deployment, or a platform that mirrors the runtime on its own origin — had to also set noCdn for the assignment to take effect at all, and assigning the URL alone failed silently by booting off gstatic anyway. Where a runtime asset is fetched from is now independent of what the build bundled: both values default to null in CDN mode and are pinned by flet build/patch_index.py only when bundling by @FeodorFitsner.flet_web.fastapi.app() now honors the FLET_ASSETS_DIR environment variable, as it already did for FLET_UPLOAD_DIR and as ft.run() does for both, so a deployment can point a mounted app at a different assets directory without editing code (#6792) by @ndonkoHenri.serious_python to 4.6.0 and re-pinned the bundled python-build snapshot to 20260902, moving the bundled Python to 3.12.14 / 3.13.15 / 3.14.7 and Pyodide for 3.14 to 314.0.6. All three CPython micros are security releases — they fix a quadratic-complexity denial of service in incremental html.parser.HTMLParser parsing and the same in xml.etree.ElementTree XPath index predicates; 3.12.14 additionally bundles libexpat 2.8.3 for CVE-2026-72522, which 3.13.15 and 3.14.7 shipped a week too early to carry. serious_python 4.6.0 tracks the same python-build release, keeping PYTHON_BUILD_RELEASE_DATE in sync with its pythonReleaseDate as the pin requires (#6810) by @FeodorFitsner.FlutterFragmentActivity and AppCompat LaunchTheme / NormalTheme so biometric authentication dialogs work on API 24–27. A biometric cross-platform permission bundle adds NSFaceIDUsageDescription for iOS and macOS builds (#6823).[tool.flet.splash] describe the Android 12 splash icon and now say so: icon_bgcolor becomes icon_background, icon_dark_bgcolor becomes icon_dark_background, and android_12_fit becomes icon_fit. All three were undocumented, and the former names are still read so existing configuration keeps working. Every key under [tool.flet.splash] now also accepts a per-platform override at [tool.flet.<platform>.splash], which previously only the colours did. Separately, when no splash image is supplied the splash falls back to icon.png — and since an app icon fills its canvas by design, it was being drawn at full size, which made the splash artwork 67% larger than before. It is now framed for the splash, as it always effectively was when the default icon carried its own padding. An explicit splash.png is still used exactly as supplied, and opaque artwork is never resized on either path — including on the Android 12 splash icon, which previously shrank it into the middle of the circle instead of letting its colour bleed past, unlike the equivalent icon rule by @FeodorFitsner.InputBorder is a class hierarchy instead of an enum, so enum-shaped usage no longer works: InputBorder is not iterable, its members have no .value or .name, and InputBorder.OUTLINE is InputBorder.OUTLINE is now False because each access returns a new instance — compare with ==. Assigning a border is unaffected; see the deprecations below. Rendering changes as well: a border with no explicit side now takes its color and weight from the Material theme per state instead of always painting black, so dark mode and custom themes work; an underline finally honors its border_radius; DropdownM2's open menu is shaped by the new menu_border_radius rather than by the field's radius; and on CupertinoTextField, NoInputBorder() now actually removes the border while an outline without a side keeps the native iOS one. See the InputBorder class hierarchy guide (#6773) by @ndonkoHenri.Optional[...] = None, so reading one returns the value the control actually applies instead of None: the eight Paint style properties, RoundedRectangleBorder.radius, Button.autofocus, Text.no_wrap, GridView.clip_behavior, Semantics.container, ExpansionPanelList.spacing, TextField.fit_parent_size, Page.show_semantics_debugger, the three CupertinoAppBar.automatic* flags, Path.Rect.border_radius and canvas.Text.max_width. Rendering is unchanged, and properties a widget resolves at runtime from the theme, the platform or its own state keep None (#6773) by @ndonkoHenri.[tool.flet.ios.export_methods.<method>] (provisioning_profile, signing_certificate, export_options, team_id) now override the flat [tool.flet.ios] keys instead of being overridden by them. Previously a per-method value silently lost to the generic one, making the subtables useless whenever a flat key was also set; the flat key is now the shared fallback across methods — the same rule as the macOS [tool.flet.macos.signing.<lane>] subtables. See the iOS per-method signing precedence guide (#6702) by @ndonkoHenri.DragTargetEvent.x, DragTargetEvent.y, and DragTargetEvent.offset (deprecated in 0.85.0). Use DragTargetEvent.local_position for target-relative coordinates or DragTargetEvent.global_position for global coordinates (#6693) by @ndonkoHenri.Video.show_controls (deprecated in 0.85.0). Set Video.controls to None to hide controls (#6693) by @ndonkoHenri.Video.playlist_add() and Video.playlist_remove() (deprecated in 0.85.0). Mutate Video.playlist directly with list methods such as append() and pop() (#6693) by @ndonkoHenri.FletApp.show_app_startup_screen and FletApp.app_startup_screen_message (deprecated in 0.86.0). Use FletApp.boot_screen_options instead, e.g. boot_screen_options={'spinner_size': 30} or boot_screen_options={'startup_message': '...'} (#6693) by @ndonkoHenri.--clear-cache flag of flet build and flet debug (deprecated in 0.86.0). Use the flet clean command instead (#6693) by @ndonkoHenri.Page.go() (deprecated in 0.80.0). Use Page.push_route() instead (#6693) by @ndonkoHenri.Page.url_launcher, Page.browser_context_menu, Page.shared_preferences, Page.clipboard, and Page.storage_paths service accessors (deprecated in 0.80.0). Instantiate the corresponding service classes directly: UrlLauncher(), BrowserContextMenu(), SharedPreferences(), Clipboard(), StoragePaths() (#6693) by @ndonkoHenri.ConstrainedControl base class (deprecated in 0.80.0). Inherit from LayoutControl instead (#6693) by @ndonkoHenri.ElevatedButton (deprecated in 0.80.0). Use Button instead (#6693) by @ndonkoHenri.Colors aliases (BLACK12, BLACK26, BLACK38, BLACK45, BLACK54, BLACK87, WHITE10, WHITE12, WHITE24, WHITE30, WHITE38, WHITE54, WHITE60, WHITE70). Use the underscored names instead (e.g. Colors.BLACK_12) (#6693) by @ndonkoHenri.app() and app_async() (deprecated in 0.80.0). Use run() and run_async() instead (#6693) by @ndonkoHenri.target parameter of run() and run_async() (deprecated alias for main). Pass main instead (#6693) by @ndonkoHenri.Page.launch_url(), Page.can_launch_url(), and Page.close_in_app_web_view() (deprecated in 0.80.0). Use UrlLauncher().launch_url() / .can_launch_url() / .close_in_app_web_view() instead (#6693) by @ndonkoHenri.[tool.flet.app.boot_screen] / [tool.flet.app.startup_screen] build-config fallback. Use [tool.flet.boot_screen] with a named screen instead (#6693) by @ndonkoHenri."") widget-state key back-compat mapping. Use "default" (or ControlState.DEFAULT) instead (#6693) by @ndonkoHenri.flet.utils.cleanup_path(). It existed only to strip rival flutter/dart directories out of the PATH given to Flutter subprocesses, which is the cause of #5118 and no longer done; it has no remaining callers. (#6815) by @ndonkoHenri.InputBorder.OUTLINE, InputBorder.UNDERLINE and InputBorder.NONE are deprecated in favor of OutlineInputBorder(), UnderlineInputBorder() and NoInputBorder(). Each still resolves, returning the equivalent instance, and they are scheduled for removal in 1.3.0. See the InputBorder class hierarchy guide (#6773) by @ndonkoHenri.border_radius, border_width, border_color, focused_border_width and focused_border_color properties of TextField, Dropdown, DropdownM2 and CupertinoTextField are deprecated in favor of border, which accepts an InputBorder or a ControlState dictionary. They keep working and are scheduled for removal in 1.3.0; where both are set, border wins. See the InputBorder class hierarchy guide (#6773) by @ndonkoHenri.DropdownM2.border_radius is deprecated in favor of menu_border_radius for the open menu, or border for the input field. It is scheduled for removal in 1.3.0. See the InputBorder class hierarchy guide (#6773) by @ndonkoHenri.DropdownM2 is no longer deprecated and remains a supported control; its 0.84.0 deprecation in favor of Dropdown has been reverted (#6693) by @ndonkoHenri.flet build windows failing with PermissionError when removing previous build output containing read-only files, such as Git pack/index files (#6808, #6817) by @eminsk.flet build web app showing a blank page forever when its Python program fails to start. The Pyodide worker reports a startup failure by rejecting the connection, which FletBackend.connect() answered by reconnecting — right for a server still coming up, useless here, since the same program fails identically every time. So the app sat on an empty boot screen while a fresh worker re-downloaded the Python runtime every 10 seconds, and the reconnect overwrote the captured error with "Loading..." before anything could show it. A transport now raises FletAppStartupException for a failure of the app itself, which settles on the error and renders it on the boot screen; an unreachable peer still reconnects as before, keeping its error for the give-up path. Two things that hid the cause are fixed with it: the fatal init error was logged with console.log rather than console.error, invisible in a console filtered to Errors, and an unguarded flet_js.send() surfaced a misleading TypeError instead of the Python traceback (#5876, #6827) by @ndonkoHenri.Control with ID … not found) or, when something still referenced the previous instance, raised RuntimeError: Control must be added to the page first. The frozen diff that reconciles a component's output skipped any child in a single-control or list property (Container.content, DataCell.content, DataColumn.label, DataTable.columns, ...) that compared equal to the previous render's — and control equality ignores the control id, so that is every rebuilt child with stable handlers (module-level functions, use_callback, cached lambdas) or a cached subtree. The new instance was left in the rendered tree with a fresh id and no parent, while the session index kept the old one, whose parent chain died with the old tree; the next event on it - a click, a hover - failed before reaching the handler, and the mounted-control recovery walk could not find it because the live instance carried an id the client had never seen. Such children are now reconciled like any other, which emits no patch operations but migrates the id, stamps the parent and refreshes the index. Per-render lambdas masked this in most apps, since they make every rebuilt control unequal by @davidlawson.flet run --web crashing with ModuleNotFoundError: No module named 'flet_desktop' before the app started. The web branch installed flet-web, but the next line imported flet_desktop unconditionally - and that is only an optional extra of flet, so a plain pip install flet or a headless CI image never got past it. --web, --ios and --android all serve the app over the web server and none opens a native window, so they now ensure flet-web, and the desktop teardown is imported lazily and runs only when a window was opened. A failure inside the desktop-view thread also no longer leaves the CLI stuck in its wait loop (#5826, #6822) by @ndonkoHenri.ft.use_dialog() crashing the session's updates scheduler with IndexError: list assignment index out of range, which silently stops an app from responding - the scheduler task dies, so every deferred update and effect after it is dropped. After swapping in a re-rendered dialog, the hook realigned the snapshot of what the client last saw by writing at the dialog's live list index; but that snapshot only refreshes when a dialog-list update is actually flushed, so entries appended or removed since then shift the two lists relative to each other. A component can render twice within a single scheduler batch - the first render appends the dialog and queues the list update, and before it drains, another update in the same batch diffs a parent whose rebuild re-renders the host - leaving the live list one entry longer than the snapshot. The snapshot entry is now found by identity, and when the dialog has not reached the client yet the queued list update carries it instead of a patch the client would drop as an unknown control (#6814) by @FeodorFitsner.UrlTarget.BLANK not actually opening a new tab per link on the web. Its value was "blank" while SELF, PARENT and TOP all carry the leading underscore the HTML spec defines, so the value reached window.open() as an ordinary window name rather than the reserved _blank keyword: the first such link opened a tab called blank and every later one reused that same tab instead of opening its own. The LaunchMode.externalApplication upgrade that openWebBrowser() applies to _blank never fired either, so on non-web platforms BLANK did not force an external browser as intended. The enum value is now "_blank" by @FeodorFitsner.FilePicker.pick_files() never opening a dialog in a web app on iOS, and Clipboard.set(), Clipboard.set_image() and the Share methods doing nothing there either. A browser opens a file picker, writes to the clipboard or shows a share sheet only while it is handling the user's click or key press, and a service method called from an event handler misses that window entirely: the click travels to Python, the handler runs, and the instruction travels back long after the permission has lapsed. WebKit enforces this and reports nothing, while Chrome and Firefox allow the same calls, so an app worked on Android and on the desktop and silently did nothing on an iPhone or iPad - which made a browser rule look like a Flet bug, and made FilePicker in particular look broken since save_file() kept working (it clicks a download link, which is not gated). These operations are now available as client actions - ft.PickFiles, ft.CopyToClipboard, ft.ShareText, ft.OpenUrl - assigned to a control's action property and performed by the client inside the original gesture. pick_files() also no longer hangs for its full one-hour timeout when a browser has already reported it will not open the dialog: it raises straight away, pointing at ft.PickFiles (#3710) by @FeodorFitsner.flet build --description (and project.description / tool.poetry.description from pyproject.toml) never reaching the built app. The value was passed to the build template under a key no file consumed (description) while every template reads project_description, so it always rendered as its empty default — a web app's <meta name="description"> and PWA manifest.json description have been silently blank since the option was introduced. Both now receive it, as does the new Linux desktop entry's Comment=, and the value is escaped per format, so a description containing quotes, newlines or backslashes can no longer produce an unparsable pubspec.yaml/manifest.json or a desktop entry the desktop environment discards. The option is now documented under Description (#2269) by @ndonkoHenri.flet pack appearing in the taskbar as "flet", grouped together with every other Flet app and unable to carry an icon. flet pack runs the shared prebuilt client binary, and the Linux desktop keys a window's identity on its X11 WM_CLASS or Wayland app_id — both of which GTK derives from the client's argv[0], so every packed app inherited that binary's own name. The client is now launched under the app's own identity instead, taken from the new FLET_APP_ID environment variable that the PyInstaller runtime hook sets to --bundle-id when one is given and to the executable's name otherwise — so an executable named something a desktop entry should not be keyed on, such as a versioned my-app-1.2.3, can be given a stable identity; the binary is unchanged, so this needs no client rebuild and works with clients already cached. A Linux app's display name and icon come from an installed desktop entry rather than from the executable, so flet pack now writes one next to the binary — with StartupWMClass already matching the app's identity, which is the part that is impossible to guess — plus the icon itself when --icon is a .png, closing the other half of the report. Neither is installed for you, since that would change your application menu as a side effect of building; Linux taskbar identity shows the two cp commands (#5422, #6800) by @ndonkoHenri.flet pack showing a second taskbar identity named "Flet description", whose right-click entry and pin launch a blank Flet client window instead of the app. Two defects stacked up: the PyInstaller runtime hook carrying the AppUserModelID fix from #6403 was never bundled into packed apps (its rthooks.dat manifest was missing from the flet-cli wheel, and PyInstaller skips a missing manifest silently), and a process-level AppUserModelID only fixes taskbar grouping anyway — the taskbar name, icon and pin target resolve through the shell's relaunch properties, which were never set, so they fell back to the cached flet.exe. The wheel now ships the manifest, and flet_desktop stamps System.AppUserModel.ID/RelaunchCommand/RelaunchDisplayNameResource/RelaunchIconResource on the client window right after launch (new flet_desktop.win_taskbar module, pure ctypes), driven by environment variables the runtime hook sets — and settable manually when packaging by other means, such as Nuitka. Apps started hidden (AppView.FLET_APP_HIDDEN) get their taskbar identity as well, and executable paths containing spaces or longer than 128 characters are supported (#6767, #6793) by @ndonkoHenri.flet pack-patched desktop clients and the vanilla client shadowing each other through the shared ~/.flet/client/ cache. The cache was keyed by flavor and version only, so a packaged app whose bundled client was patched with a custom icon and metadata could silently run whatever same-version client happened to be cached first — and vice versa. Bundled client archives are now content-fingerprinted and each distinct client gets its own cache directory. Client archives are built deterministically so rebuilds with unchanged content reuse the same cache entry, superseded entries unused for 30 days are garbage-collected (never touching a running app's client), and concurrent first-run extractions of the same archive no longer crash the losing process (#6793) by @ndonkoHenri.FletApp web apps served from a path-prefixed URL never connecting: the embedded session derived its WebSocket path from the host document's endpoint configuration — which describes the host app and is shared by every app embedded on the page — so the URL's path prefix was lost before connecting (e.g. FletApp(url="https://gateway/device1/") behind a reverse proxy opened wss://gateway/ws instead of wss://gateway/device1/ws). Embedded apps now derive the endpoint from their own URL, matching what the io implementation already did; root apps are unchanged (#6794) by @jmvillalba.pageshow with persisted); for a hosted app the Flet session lives on the server and survives the reload, so state is preserved. The reload is gated to WebKit - every browser on iOS, Safari on macOS - because other engines restore correctly, and for a flet build web (Pyodide) app, whose state lives in the page, an unnecessary reload would destroy it. Applied to both the hosted web client and the flet build web template by @FeodorFitsner.flet create --template extension generating an example app whose pyproject.toml cannot be parsed on Windows. The [tool.flet.dev_packages] and [tool.uv.sources] entries that point back at the extension package interpolated the host's os.sep into a TOML basic string, so on Windows they rendered as "..\.." and "..\..\": the first is an invalid escape sequence, and in the second the trailing \" escapes the closing quote and leaves the string unterminated — the "unbalanced quotes" error reporters hit before they could build or run the generated example. Both paths are now written with forward slashes, which need no escaping in TOML and which pathlib and uv accept on Windows just as they do elsewhere (#5507, #6775) by @ndonkoHenri.flet publish's documented [tool.flet.web].route_url_strategy and FLET_WEB_ROUTE_URL_STRATEGY fallbacks being unreachable: the --route-url-strategy option's argparse default of "path" made the CLI value always win. The default now applies at the end of the resolution chain, as in flet build, by @ndonkoHenri.macos/Runner/*.entitlements files being rejected by codesign with AMFIUnserializeXML: syntax error when used directly for re-signing: the template emitted boolean values as self-closing tags with a space (<true />), which Xcode and plutil accept but codesign's stricter AMFI plist parser does not. The templates now emit <true/>, and flet build's own signing step additionally normalizes any entitlements file through plistlib before use, so plist formatting can never break signing (#6702) by @ndonkoHenri.CupertinoBottomSheet painting an opaque rectangular background behind custom content, which obscured rounded corners and transparent padding. Its Material wrapper is now transparent while preserving normal text styling (#4761, #6780) by @ndonkoHenri.WebView failing to open a local page on Android with net::ERR_ACCESS_DENIED, so that WebView(url="file:///…/index.html") and load_request("file://…") now work as they already did on iOS and macOS. Every URL went through webview_flutter's loadRequest(), a bare WebView.loadUrl() on Android; loadFile() is the only entry point that calls WebSettings.setAllowFileAccess(true), which defaults to false whenever the app targets API 30 or above — as Flet builds do (targetSdk 36). Chromium rendered its "Webpage not available" error page for a file the app had just written itself, making a permissions problem look like a broken path. file: URLs are now routed to loadFile() via Uri.toFilePath(), so percent-encoded paths such as iOS's Application%20Support decode correctly and sibling assets (<script src="lib.js">, stylesheets, images) resolve. load_html(base_url="file://…") maps to loadDataWithBaseURL, which does not enable file access either, so it now grants it explicitly first — through webview_flutter_android, imported behind a dart.library.io conditional so web builds are unaffected. Remote URLs are unchanged (#4627, #6787) by Note truncated.
runClientActions() and runControlActions() in utils/client_actions.dart, which perform a control's url and action properties on the client, synchronously, from inside the gesture callback that triggered them. runClientActions() resolves each action's target service through FletBackend.controlsIndex and calls Control.invokeMethod() on it without awaiting, because browsers grant gesture-gated APIs - opening a file picker, writing to the clipboard, navigator.share, window.open - only while user activation is live, and activation does not survive an async gap. The new Control.hasInvokeMethodListeners getter guards that path: Control.invokeMethod() waits for a listener when the target service is not mounted yet, and awaiting that wait would silently consume the gesture, so an unresolvable action is skipped and logged instead. A new Control.hasControlActions extension getter reports whether a control has anything to run, for controls that only install a tap handler when something is wired to them. openWebBrowser() is no longer called directly by Button, Container, IconButton, ListTile, CupertinoListTile, CupertinoButton and FloatingActionButton, which now dispatch through runControlActions(); parseTextSpans() and parseInlineSpan() take an optional trailing BuildContext so a TextSpan can carry actions too."_from_gesture": true to the arguments they invoke a service method with, so a service can tell the two entry points apart. FilePickerService uses it to emit a result event only for the gesture path - a gesture-triggered pick has no caller to return to - and to skip the new isGestureGatedDialogBlocked() check, added to utils/platform_utils_web.dart and its non-web counterpart. That check reports true only for an Apple/WebKit browser whose navigator.userActivation says no activation is live, so a pick_files() call that cannot possibly open a dialog fails immediately instead of waiting out its timeout; Chrome and Firefox permit programmatic file input clicks outside a gesture and are never reported as blocked.FormFieldInputBorder enum and its parseFormFieldInputBorder() / Control.getFormFieldInputBorder() helpers with parseInputBorder(), which builds an InputBorder from a serialized border object. parseFormFieldBorders() maps a control's border property — a single border or a map of control states — onto the InputDecoration border slots, including errorBorder, focusedErrorBorder and disabledBorder, and parseFormFieldBoxBorder() translates the same property for controls decorated with a BoxDecoration instead (#6773) by @ndonkoHenri._onPatchControl now reports a PATCH_CONTROL whose target id is missing from controlsIndex instead of silently discarding it. A dropped patch means the client and server have diverged and the screen is stale from that point on; previously nothing was logged anywhere, making the resulting "app stopped responding" impossible to diagnose. Uses print rather than debugPrint, which main.dart nulls in release builds - exactly where the message needs to be visible.FletJS.canvasKitBaseUrl is now String?. flutter_bootstrap.js applies flet.canvasKitBaseUrl and flet.fontFallbackBaseUrl whenever they are set rather than only when flet.noCdn is true, and both default to null in CDN mode — so a host serving its own copy of the runtime can point them anywhere without also claiming a no-CDN build. The getter has no readers in this package; the annotation now matches the value it can carry.Container applying its padding twice, and confining ink/hover effects to the size of its content, when ink is enabled together with animate. padding and alignment were passed both to the outer AnimatedContainer and to the inner Container under the InkWell, so the effective padding doubled; the duplicated alignment also made the Material/InkWell shrink-wrap to the content, so splashes and the hover overlay no longer reached the container's edges even though bgcolor filled it. Both properties now live only on the inner container - an AnimatedContainer when animate is set, so they still animate - matching the non-animated ink path.Fix every flet_ads control ( BannerAd , InterstitialAd , NativeAd , ConsentManager ) crashing on construction with RuntimeError: <Ad>(N) Control must
flet_ads control (BannerAd, InterstitialAd, NativeAd, ConsentManager) crashing on construction with RuntimeError: <Ad>(N) Control must be added to the page first, which made the package unusable since 0.85. The mobile-only platform guard read self.page from init(), which runs at construction — before the control is attached to the page — so the parent-chain lookup raised. The guard is back in before_update(), a post-mount hook where self.page resolves, so ads construct freely and only reject web/desktop at mount time (#6726, #6735) by @ndonkoHenri.An Android permission set to false is now actively removed from the merged manifest instead of merely being left out of the generated one. Gradle's manifest merger folds in the manifest of every Flutter plugin and can also synthesize permissions on its own, and false previously had no effect on either — the template only skipped emitting the entry, so a plugin-contributed permission passed straight through with no way to stop it. Concretely: flet-camera pulls in camera_android_camerax, which declares WRITE_EXTERNAL_STORAGE bounded to maxSdkVersion="28", and the merger implies an unbounded READ_EXTERNAL_STORAGE from it (legacy behaviour — write once implied read). Both then appear in the Play Console despite being absent from pyproject.toml, and the unbounded read is exactly the shape Google Play's storage policy objects to. Permissions set to false now render as <uses-permission android:name="…" tools:node="remove" /> (the template's <manifest> gained the tools namespace), which strips them during the merge; removing a permission nothing declares is a harmless no-op. Verified on Flet Studio: 11 permissions down to 9, both storage entries gone from the built APK by @FeodorFitsner.
Bumped serious_python to 4.5.1 and re-pinned the bundled python-build snapshot to 20260730 (dart_bridge 1.7.1). serious_python 4.5.1 tracks the same python-build release, keeping PYTHON_BUILD_RELEASE_DATE in sync with its pythonReleaseDate as the pin requires by @FeodorFitsner.
Android ProGuard/R8 rules can now be extended from pyproject.toml via [tool.flet.android].proguard_rules. The generated project's android/app/proguard-rules.pro was a fixed template file, so an app that needed an extra keep rule had no way to add one short of downloading the published build template, patching the file and passing --template. This matters for Pyjnius: autoclass() resolves Java classes by name at runtime, and R8 renames anything in the APK that isn't kept — so autoclass() on a class bundled by a Flutter plugin or by your own Java/Kotlin fails in release builds. It fails hard: JNI FindClass returns null and the process aborts with JNI DETECTED ERROR IN APPLICATION: obj == null / SIGABRT rather than raising a catchable Python exception, and because R8 only runs in release builds it never reproduces in debug. Android framework classes (android.os.Build and friends) live outside the APK and never needed a rule. Rules are appended to the defaults, since R8 has no directive that undoes a keep; to remove the defaults instead — in particular -keepnames class * { *; }, which keeps every class and member name in the app and costs 2.5 MB of classes.dex on Flet Studio (5.9 MB → 3.4 MB, -43%) — set [tool.flet.android].proguard_default_rules = false. Dropping the defaults is safe for Pyjnius's PythonActivity access, because serious_python_android 4.1.0+ ships that keep rule in its own consumer-rules.pro. Defaults are unchanged, so existing builds render exactly the same file by @FeodorFitsner.
Android Gradle properties can now be configured from pyproject.toml via [tool.flet.android.gradle_properties]. The generated project's android/gradle.properties was previously fixed, so its memory settings — org.gradle.jvmargs=-Xmx8G plus a 4 GB metaspace — could not be changed. That is larger than the total RAM of a standard GitHub-hosted runner (measured: 7.8 GB with 3 GB of swap), so release builds, which additionally run Dart AOT once per ABI and R8, could exhaust memory and stall with no error; the only workaround was to download the published build template, patch the file and pass --template. Entries in the table override the defaults or add new properties, e.g. "org.gradle.jvmargs" = "-Xmx3G -XX:MaxMetaspaceSize=1G" and "org.gradle.workers.max" = 2. Defaults are unchanged, so existing builds render exactly the same file by @FeodorFitsner.
Full Changelog: v0.86.4...v0.86.5
No changes in the flet Dart package; version bumped for release coordination with configurable Android gradle.properties on the Python side (#6733).
Fix services registered after an embedded FletApp is opened never becoming usable on the host page — calling one failed with Timeout waiting for invok
FletApp is opened never becoming usable on the host page — calling one failed with Timeout waiting for invoke method listener for <Service>(id).<method>. ServiceRegistry subclasses Service, so it registered itself on construction; when an embedded app's page built its own registry while the host page was still the current context, the embedded registry was registered as a service inside the host's registry. The client has no binding for a control of type ServiceRegistry, so building it threw Unknown service inside the host's service loop and aborted it, leaving every service positioned after that entry unbound — permanently, since the entry stays in the list. A registry is the container for services, not a service, so it no longer self-registers; the client-side loop also isolates per-service failures now, so a single unbuildable entry can't stop the rest from binding. Reproduced with a host app embedding a FletApp and registering a Clipboard afterwards by @FeodorFitsner.Full Changelog: v0.86.3...v0.86.4
ServiceBinding throws Unknown service for a control type no extension can build, and that exception escaping ServiceRegistry._onServicesUpdated() aborted the whole loop, so every service after the offending entry was silently never bound and later invokeMethod calls on them hung until they timed out. Each binding is now built independently and a failure is logged and skipped. Also rebuilds the registry when the _services control instance is replaced (not just when its uid changes), matching how the window service tracks its control by identity.An embedded FletApp can now run over the in-process dart_bridge transport instead of a socket. Set url="dartbridge://" and the client allocates a nati
An embedded FletApp can now run over the in-process dart_bridge transport instead of a socket. Set url="dartbridge://" and the client allocates a native channel, delivers its port through the new FletApp.on_connect event, and the host serves that port with a FletDartBridgeServer — so a Flet program hosted inside another Flet app (a gallery, a preview) exchanges messages at memcpy speed with no socket file, no TCP port, and no AF_UNIX path-length limit (which broke embedded apps on the iOS simulator, where the container path overflows sun_path). High-throughput DataChannels used by embedded apps (RawImage, MatplotlibChart) get their own dedicated bridge too. The transport is opt-in and falls back to the existing URL-scheme channels: on web and desktop dev builds, where dart_bridge is unavailable, hosts keep using a socket URL by @FeodorFitsner.
flet run can now pass custom arguments to your app script: everything after a -- separator is forwarded to the script instead of being parsed by Flet, and arrives there as sys.argv[1:] - e.g. flet run --web main.py -- --dataset big.csv --verbose. Previously there was no way to do this: the app was always launched as python -u <script> with no extra arguments, so a flag meant for the app was consumed by the CLI's own parser and rejected with flet: error: unrecognized arguments: --verbose. The arguments are re-applied on every hot reload and work in all run modes (desktop, --web, --ios, --android, and -m module invocations). Arguments that don't look like options can be passed without the separator (flet run main.py big.csv), and mistyped Flet options are still reported as errors - now with a hint to use -- when they were meant for the app. See Passing arguments to your app by @FeodorFitsner.
Fix iOS apps built with flet build ipa crashing at startup with Failed to lookup symbol 'serious_python_run': dlsym(RTLD_DEFAULT, serious_python_run): symbol not found. serious_python shipped dart_bridge — which provides the in-process Dart↔Python transport — as a static library linked into the app executable. An iOS executable exports nothing to the dynamic symbol table by default and the release build strips local symbols, so the dlsym lookups that Dart (DynamicLibrary.process()) and Python (import dart_bridge) perform at runtime could not resolve. Only release/archive (device) builds under the Swift Package Manager path were affected — debug and simulator builds don't dead-strip, so the failure did not reproduce there, and Android was never affected (its dart_bridge is a dynamic .so, which exports its symbols). Bumps serious_python to 4.4.0, which ships dart_bridge as a dynamic framework — embedded and signed into the app like Python.xcframework, with its symbols exported — and re-pins the bundled python-build snapshot to 20260726 (dart_bridge 1.5.1 → 1.6.1, Pyodide 3.14 314.0.2 → 314.0.3); the bundled Python versions (3.12.13 / 3.13.14 / 3.14.6) are unchanged by @FeodorFitsner.
Fix MatplotlibChart freezing permanently when its platform view is disposed with a frame in flight — the common trigger is switching to another tab inside the app, which races the frame stream: DataChannel.send on a disposed channel silently drops, so the frame's [0xFF] frame-applied ack never arrives and _send_and_wait's unbounded await parks MatplotlibChart._receive_loop — the sole consumer of the frame queue — for the rest of the session, with no exception raised; remounting opens a fresh channel but the stale ack futures were never resolved, so the chart stayed frozen. _capture_channel now resolves all pending ack futures when a new channel is captured (a fresh channel means every pending ack belongs to the disposed one), unparking the producer instantly on remount, and the ack await is bounded by FRAME_ACK_TIMEOUT (5s; a healthy ack lands in milliseconds) — on expiry the frame is dropped and its future removed from the ack FIFO so subsequent acks keep resolving the right entries (#6709, #6710) by @ForsakenDurian.
Fix a system/edge-swipe back gesture exiting the whole host app instead of navigating back when it lands on an embedded FletApp (an app rendered inside another Flet app — e.g. a gallery host running example apps in-process). The embedded app's WidgetsApp (MaterialApp/CupertinoApp) ran the default NavigationNotification handler, which reported SystemNavigator.setFrameworkHandlesBack(false) for a nested app that couldn't pop (typically a single-view example) and swallowed the notification, so the OS finished the whole activity on back and the host never got to report that it could pop. An embedded page now lets that notification bubble to the host (which re-reports canHandlePop) and chains a ChildBackButtonDispatcher to the host Router, so a system back propagates to the host and pops the view that embeds it by @FeodorFitsner.
Fix page.window.maximized = True intermittently reverting to unmaximized right after startup on macOS, when set in the same patch as page.title (e.g. page.title = "My App"; page.window.maximized = True in main()) by @davidlawson.
Fix flet build picking a non-decodable icon/splash image when several files share a base name, producing a machine-dependent NoDecoderForImageFormatException from flutter_launcher_icons. When an app's assets held, say, both icon.png and icon.svg, find_platform_image selected the first match from glob.glob(...) — whose order is filesystem-dependent — so the same app could pick icon.png on one machine and icon.svg on another (SVG is vector and can't be decoded by the raster icon/splash generators), turning a working build into a crash purely based on directory listing order. Candidates are now filtered to formats the generators can actually decode (.svg is dropped everywhere; .icns stays macOS-only and .ico Windows-only) and ranked so a raster image (.png first) always wins, making the choice deterministic across machines. When the only supplied image is an SVG (no raster sibling), it's skipped with a build-log warning and the default Flet icon is used instead of crashing by @FeodorFitsner.
Fix modal controls (AlertDialog, CupertinoAlertDialog, BottomSheet, CupertinoBottomSheet) crashing to a black screen with "setState()/markNeedsBuild() called during build" when they close in the same frame that another route or overlay opens — e.g. dismissing a bottom sheet and showing a SnackBar from one handler. The close path popped the route synchronously during build, so the exit animation notified a listener that was mid-build. Each modal now tracks its own ModalRoute and closes it in a post-frame callback, popping that route (never the topmost one); View's confirm-pop pops its own route too, so a modal dismissed in the same tick as a view pop can no longer dismiss the wrong one by @FeodorFitsner.
Full Changelog: v0.86.2...v0.86.3
FletApp (an app rendered inside another Flet app — e.g. a gallery host running example apps in-process). The embedded app's WidgetsApp (MaterialApp/CupertinoApp) ran the default NavigationNotification handler, which reported SystemNavigator.setFrameworkHandlesBack(false) for a nested app that couldn't pop (typically a single-view example) and swallowed the notification, so the OS finished the whole activity on back and the host never got to report that it could pop. An embedded page now lets that notification bubble to the host (which re-reports canHandlePop) and chains a ChildBackButtonDispatcher to the host Router, so a system back propagates to the host and pops the view that embeds it.AlertDialog, CupertinoAlertDialog, BottomSheet, CupertinoBottomSheet) throwing "setState()/markNeedsBuild() called during build" and blanking the screen when closed in the same frame another route/overlay opens (e.g. a SnackBar). Each modal now tracks its own ModalRoute and closes it via a post-frame closeModalRoute() that pops that specific route; View's confirm-pop pops its own route too, removing the wrong-route race between a dismissing modal and a view pop.Fix code edits not taking effect under flet debug android : after re-running the command, the app kept executing the previously-unpacked, stale code i
flet debug android: after re-running the command, the app kept executing the previously-unpacked, stale code instead of your changes. flet debug rebuilds and reinstalls the same-version APK on each iteration (flutter run does an update install that preserves app data), and serious_python's on-device extraction cache — keyed only on versionName+versionCode — never saw the version change, so it skipped re-unpacking the new app.zip. Bumps serious_python to 4.3.4, which folds the APK's lastUpdateTime into that cache key so every (re)install re-extracts the current code while ordinary relaunches still hit the cache. flet build apk was never affected (#6682) by @FeodorFitsner.FletApp (an app rendered inside another Flet app — e.g. a preview or gallery host that runs example apps in-process) not refreshing its UI in response to events. Auto-update mode was tracked as components_mode on a single process-global context singleton, so a host app that rendered via page.render/page.render_views turned components mode on process-wide and context.auto_update_enabled() then returned False for the embedded app too — any handler that mutated a control without calling .update() (the common imperative style, including all page.services sensor readings) silently never re-rendered. Event dispatch also ran in a fresh task whose page context var could carry a different session's page, so context-derived state resolved against the wrong session. components_mode is now stored per-Session, and Session.dispatch_event binds the page context to its own session before invoking handlers, so multiple Flet apps sharing one process keep independent update behavior by @FeodorFitsner.TextField.error_text with error (chat tutorial, mind_queue, palette_editor), and declare the device permissions each sensor example needs to run on-device — NSMotionUsageDescription on iOS for the motion/barometer sensors and android.permission.VIBRATE for HapticFeedback by @FeodorFitsner.flet run --ios / --android app URL in a desktop browser: the page loaded but stayed on the boot screen, endlessly retrying a WebSocket connection to ws://<host>:<port>/ws. Mobile-mode apps are mounted under a non-root path (e.g. /counter/main.py), so the real WebSocket route lives at /counter/main.py/ws - but since 1.0 Alpha the FastAPI wrapper always passed the bare default ws endpoint name into FletStaticFiles, bypassing its mount-path-aware fallback, and index.html got patched with flet.webSocketEndpoint="ws", which the web client resolves against the server root. The native iOS/Android client derives the path from the page URL and was unaffected. A relative WebSocket endpoint is now resolved against the app mount path when patching index.html, fixing browser access to any Flet web app mounted under a non-root path (--ios/--android, flet run --name, or a flet_web.fastapi app mounted at a sub-path) by @FeodorFitsner.RawImage and MatplotlibChart animations flooding the console with uncatchable engine exceptions (and breaking the animation) after the browser tab was backgrounded for a while and then refocused. On Flet web the frame producer runs in a Pyodide worker (or on a remote server over a WebSocket) that the browser never throttles, while the client's Flutter frame pipeline is suspended whenever the tab is hidden - so setState schedules frames that never paint and the post-frame callbacks that dispose replaced ui.Images never fire. Decoded images and pending disposals then pile up unbounded in the Dart heap and flush into the engine all at once on resume, one exception per queued frame. This is a client-side accumulation independent of transport, so it also affected native windows minimized with an animation running. Fixed in two layers: (1) a shared FrameStreamVisibility client-side mixin - used by both RawImage and flet-charts' MatplotlibChartCanvas - stops decoding/uploading and frees replaced images immediately while hidden (keeping only cheap offscreen state up to date, so incremental matplotlib diffs stay correct), then presents just the latest frame on resume; (2) a new page.wait_until_visible() gate (driven by on_app_lifecycle_state_change, alongside a page.app_visible property) that the streaming controls await internally, so producer loops park while hidden instead of rendering frames a suspended client can only discard (#6691) by @FeodorFitsner.flet build / flet publish flooding non-interactive logs (CI, cloud build, any piped stdout) with thousands of progress-spinner frames, and fix the --no-rich-output flag not actually producing plain output. The CLI's rich Console was created with force_terminal=True whenever the FLET_CLI_NO_RICH_OUTPUT env var was unset, which forces the Live status spinner to repaint even when stdout isn't a TTY — so in a pipe every animation frame lands on its own line (e.g. hundreds of ( ● ) Initializing web build... lines). And the --no-rich-output CLI flag never reached that console at all: it's parsed per-command, after the module-level console is already built, so it only suppressed emojis while color and the spinner kept going. Now the console auto-detects the terminal (force_terminal=None) — interactive terminals keep the animated spinner while piped output stays quiet — and both FLET_CLI_NO_RICH_OUTPUT and --no-rich-output (detected from sys.argv at import) force fully plain output by @FeodorFitsner.flet_video.Video resetting its volume (and pitch, playback_rate, shuffle_playlist, playlist_mode, subtitle_track) to the player's defaults after toggling visible off then on — e.g. volume jumped back to 100. Hiding a Video disposes its native media_kit player and showing it recreates a fresh one at default settings; the "last-applied" tracking now lives with the player (not the persistent control model) and is reset on recreation, so build() re-applies every setting to the new player (#6683, #6694) by @ndonkoHenri.SearchBar.on_tap_outside_bar not firing when the user tapped outside the open search view. That case now has a dedicated SearchBar.on_tap_outside_view event (fired when tapping outside the open view, e.g. to dismiss it), and on_tap_outside_bar is documented to match what it actually does: fire while the bar is focused and the view is closed, like TextField.on_tap_outside (#6593, #6697) by @ndonkoHenri.--android-legacy-packaging flag (and [tool.flet.android].legacy_packaging setting) to flet build apk/aab for opting into legacy Android native-library packaging. By default (modern packaging), native .so files are stored uncompressed and page-aligned in the APK and memory-mapped directly at runtime, which typically gives a smaller install and Play Store download but a larger raw .apk file. Enabling this option sets useLegacyPackaging = true so the .so are compressed inside the APK and extracted to disk on install: the raw .apk file is smaller (handy when side-loading), at the cost of a larger on-device install and slower native-library loading. The extraction directory is exposed to Python as ANDROID_NATIVE_LIBRARY_DIR, which can help custom native-library consumers that require a real filesystem path. See Native library packaging by @FeodorFitsner.Full Changelog: v0.86.1...v0.86.2
flet-mcp 's get_api tool now covers top-level callables — the app entry point ( run ), reactive hooks ( use_state , use_ref , use_effect , …), and dec
flet-mcp's get_api tool now covers top-level callables — the app entry point (run), reactive hooks (use_state, use_ref, use_effect, …), and decorators (component, memo, observable) — which previously returned not found because only classes were indexed. A new functions bucket in the API builder extracts each package's re-exported public callables and renders them with a signature: line. get_api also resolves enum member lookups inline: get_api("Colors", query="RED") now returns the matching members instead of erroring with a redirect to search_enum_members. Both changes remove wasted agent round-trips observed in production usage by @FeodorFitsner.flet build windows failing on non-UTF-8 system locales (e.g. Simplified-Chinese Windows, code page 936/GBK) with warning C4819 escalated to error C2220 while compiling a plugin's Windows sources. A non-ASCII character in a plugin source (e.g. an em dash in a comment) couldn't be decoded under the system code page, and the build template's /WX (warnings-as-errors) turned it fatal. The Windows build template now compiles all targets with /utf-8, so every plugin — including third-party ones flet doesn't control (e.g. connectivity_plus) — reads its sources as UTF-8 regardless of the build machine's code page. Also bumps serious_python to 4.3.3, which removes the character from its own plugin at the source (#6686) by @FeodorFitsner.shutil.ReadError: ... is not a zip file failure in web apps when the app package download fails. The Pyodide worker piped the pyfetch(app_package_url) response straight into unpack_archive() without a status check, so any non-2xx response (transient server 500, expired auth 401, deleted app 404) wrote the JSON/HTML error body to a temp file and crashed while unpacking it. The worker now checks response.ok and raises a readable Failed to download app package: HTTP <status> <url> — <body> error, including the first 200 chars of the error body. Applied to both the Flet web client and the flet build template (#6680) by @FeodorFitsner.BasePage return type and import from BaseControl and ControlEvent (#6606) by @Iaw4tch.GestureDetector.allowed_devices crashing with type 'List<dynamic>' is not a subtype of type 'List<String?>?' and preventing the control from rendering. Property values are deserialized from JSON as List<dynamic>, but the value was read via get<List<String?>>(...), whose reified cast fails because a List<dynamic> is not a List<String?>. It's now read as List<dynamic> and each entry is converted to a string before parsing, restoring supportedDevices filtering for Flutter's GestureDetector (#6684) by @TURBODRIVER.Full Changelog: v0.86.0...v0.86.1
No changes in the flet Dart package; version bumped for release coordination with the web client's readable app-package download errors (#6680).
Deprecate the --clear-cache flag of flet build and flet debug ; use the new flet clean command instead. The flag remains functional but now emits a de…
multiprocessing in packaged Flet desktop apps built with flet build macos, flet build windows, and flet build linux. multiprocessing APIs such as Process, ProcessPoolExecutor, the spawn/forkserver start methods, and the resource tracker now work in packaged desktop apps. Previously, worker processes re-executed sys.executable, which pointed to the app binary itself, causing each worker to launch another GUI app instance and hang. Flet desktop runners now detect CPython multiprocessing child command lines before Flutter starts and divert them to a headless embedded Python interpreter via dart_bridge 1.5.0+. The Python bootstrap also runs the app module as the real sys.modules["__main__"] with python -m semantics, so top-level worker functions in main.py can be pickled correctly. When using multiprocessing, your app must follow normal Python multiprocessing rules: guard ft.run(...) with if __name__ == "__main__":, define worker functions at module top level, and do not access Flet UI objects from worker processes. See the new Multiprocessing cookbook page. Mobile platforms remain unsupported because iOS and Android do not allow apps to spawn arbitrary child processes (#4283, #6577) by @ndonkoHenri.flet build and flet publish. Pick the runtime your app ships with via the new --python-version flag (3.12 / 3.13 / 3.14), or let it be derived from [project].requires-python in your pyproject.toml; defaults to the latest supported stable (currently 3.14). The matching CPython-standalone build, Pyodide release (0.27.7 / 0.29.4 / 314.0.1), and Emscripten wheel platform tag are all resolved from flet-dev/python-build's date-keyed manifest. Adding a future pre-release CPython line (e.g. 3.15 beta) is a one-row append with prerelease=True — opt-in only via an explicit --python-version 3.15 or requires-python = "==3.15.*", never the auto-resolved default. Requires serious_python >= 4.0.0, now pinned in the flet build template. See the new Choosing a Python version docs section (#6577) by @FeodorFitsner.ft.DataChannel: dedicated byte channels for widgets that move bulk binary data (image frames, audio buffers, ML tensors) between Dart and Python, bypassing the MsgPack control protocol. The Dart side opens a channel via FletBackend.of(context).openDataChannel() and announces it to Python by firing a data_channel_open control event with {channel_name, channel_id}; the Python side declares on_data_channel_open: Optional[ft.EventHandler[ft.DataChannelOpenEvent]] and captures the channel via self.get_data_channel(e.channel_id). Backed by a dedicated PythonBridge per channel in embedded native mode (4–7 GiB/s on M2 Pro) and by the default ProtocolMuxedDataChannelFactory in dev / web modes (raw-byte frames muxed over the active Flet protocol transport with a 1-byte type discriminator). Pyodide gets zero-copy outbound sends via postMessage Transferable ArrayBuffer. First consumer: flet-charts MatplotlibChartCanvas, migrated from _invoke_method PNG dispatch to a 1-byte-opcode data channel by @FeodorFitsner.dart_bridge FFI). package:flet gains a third protocol transport alongside the UDS / TCP socket servers: it can run Flet's MsgPack protocol over an in-process dart_bridge byte channel via a FletApp(channelBuilder: …) seam (the flet package stays Python-independent — it doesn't depend on serious_python or know about PythonBridge; the embedder wires the channel). serious_python >= 3.0.0 uses this seam to embed the Python interpreter in-process instead of talking to it over a localhost socket, and the flet build template migrates from sockets to the FFI transport. On Android, where the OS may keep the process alive across a back-button quit and restart only the Dart VM, the transport rebinds to the new VM's dart_bridge ports on a session-restart signal (libdart_bridge >= 1.3.0) — the Python process and its in-memory state are preserved and the Flet session is rebuilt from REGISTER_CLIENT by @FeodorFitsner.flet clean command that deletes the build directory of a Flet app — the Flutter bootstrap project, cached artifacts, and generated output — in a single step (#6233) by @ndonkoHenri.compression_quality to FilePicker.pick_files() for selecting the image compression quality used by supported platforms (#6573) by @ndonkoHenri.ConsentManager to flet-ads for gathering user consent (e.g. GDPR/EEA) via Google's User Messaging Platform (UMP) before requesting ads (#6569, #6615) by @ndonkoHenri.ft.RawImage: a high-bandwidth pixel-frame display control for Pillow output, NumPy arrays, camera frames and procedural graphics. Frames stream over a dedicated ft.DataChannel instead of the control protocol: raw premultiplied RGBA straight to a GPU texture on local transports (desktop, flet run, Pyodide), automatic PNG fallback on remote flet-web sessions. The awaitable render(pil_or_numpy) / render_rgba(w, h, bytes) / render_encoded(png_jpeg_webp_bytes) methods resolve when the client has displayed the frame, so a plain while True: await ri.render(...) loop self-paces to display speed. Premultiplied-alpha conversion runs in Pillow's C loops with an opaque fast-path; Pillow and NumPy remain optional. The last frame is retained and replayed on remount, mirroring Image.src. Ships with five gallery examples (photo viewer, plasma, Pillow paint, Mandelbrot explorer, Game of Life) and a docs page with RawImage vs Image guidance (#6674) by @FeodorFitsner.flet build / flet debug now integrate the embedded Python runtime via SPM instead of CocoaPods (CocoaPods goes read-only in December 2026). Flet auto-falls back to CocoaPods when the app depends on a package that isn't SPM-ready — currently flet-video (media_kit) — since Flutter then builds the whole app with CocoaPods. Force CocoaPods for other non-SPM packages with --no-swift-package-manager (or swift_package_manager = false under [tool.flet]). Flet does not change Flutter's global SPM configuration; the setting only selects how serious_python stages the runtime to match. When SPM is used (it has no pod install hook), flet build sets SERIOUS_PYTHON_DARWIN_SPM so serious_python's package step stages the runtime (Python/dart_bridge xcframeworks, the iOS native extensions, and the stdlib/site-packages/app resources) into the plugin's Package.swift layout on the host before flutter build, and exports the SP_NATIVE_SET cache-bust key into the build. Requires the SPM-capable serious_python release.flet build apk/aab consume serious_python's new Android packaging: Python extension modules load memory-mapped directly from the APK (no extraction to disk), and pure Python ships in stored asset zips read via zipimport, so the standard library is no longer duplicated per ABI. Apps no longer need useLegacyPackaging / keepDebugSymbols — the flet build Android template drops them; just use minSdk 23+. New --android-extract-packages flag and [tool.flet.android].extract_packages ship "path-hungry" packages — those that read bundled data via __file__ / pkg_resources instead of importlib.resources — extracted to disk instead of inside the zip (most packages, including certifi, are zip-safe and need no entry). Requires serious_python with the native-mmap packaging (dart_bridge 1.4.0).flet build template. Each flet build web / flet publish run downloads the matching pyodide-core-<version>.tar.bz2 (plus the runtime micropip and packaging wheels) into a per-version cache at ~/.flet/pyodide/<version>/ and copies the files into the build output. Subsequent builds reuse the cache; the older 0.27.5 bundle previously shipped in the cookiecutter template is gone (#6577) by @FeodorFitsner.flet-dev/python-build's date-keyed manifest.json (fetched once and cached under ~/.flet/cache), the single source of truth shared with serious_python — replacing flet's hand-mirrored version table. flet build forwards only SERIOUS_PYTHON_VERSION and lets serious_python derive the full version / build date / dart_bridge version from its own committed snapshot. The module exposes get_supported_python_versions() / get_default_python_version() (the previous SUPPORTED_PYTHON_VERSIONS / DEFAULT_PYTHON_VERSION constants are removed) (#6577) by @FeodorFitsner.flet --version shows just the Flet and Flutter versions; the static Pyodide: … line and the global flet.version.pyodide_version export are removed (the supported Python / Pyodide set now lives in python-build's manifest, not the CLI output) (#6577) by @FeodorFitsner.flet --version --json emits a machine-readable document — Flet/Flutter versions and the Linux build dependencies — for CI to read via jq instead of importing Flet internals with python -c. (The supported Python/Pyodide table is no longer included; it comes from python-build's manifest.) The canonical Linux apt dependency list moved from flet.utils.linux_deps (runtime package) to flet_cli.utils.linux_deps (build tooling) by @FeodorFitsner.client/web/python.js and the build template's python.js no longer hardcode defaultPyodideUrl. patch_index.py now injects flet.pyodideUrl per build (CDN URL by default, or the local pyodide/pyodide.js path under --no-cdn) so the runtime URL always tracks the resolved Pyodide release (#6577) by @FeodorFitsner.flet run dev mode) now use length-prefixed framing instead of streaming msgpack.Unpacker.feed. Combined with a new 1-byte type discriminator at the head of every packet (0x00 = MsgPack control frame, 0x01 = raw DataChannel frame), this unifies framing across all transports (sockets, WebSocket, dart_bridge FFI, Pyodide postMessage). StreamingMsgpackDeserializer is removed from package:flet; each inbound packet is one complete MsgPack value, decoded one-shot via msgpack.deserialize(bytes) by @FeodorFitsner.flet build template migrate to Flutter 3.44's built-in Kotlin (the Android app no longer applies the Kotlin Gradle plugin itself) and Java 17; the client's Gradle wrapper moves to 8.14 by @FeodorFitsner.MatplotlibChart now skips per-frame diffing and PNG encode/decode when the client runs on the same machine: uncompressed RGBA full frames stream straight from Agg's buffer over the chart's DataChannel (new 0x04 opcode) and are displayed with a single decodeImageFromPixels + swap on the Dart side. A 1600×1000 @ DPR 2 figure (24 MB/frame) over a local socket goes from 7.4 to 18.7 fps, leaving matplotlib's own render as the dominant per-frame cost; remote WebSocket clients keep the compact PNG full+diff pipeline. The format is auto-selected via the new Connection.local_data_transport capability flag (set by the socket, dart_bridge and Pyodide transports). Also fixes O(n²) length-prefixed packet reassembly in the Dart socket transport — multi-MB frames arrive in dozens of chunks and previously re-flattened the accumulation buffer on every chunk (#6673) by @FeodorFitsner.flet build web and flet publish now default the web renderer to canvaskit instead of auto. With auto, Chromium selects the dart2wasm/skwasm renderer, whose JS↔Dart typed-data boundary costs make byte-streaming Pyodide apps (matplotlib frames, RawImage) ~6–7x slower per frame; pass --renderer auto or set [tool.flet.web].renderer to restore the old behavior. Also fixes tool.flet.web.renderer being ignored by flet publish (shadowed by an argparse default) (#6673) by @FeodorFitsner.import flet is now lazy. The flet package previously executed its full ~270-module public API eagerly on import flet; it now resolves public names on first access via a module-level __getattr__ (PEP 562), so an app loads only the modules it actually uses. On a mid-range Android device this cut import flet from ~2.0s to ~0.15s. The eager subsystem clusters that Page pulled in (auth, components/hooks, Cupertino controls) are deferred too. Type checkers, IDEs, and from flet import * are unaffected (#6597) by @FeodorFitsner.serious_python >= 4.0.0, now pinned in the flet build template). Your Python sources ship unpacked inside the app bundle next to the stdlib/site-packages (no first-launch app.zip extraction) on macOS/iOS/Windows/Linux; on Android they ship as a stored app.zip asset unpacked once on first launch; web is unchanged. The app directory is now read-only, so the Python program's working directory moved to a writable, app-private data dir. FLET_APP_STORAGE_DATA now maps to the OS application support dir (a data subdir) instead of the user's Documents folder and is the cwd; FLET_APP_STORAGE_TEMP now points to the OS temp dir (was the cache dir) and a new FLET_APP_STORAGE_CACHE exposes the cache dir. flet run sets the dev cwd to a hidden, git-ignored <project>/.flet/storage/data. Relative reads of bundled files (open("seed.json")) must move to __file__/importlib.resources or assets/. See the app files unpacked / storage dirs guide by @FeodorFitsner.flet build and flet publish now bundle CPython 3.14 by default (previously 3.12, implicit via the old single-version serious_python). Existing apps that depend on native wheels without 3.14 binaries should pin explicitly with --python-version 3.12 (CLI), requires-python = ">=3.12,<3.13" (pyproject), or SERIOUS_PYTHON_VERSION=3.12 in the build environment (#6577) by @FeodorFitsner.pythons.<short>.android_abis) rather than hardcoded in flet. As of python-build 20260630, armeabi-v7a (32-bit ARM) is published for 3.12, 3.13 and 3.14, so all three build it by default; an explicit --arch <abi> is validated against the selected Python's supported set and fails with a clear error otherwise (#6578) by @ndonkoHenri.flet build / flet publish now compile your app and packages to .pyc by default (previously off). This removes per-launch bytecode recompilation — a significant cold-start win, especially on mobile where pure Python is imported from a stored zip (zipimport) and can't cache bytecode back to disk, so every module would otherwise recompile from source on each launch. The CLI flags gain --no-compile-app / --no-compile-packages (via argparse.BooleanOptionalAction; the existing --compile-app / --compile-packages still work), and [tool.flet.compile].app / .packages now default to true. Pass --no-compile-* or set them to false to restore the old behavior (faster iterative builds, or keeping .py source in the bundle). Compiled web builds were verified to load in Pyodide (bundled CPython and Pyodide share the same minor version). See the compile-on-by-default guide (#6598) by @FeodorFitsner.0x00 = MsgPack control frame, 0x01 = raw DataChannel frame). WebSocket / postMessage / dart_bridge transports keep native message boundaries and only gain the type byte. The Flet CLI dev server and the in-process Python runtime are upgraded in lockstep — running flet run with mismatched flet versions across CLI and runtime is no longer supported. See the DataChannel protocol framing upgrade guide. The MatplotlibChartCanvas widget transports its full / diff / clear frames via a DataChannel rather than _invoke_method arguments — visually identical, but custom code that subclassed it and overrode the apply methods may need updating by @FeodorFitsner.--clear-cache flag of flet build and flet debug; use the new flet clean command instead. The flag remains functional but now emits a deprecation warning, and is scheduled for removal in 0.89.0 (#6233) by @ndonkoHenri.'!_dirty': is not true assertion (EXCEPTION CAUGHT BY WIDGETS LIBRARY in _BootOverlay) thrown by apps built or debugged from the flet build template when the app becomes ready. With the default boot_screen.fade_out_duration of 0 the overlay's zero-duration AnimatedOpacity completed synchronously, firing onEnd — and its setState — in the middle of the overlay's own rebuild. The overlay is now removed in a single state update when no fade is configured; non-zero fade durations still animate as before. Debug-mode only: the assertion is compiled out of release builds (#6666) by @FeodorFitsner.flet build failing on Windows when a dependency is pulled in via [tool.flet.<platform>].dev_packages (or any local-path install): the rewritten <pkg> @ file://<path> URL now uses Path.as_uri(), producing the correct file:///D:/... three-slash form instead of file://D:\..., which pip on Windows parsed as a UNC path and aborted with OSError: [Errno 2] No such file or directory: '\\\\D:\\a\\...' (#6577) by @FeodorFitsner.flet build web --python-version 3.13 failing to match any Pyodide-built native wheel. The 3.13 row in the Python version registry was set to Pyodide platform tag pyodide-2025.0-wasm32, but Pyodide actually publishes 0.29 wheels under pyemscripten_2025_0_wasm32 (the pyodide_ → pyemscripten_ prefix transition happened at 0.28/0.29, not at 314.0). Corrected to pyemscripten-2025.0-wasm32 so pip's wheel selection picks up the correct tags by @FeodorFitsner.flet build now cleans the build directory when the bundled Python version changes between builds, preventing stale compiled bytecode from the previous version crashing the app at runtime with ImportError: bad magic number by @FeodorFitsner.key in tests. ValueKey(control.key) was constructed as ValueKey<Object>, and Flutter's runtimeType-strict ValueKey.== never matches that against the ValueKey<String> the rendered widget carries — so find.byKey(Key('foo')) (flutter_test) and find_by_key('foo') (Flet tester) located 0 widgets. The ValueKey is now built with the value's concrete type (String → ValueKey<String>, int → ValueKey<int>, …) on both the Dart and Python sides by @FeodorFitsner.flet build apk / flet build aab with --arch packaging native libraries for all Android ABIs instead of only the requested ones. The requested architectures are now forwarded to Flutter as --target-platform (so --split-per-abi builds only the requested splits), unrequested ABI directories are excluded from the artifact via packaging.jniLibs.excludes, Android --arch values are validated against the bundled Python's supported ABIs, multiple --arch values now correctly reach serious_python (comma-joined), and stale artifacts from previous builds are no longer copied into the output directory (#6567, #6578) by @ndonkoHenri.--arch, --source-packages and --permissions flags in flet build keeping only the values of the last occurrence (action="extend" on each) (#6578) by @ndonkoHenri.flet build apk failing at mergeDebugNativeLibs with N files found with path 'lib/<abi>/libc++_shared.so' when an app combines serious_python_android with another Flutter plugin that also bundles the NDK C++ runtime (#6570, #6571) by @ndonkoHenri.handler signatures in subscribe and subscribe_topic methods of PubSubClient for better type checking (#6549) by @Iaw4tchFilePicker.pick_files() on web for slow network shares or slow machines: pass cancel_upload_on_window_blur=False to prevent valid file selections from being reported as cancelled when the browser window loses focus during file picking (#771, #6573) by @ndonkoHenri.PagePlatform.ANDROID_TV in Page.get_device_info() retrieval (#6604) by @bl1nch.ProgressRing.year_2023 being ignored, so the control correctly switches between the latest and 2023 Material Design appearances (#6614) by @ndonkoHenri.flet build ipa / ios apps that ship ctypes packages with plain .dylib shared libraries (e.g. llama-cpp-python) now load them on the iOS simulator instead of failing at launch with a dlopen platform mismatch (have 'iOS', need 'iOS-simulator'); the iOS runtime also now bundles the _multiprocessing extension (importable, not spawnable). Bumps the pinned bundle to serious_python 4.2.1 / python-build 20260701 (serious_python#223) by @ndonkoHenri, @FeodorFitsner.ResponsiveRow (video players, WebViews, scroll positions) losing their state whenever a window resize crossed a breakpoint and the layout switched between a single row and wrapping (#6661, #6663) by @FeodorFitsner.FilePicker.save_file() documentation: on desktop, passing src_bytes writes those bytes to the selected file (#6573) by @ndonkoHenri.Full Changelog: v0.85.3...v0.86.0
No changes in the flet Dart package; version bumped for release coordination with the multi-version bundled CPython support on the Python side (#6577).
Allow [tool.flet.android.permission] values to be TOML inline tables in addition to booleans — each key = "value" entry adds an android:<key>="<value>
[tool.flet.android.permission] values to be TOML inline tables in addition to booleans — each key = "value" entry adds an android:<key>="<value>" attribute to the generated <uses-permission> element, unlocking modifiers like android:maxSdkVersion and android:usesPermissionFlags that real-world Android permissions (e.g. Bluetooth LE) require. The boolean form and the --android-permissions CLI flag are unchanged; a non-empty inline table is always emitted, an empty table ({}) is treated as false, and invalid value types fail the build with a clear error (#6550, #6551) by @FeodorFitsner.[tool.flet.android.provider] for declaring custom <provider> entries in the generated AndroidManifest.xml. Each table key is the provider's android:name; entries become android:<key>="<value>" attributes on the generated element. A reserved meta_data sub-table emits nested <meta-data> children (scalar values render as android:value="…"; inline-table values render as android:<k>="<v>" so android:resource="@xml/…" works). false / {} skip the entry; true and invalid value types fail the build with a clear error. The built-in androidx.core.content.FileProvider block is unchanged (#6556, #6559) by @FeodorFitsner.flet build web template from 0.27.5 to 0.27.7 (includes micropip 0.9.0) (#6549) by @FeodorFitsner.web/canvaskit/ build artifacts (canvaskit.js/.wasm/.symbols and the chromium/ and skwasm/skwasm_st variants) from the flet build web template — these are produced by the Flutter web build and should not have been committed into the cookiecutter template (#6549) by @FeodorFitsner.flet-build-template.zip across builds. The build template is bound to an exact Flet version and is immutable, so on every flet build / flet debug after the first, the CLI now uses a previously-downloaded zip from $FLET_CACHE_DIR/build-template/v<flet-version>/ (defaulting to ~/.flet/cache/build-template/v<flet-version>/) instead of re-fetching it via cookiecutter. The CLI also exports FLET_CACHE_DIR into the child Gradle process, so serious_python_android >= 1.0.1 lands its Python dist tarballs (python-android-dart-<py>-<abi>.tar.gz) in the same cache root by default — fixing the multi-minute "Creating app shell" / downloadDistArchive_* delay on every Android debug build. Custom --template URLs and the local-dev template path are unchanged (#6555, #6558) by @FeodorFitsner.serious_python dependency from 1.0.0 to 1.0.1 so Android builds pick up the new persistent Python-tarball cache + conditional-GET revalidation introduced in serious_python 1.0.1 (#6558) by @FeodorFitsner.flet.Router's default on_view_pop navigating to the wrong URL when an outlet=True layout sits between two views in manage_views=True mode. Popping such a view now targets the previous view entry's resolved URL — skipping outlet layouts and componentless grouping routes — instead of chain[-2], which could equal the current view's URL and strand the page route, making the next navigation to it a no-op (#6533) by @FeodorFitsner.flet-audio.Audio.play()/seek() timing out when replaying after playback had completed: under the default ReleaseMode.RELEASE the source is freed on completion and is now re-prepared on replay (#6536, #6538) by @ndonkoHenri.ft.run(view=ft.AppView.FLET_APP_HIDDEN) briefly flashing the native window in the top-left corner during Windows desktop startup. The Windows runner now respects FLET_HIDE_WINDOW_ON_START and skips the first-frame Show() call so the window stays hidden until page.window.visible = True, matching the Linux desktop behavior; the same fix is applied to the flet build windows template runner so generated apps behave consistently. On Linux, pre-show window placement actions (page.window.center(), page.window.alignment) are now deferred until the window first becomes visible to avoid an analogous flash, and the window's focused state is preserved when a prevent_close handler cancels a close attempt (#5897, #5914, #6527) by @ihmily.Full Changelog: v0.85.2...v0.85.3
centerWindow(), setWindowAlignment()) until the window first becomes visible, so page.window.center() / page.window.alignment set before page.window.visible = True no longer flash the window during startup. Also preserve the focused state when a prevent_close handler cancels a close attempt (#5897, #5914, #6527) by @ihmily.Add Route(modal=True) to flet.Router for fullscreen-dialog modal overlays that don't replace the underlying view stack — closing the modal pops it wit
Route(modal=True) to flet.Router for fullscreen-dialog modal overlays that don't replace the underlying view stack — closing the modal pops it without rebuilding the views underneath. Two flavours by placement: top-level modals are global (the base stack is rebuilt from the Router's last non-modal location), nested-child modals are local (the base stack is the chain above the modal in the route tree, so deep-link works from URL alone) (#6516) by @FeodorFitsner.Route(recursive=True) to flet.Router so a route can match itself as its own descendant — one View per consumed URL segment, ideal for tree-shaped URLs of unbounded depth (/folder/a/b/c produces a 4-View stack; back-swipe walks one segment at a time). Non-recursive children are tried before self-recursion at every depth, so a specific sibling (e.g. example/:gp*) wins over the recursive :slug without duplicating it at every level (#6516) by @FeodorFitsner.flet.Router's default on_view_pop now navigates to the matched chain's parent (chain[-2].resolved_path) instead of views[-2].route, which is robust against apps that share a View.route value between sibling tab roots to suppress switch transitions. Apps that install their own page.on_view_pop before page.render_views() still take precedence. Each sub-chain (base + modal) renders with its own LocationInfo, so is_route_active(...) inside a base view sees the base URL while a global modal is open over it (#6516) by @FeodorFitsner.sessionStorage-cloned _flet_session_id. REGISTER_CLIENT now rejects session reuse when the existing session still has a live connection, allocating a fresh session for the second tab while preserving legitimate single-tab reconnect after refresh or network blip (where connection is already None) (#6512, #6513) by @ihmily.No changes in the flet Dart package; version bumped for release coordination with flet.Router enhancements on the Python side (modal/recursive route flags, chain-based default pop).
Fix TooltipTheme.decoration so it applies to controls using ft.Tooltip(...) when the tooltip does not explicitly set decoration or bgcolor (#6432, #64
TooltipTheme.decoration so it applies to controls using ft.Tooltip(...) when the tooltip does not explicitly set decoration or bgcolor (#6432, #6482) by @ndonkoHenri.flet-geolocator.Geolocator reliability on web and desktop: get_last_known_position() no longer crashes with TypeError: argument after ** must be a mapping, not NoneType and now returns Optional[GeolocatorPosition]; get_current_position() no longer hangs forever on web (Dart-side workaround for the upstream geolocator_web 4.1.3 inMicroseconds/inMilliseconds timeout typo) and uses sensible web defaults (time_limit: 30s, maximum_age: 5m); the previously-dropped configuration argument now actually reaches getCurrentPosition on the Dart side; the position stream is gated behind a registered on_position_change/on_error handler (with cancel-on-update to prevent leaks); and platform exceptions (LocationServiceDisabledException, PermissionDeniedException, PermissionDefinitionsNotFoundException, PermissionRequestInProgressException, PositionUpdateException, TimeoutException) are now translated into actionable error messages and surfaced to Python as RuntimeError without the default Exception: prefix (#6487) by @FeodorFitsner.flet's oauthlib/httpx deps not actually excluding those packages under Pyodide: the flet build web package platform has been renamed from Pyodide to Emscripten to match platform.system() inside the Pyodide runtime, and the markers now use platform_system != 'Emscripten', so the exclusion works both via flet build and a direct micropip.install("flet") in a Pyodide REPL. Requires serious_python >= 1.0.0, which is now pinned in the flet build template (#6492) by @FeodorFitsner.No changes in the flet Dart package; version bumped for release coordination with flet-geolocator fixes on the Python side.
Remove deprecated module-level margin, padding, border, and border_radius helper functions (all(), symmetric(), only(), horizontal(), vertical()) in f…
flet-video; Video.take_screenshot() for capturing video frames; and Video.on_position_change/Video.on_duration_change events (#6463) by @ndonkoHenri.ft.Router component for @ft.component apps with nested routes, layout routes with outlets, dynamic segments, optional segments, splats, custom regex constraints, data loaders, active link detection, authentication patterns, and manage_views=True mode for view-stack navigation with swipe-back gestures and AppBar back button on mobile (#6406) by @FeodorFitsner.ft.use_dialog() hook for declarative dialog management from within @ft.component functions, with frozen-diff reactive updates and automatic open/close lifecycle (#6335) by @FeodorFitsner.scrollable, pin_leading_to_top, and pin_trailing_to_bottom properties to NavigationRail for scrollable content with optional pinned leading/trailing controls (#1923, #6356) by @ndonkoHenri.ResponsiveRow for responsive layouts whose content exceeds the available height (#2590, #6417) by @ndonkoHenri.issues property to CodeEditor (along with Issue and IssueType types) for displaying code analysis error markers in the gutter, with analysis performed on the Python side (#6407) by @FeodorFitsner.Page.pop_views_until() to pop multiple views and return a result to the destination view (#6326, #6347) by @brunobrown.NavigationDrawerDestination.label accept custom controls and add NavigationDrawerTheme.icon_theme (#6379, #6395) by @ndonkoHenri.local_position and global_position to DragTargetEvent for target-relative and global pointer coordinates (#6387, #6401) by @ndonkoHenri.AudioRecorder, including on_stream chunks and direct upload support via AudioRecorderUploadSettings (#5858, #6423) by @ndonkoHenri.Page.theme_animation_style for customizing the duration and curve of the theme cross-fade between theme and dark_theme (or disabling it with AnimationStyle.no_animation()), exposing Flutter's MaterialApp.themeAnimationStyle (#6476) by @FeodorFitsner.margin, padding, border, and border_radius helper functions (all(), symmetric(), only(), horizontal(), vertical()) in favor of the corresponding Margin, Padding, Border, and BorderRadius classmethods (#6425) by @ndonkoHenri.DragTargetEvent.x, DragTargetEvent.y, and DragTargetEvent.offset; use local_position for target-relative coordinates or global_position for global coordinates instead. These APIs are scheduled for removal in 0.88.0 (#6387, #6401) by @ndonkoHenri.Video.show_controls; set Video.controls to None to hide controls. This API is scheduled for removal in 0.88.0 (#6463) by @ndonkoHenri.Video.playlist_add() and Video.playlist_remove(); mutate Video.playlist directly with list methods such as append() and pop(). These APIs are scheduled for removal in 0.88.0 (#6463) by @ndonkoHenri.@value dataclass objects so they keep the nearest control parent/page context, and restore optional structured properties that are cleared to None and later set again (#6463) by @ndonkoHenri.Page and View vertical centering when scrolling is enabled, including hidden scrollbars, so short content remains centered in the viewport (#6446, #6450) by @ndonkoHenri.flet_video.Video controls by linking media_kit video apps against mimalloc in run and build flows (#6164, #6416) by @ndonkoHenri.flet build and flet publish dependency parsing for project.dependencies and Poetry constraints with </<=, and add coverage for normalized requirement handling (#6332, #6340) by @td3447.CodeEditor background not filling the entire area when expand=True (#6407) by @FeodorFitsner.ResponsiveRow with an explicit error, treat child controls with col=0 as hidden, and clarify Container expansion behavior when alignment is set (#1951, #3805, #5209, #6354) by @ndonkoHenri.find_platform_image selecting incompatible icon formats (e.g. .icns on Windows) by ranking glob results per target platform (#6381) by @HG-ha.page.window.destroy() taking several seconds to close Windows desktop apps when prevent_close is enabled (#5459, #6428) by @ndonkoHenri.Page.show_drawer(), close_drawer(), and root/top view accessors (appbar, drawer, navigation_bar, controls, ...) failing with TypeError under Page.render_views() by unwrapping component-wrapped views and normalizing single-view returns (#6413, #6414) by @FeodorFitsner.auto_scroll on scrollable controls silently doing nothing unless scroll was also explicitly set (#6397, #6404) by @ndonkoHenri.index.html with a 200 OK for missing asset files; requests for paths with a file extension other than .html now return a proper 404, while route-like paths still fall back to index.html for SPA routing (#6425) by @ndonkoHenri.Lottie failing to load local asset files on Windows desktop (and unreliably on other desktop platforms), so animations referenced by src="file.json" from the app's assets/ directory now display correctly (#6386, #6426) by @ndonkoHenri.Page.on_resize and Page.on_media_change not firing after mobile orientation changes (#6457, #6423) by @ndonkoHenri.flet pack desktop packaging so Windows and Linux bundles include the expected client archive, and Windows taskbar pins point to the packed app instead of the cached flet.exe (#5151, #6403) by @ndonkoHenri.flet build template: inherit from Platform.environment and use putIfAbsent for FLET_* variables so pre-set system env vars are not overwritten (#6394) by @Bahtya.NavigationBarDestination.selected_icon rendering wrongly when provided as an Icon control (#6460, #6468) by @ndonkoHenri.#c00, #fc00) rendering as invisible by expanding them to their full 6/8-digit forms (#6419, #6421) by @ndonkoHenri.LineChartEvent.spots returning undecoded MessagePack extension values instead of LineChartEventSpot objects (#6443, #6468) by @ndonkoHenri.LineChart (and other charts) silently dropping custom ChartAxisLabel entries whose value matched a tick only after floating-point rounding (e.g. 0.1, 0.2, 0.3) by switching label lookup to a tolerance-based comparison scaled to the axis interval (#6445, #6459) by @KangZhaoKui.src (e.g. Image(src="/images/foo.svg")) breaking on web when the app is mounted at a non-root URL, pass data:/blob: URIs through the asset resolver unchanged, preserve origin-relative semantics when assets_dir is unset, and add a window.flet.assetsDir JS-interop bridge so embedding hosts can supply assets_dir to the top-level FletApp (#6470) by @FeodorFitsner.MatplotlibChart on Flutter web (CanvasKit/WASM) during animations by replacing the Canvas + capture() rendering path with a dedicated MatplotlibChartCanvas widget that composites matplotlib diff frames in CPU memory; also fixes Safari async PNG decode (EncodingError: Loading error.), a render/figure.savefig() race that crashed the toolbar Download, and pan/zoom playback lag from buffered pointer events (#6473) by @FeodorFitsner.Duration fields (and other int-typed properties) silently decoding to 0 when given a Python float (e.g. Duration(seconds=2.0) causing Page.theme_animation_style to end instantly) by coercing double to int in the Dart-side parseInt (#6478, #6480) by @FeodorFitsner.crocodocs watch command for hot-reload docs development with file-watching, debounced regeneration, and optional child process management (#6402) by @ndonkoHenri.ReorderableListView app example showing add, remove, and reorder flows with stable item identity (#6374) by @FeodorFitsner.flet.utils.linux_deps and update CI workflows and publish docs to consume them dynamically (#6357, #6383) by @ndonkoHenri.serious_python to 0.9.12 in the flet build template (#6461) by @FeodorFitsner.parseControlWidget() and parseControlWidgets() utilities for converting Flet controls in protocol values to Flutter widgets (#6463) by @ndonkoHenri.View, Column, and Row content so main-axis alignment still applies (#6446, #6450) by @ndonkoHenri.ResponsiveRow with an explicit error and treat child controls with col=0 as hidden at the current breakpoint (#1951, #3805, #6354) by @ndonkoHenri.page.window.destroy() taking several seconds to close Windows desktop apps when prevent_close is enabled (#5459, #6428) by @ndonkoHenri.flet pack desktop packaging so Windows and Linux bundles include the expected client archive, and Windows taskbar pins point to the packed app instead of the cached flet.exe (#5151, #6403) by @ndonkoHenri.src (e.g. Image(src="/images/foo.svg")) against assets_dir on web so embedded apps mounted at non-root URLs load assets correctly, pass data:/blob: URIs through unchanged, preserve origin-relative semantics when assets_dir is unset, and add a window.flet.assetsDir JS-interop bridge so embedding hosts can supply assets_dir to the top-level FletApp (#6470) by @FeodorFitsner.double to int in parseInt so float values passed into int-typed protocol fields (e.g. Duration(seconds: 2.0)) decode correctly instead of falling back to the default (#6478, #6480) by @FeodorFitsner.Migrate Flet docs from MkDocs to Docusaurus for a more maintainable documentation pipeline (#6359) by @FeodorFitsner.
Fix solitaire tutorial and drag examples to use local_delta.x and local_delta.y instead of removed delta_x and delta_y (#6317, #6344) by @Krishnachait
local_delta.x and local_delta.y instead of removed delta_x and delta_y (#6317, #6344) by @Krishnachaitanyakc.flet-datatable2 on 0.83.0 (#6349, #6350) by @ndonkoHenri.Lightweight dataclass validation and deprecation with Annotated + auto-added deprecation admonitions in docs (#6278) by @ndonkoHenri.
ExpansionPanelList (#6294) by @ndonkoHenri.SharedPreferences to support int, float, bool, and list[str] values (#6304, #6267) by @ndonkoHenri.Prop updates and @value types (#6098, #6270, #6117, #6296) by @FeodorFitsner.flet packages and template artifacts from CI (#6306, #6331) by @FeodorFitsner.flet-desktop (#6290, #6309) by @FeodorFitsner.Annotated + auto-added deprecation admonitions in docs (#6278) by @ndonkoHenri..update() explicitly (#6236, #6298) by @FeodorFitsner.ReorderableListView reorder event deserialization for start/end callbacks (#6177, #6315) by @ndonkoHenri.micropip for Pyodide apps that already define dependencies in pyproject.toml (#6259, #6300) by @FeodorFitsner.Lazy-load optional auth dependencies to avoid import-time failures in web/Pyodide startup (#6258, #6280) by @ndonkoHenri.
binaryornot below 0.5 to fix build-template UTF-8 decode errors (#6276, #6279) by @ndonkoHenri.Nothing published for this version
Add Auth0 audience support through OAuth authorization_params (#3775, #6205).
audience support through OAuth authorization_params (#3775, #6205).Map.get_camera(), MapEventType, and richer MapEvent payloads in flet-map (#6196, #6208).InterstitialAd is now a Service, and BannerAd is now a LayoutControl (#6194, #6235).CodeEditor with Chinese pinyin input support and aligned gutter rendering (#6211, #6243, #6244).Trolli app declarative example rewrite (#6242).Tabs, TabBar, Tab, and TabBarView (#6220, #6224).WebView null-check crash (Null check operator used on a null value) (#6238).Add CodeEditor control (#6162).
Camera control (#6190).CodeEditor control (#6162).PageView control (#6158).flutter_colorpicker (#6109).LayoutControl.transform and RotatedBox control (#6198).LayoutControl.on_size_change event for size-aware layouts (#6099).Hero animations (#6157).FilePicker with_data support for file content (#6199).ignore_up_down_keys to TextField and CupertinoTextField (#6183).flet build --artifact and iOS simulator build targets (#6074, #6188).object_patch memory churn (#6204).style patching and clear stale style state (#6119).AlertDialog and CupertinoAlertDialog barrier color updates (#6097).ControlEvent runtime type hints (#6102)..mjs and .wasm (#6140).Fix memory leak in Flet web apps (#6089).
fix: Enable TextButton style and full-width Dropdown (#6048).
Lazy loading of icons, theme for faster app startup (#6043).
locale prop to CupertinoDatePicker, DatePicker, DateRangePicker, TimePicker (#6030).datetime instances to UTC while passing over the wire (#6023).badge_position and title_position of PieChartSection accept values >= 1.0 (#6024).GestureDetector.on_tap event (#6016).locale prop to CupertinoDatePicker, DatePicker, DateRangePicker, TimePicker (#6030).badge_position and title_position of PieChartSection accept values >= 1.0 (#6024).GestureDetector.on_tap event (#6016).parseEnum utility function.OAuth fixes and updated examples (#5996).
LinearGradient alignment defaults + allow multiple use of --exclude option in flet build (#5986).on_long_press and on_hover events to IconButton (#5984).asyncio.iscoroutinefunction with inspect.iscoroutinefunction (#5928).flet_permission_handler when using Python 3.14 (#5896).Fix flet publish to sub-directories, Icons Browser and other Gallery examples updated #5964.
flet publish to sub-directories, Icons Browser and other Gallery examples updated #5964.Flet 1.0 Beta Release – Read the announcement
New: Multiple subscribers can subscribe to a published topic by send_all_on_topic
send_all_on_topic (#5303)Fixed missing imports in __init__.py (#5292).
Nothing published for this version
feat(cli): flet -V as alternative to flet --version
flet -V as alternative to flet --version (#4791)Dropdown.expand has no effect (#5042)on_double_tap, on_pan_start) in WindowDragArea (#5043)ReorderableListView drag handle listeners (#5051)LineChartDataPoint.tooltip not properly rendered (#5105)Page.__on_authorize_async (#5154)FilePicker upload fails if original filename is modified (#5037)Remove deprecated Control.update_async() method
flet build: allow dependencies with commas (#5033)Textfield cursor position changes when modifying field content in on_change (#5019)Control.update_async() method (#5005)Added FletApp.showAppStartupScreen and FletApp.appStartupScreenMessage properties.
FletApp.showAppStartupScreen and FletApp.appStartupScreenMessage properties.tool.flet.splash.icon_bgcolor and tool.flet.splash.icon_dark_bgcolor settings for Android splash screen icon image.tool.flet.app.boot_screen and tool.flet.app.startup_screen settings for customizing Flet app "loading" screens.Dropdown.menu_width property (#5007)Fix: do not remove flutter-packages on re-build if dev_packages configured.
flutter-packages on re-build if dev_packages configured.Fixes to make flet build work in CI environment
flet build work in CI environment (#4993)Error on second flet build run "Because {app} depends on flet_{package} from path which doesn't exist"
<application> element properties in pyproject.toml (#4977)Control.build() method.Fixed: binary file operations should not specify encoding.
Remove v0.24.0 deprecations #4932)
DropdownMenu control (#1088)ReorderableListView Control (#4865)Container.dark_theme property (#4857)httpx Support (#4840)CupertinoCheckbox.inactive_color in favor of fill_color (#4837)flet build: use Provisioning Profile to sign iOS app archive (.ipa), deprecate --team option (#4869)flet doctor CLI command (#4803)ElevatedButton, OutlinedButton, TextButton, FilledButton, IconButton ) (#4872)ControlEvent.data should be of type Optional[str] and default to None (#4786)flet build: add --source-packages to allow installing certain Python packages from source distros (#4762)SearchBar.bar_border_side isn't visually honoured (#4767)SearchBar.blur() to programmatically unfocus the bar (#4827)Remove v0.26.0-related deprecations
flet_* packages moved to separate repositories (#4721)ListView.controls (#3931)InteractiveViewer transformations (#4391)Window.ignore_mouse_events (#4465)Optional[] from predefined typing *Values (#4702)InteractiveViewer update events (#4704)SafeArea object has no attribute _SafeArea__minimum (#4500)Segment and BarChartRod on update() (#4525)CheckBox.border_side.stroke_align to an Enum fails (#4526)ControlState should be resolved based on user-defined order (#4556)Dismissible.dismiss_direction (#4557)DatePicker regression with first and last dates (#4661)flet build command: Copy flutter-packages, support for platform-specific dependencies (#4667)CupertinoBottomSheet applies a red color and yellow underline to Text content (#4673)ButtonTheme displays a grey screen (#4731)Textfield input border color considers user-specified border_color property (#4735)Tooltip.message a required parameter (#4736)Fix flet publish creates broken website if no requirements.txt or pyproject.toml found (#4493).
flet publish creates broken website if no requirements.txt or pyproject.toml found (#4493).git, path, url Poetry-style dependencies in pyproject.toml (#4554).Map.center_on() and default animations (#4519).Segment and BarChartRod on update() (#4525).CheckBox.border_side.stroke_align to an Enum fails (#4526).ControlState should be resolved based on user-defined order (#4556).Dismissible.dismiss_direction (#4557).Added InteractiveViewer programmatic transformations (#4451).
Mobile Ads (Banner and Interstitial) (details and example).
Banner and Interstitial) (details and example).Button control (#4265) - which is just an alias for ElevatedButton control.Badge Control to a Dataclass; added new badge property to all controls (#4077).{value_length}, {max_length}, and {symbols_left} placeholders to TextField.counter_text (#4403).--skip-flutter-doctor to build cli command (#4388).WebView enhancements (#4018).Map control enhancements (#3994).Theme props (#4278, #4278).__contains__ methods in container-alike Controls (#4374).Markdown code theme (#4343).barrier_color prop to dialogs (#4236).icon and icon_content props into icon: str | Control (#4305).colors and icons variables to Enums (#4180).suffix_icon, prefix_icon and icon can be Control or str (#4173).--pyinstaller-build-args to flet pack CLI command (#4187).rive_common.Icon rotation (#4384).Markdown.code_theme when using MarkdownCodeTheme enum (#4373).Segment and NavigationBarDestination accept only string tooltips (#4326).date has wrong format (#4019).MapConfiguration.interaction_configuration is not honoured (#3976).Video.jump_to() fails with negative indexes (#4294).AppBar.tooltip_opacity (#4280).CancelledError (#4268).CupertinoContextMenuAction doesn't close context menu (#3948).max_menu_height (#3974).before_update() (#4181).label is set, use MainAxisSize.min for the Row (#3998).NavigationBarDestination.disabled has no visual effect (#4073).CupertinoTextField (#4103).jsonDecode tooltip before displaying (#4069).bgcolor, color and elevation (#4126).no_rich_output is True (#4108).TextField freezes on Linux Mint #4422](https://github.com/flet-dev/flet/pull/4422)).FIXED: Tooltip displays wrong message when used with IconButton, FloatingActionButton and PopupMenuButton
NEW: Adding Background/Foreground Services to GeoLocator UPDATE
Placeholder Control (#3646)InteractiveViewer Control (#3645)Container.ignore_interactions property (#3639)rtl prop to more controls (#3641)TextField.counter property (#3676)flet_video to know what song is playing (#3772)floating_action_button_theme property to Theme (#3771)on_completed event to flet_video (#3758)focus, on_focus, on_blur to SearchBar (#3417, #3752)--no-rich-output flag to prevent rich output (#3708)Tooltip a dataclass which can be used in Control.tooltip (#3837)Views into a background container (#3820)flet.map is not available after building app (#3845)InputFilter clears TextField when an invalid character is entered (#3779)Dropdown.alignment not respected (#3737)CupertinoPicker (#3678)PieChartEvent.type on web (#3611)Switch.width and height properties (#3670)TextStyle and *Event classes (#3551)*Buttons (#3582)CupertinoAppBar (#3603)Sequence instead of list (#3661)CHANGED: Delete Page.window.on_resize | deprecate Page.on_resize in favor of Page.on_resized
Slider.value defaults to min (#3503)isinstance check in SnackBar.before_update to use a tuple of types instead of Union, resolving TypeError: "Subscripted generics cannot be used with class and instance checks".Page.open() breaking after multiple calls.FIX: Fix parseFloatingActionButtonLocation() to work on desktop
ParamSpec from typing for Python >3.10.len(list(filter(...))) by any(...).NEW: An ability to access PubSubHub from outside Flet app
PermissionHandler control (#3276)Map control (#3093)Geolocator control (#3179)AutoFillGroup Control (#3047)TextStyle props: overflow, word_spacing, baseline (#3435)Container.color_filter property (#3392)dropdown.Option.text_style property (#3293)dropdown.Option.content property (#3456)Video.configuration property (#3074)NavigationDestination to NavigationBarDestination (#3172)numbers.dart utils (#3263)page.window_* and page.browser_context_menu_* properties to Window and BrowserContextMenu classes (#3463)Container.on_tap_down not called when on_click is not provided (#3442)Nothing published for this version
Added --exclude option to flet build command
AutoComplete control (#3003)--exclude option to flet build command (#3125)CupertinoTimePicker.alignment property (#3036)file_picker dependency to 8.0.3.flet --version command for source checkout.pubspec.yaml for adding custom Flutter packages requires dependency_overrides (#3187)disabled dropdown (#3183)Controls enhancement (see #2882 for details).
Theme Enhancement (#2955).Rive Control (#2841).Control.parent property (#2906).Container.on_tap_down event.upload_endpoint_path into flet.fastapi.app (#2954).page.run_task (#2959).Container: fix triggered both on_click and on_long_press events (#2914).Replace deprecated (in Python 3.12) datetime.utcnow() with datetime.now(timezone.utc).
--android-adaptive-icon-background to flet build command._FletSocketServer__receive_loop_task error on Linux.datetime.utcnow() with datetime.now(timezone.utc).self.__executor.shutdown for Python 3.8.Python dependencies bumped and loosen.
EventHandler: do not call it when converter returned None.FastAPI instead of built-in Fletd server. Mixed async/sync apps. (#2700).
CupertinoActivityIndicator Control (#2762).LottieControl and Video v2 (#2673).CupertinoActionSheet and CupertinoActionSheetAction controls (#2763).CupertinoSlidingSegmentedButton and CupertinoSegmentedButton controls (#2767).CupertinoTimerPicker and CupertinorPicker Controls (#2743).CupertinoContextMenu and CupertinoContextMenuAction controls (#2772).CupertinoDatePicker Control (#2795).Page.on_app_lifecycle_state_change event (#2800).Semantics properties and SemanticsService control (#2731).label_style property for Checkbox, Switch, and Radio (#2730).__init__ (#2724).Move system_overlay_style from AppBar to Theme (#2667).
system_overlay_style from AppBar to Theme (#2667).flet build command checks minimal Flutter SDK version.CupertinoDialogAction controls inside adaptive dialogs.FletApp control takes control create factories from a parent app.Fixed scrolling behavior changes in scrollable controls.
AppBar.system_overlay_style property (#2615).
AppBar.system_overlay_style property (#2615).CupertinoButton props: filled, style.bgcolor, style.padding, text, icon, icon_color.NavigationBar.border property which is used in adaptive mode only.Page.design and Pagelet.design properties to force Material, Cupertino or Adaptive design language on entire app (#2607).Page.media property with the data about obstructed spaces on the device (#2613).Control.on_update() method for better custom controls.--include-packages option and support for pubspec.yaml for custom Flutter packages plus API for adding custom Flutter packages.rtl property to multiple controls (#2582).TextStyle.letter_spacingproperty (#2574).Audio, AudioRecorder, Video and WebView controls moved into separate Flutter packages (#2579).Control.on_update() overridable method (#2578).AlertDialog properties: icon, bgcolor, elevation.expand_loose property for Control and all controls that have expand property (#2561).flet create command to show verbose output (#2544).AudioRecorder control (#2494).flet pack --distpath deletes dist directory (#2500).adaptive property to all container-alike controls.TextField.text_vertical_align property (#2496).CupertinoButton Control (#2495).CupertinoListTile control (#2487).Pagelet control (#2469).AppBar.adaptive (#2458).CupertinoTextfield control (#2417).FloatingActionButtonLocation offset (#2411).Text.style type Deprecation warning (#2286).
flet build to apply Python SSL fix when packaging for iOS and Android (#2349).build app template (#2350).flet build -vv should run pip install with verbose output (#2351).flet build should raise an error when trying to package an app with native modules for iOS or Android (#2356).flet build to add timestamp (hash) asset with Flet Python app to re-extract when code changes (#2289).if __name__ == "__main__" check on Android.pyproject.toml.flet build to fix --base-url with surrounding slashes (#2369).CupertinoAlertDialog, CupertinoDialogAction, adaptive property for AlertDialog (#2365).Dismissible.confirmDismiss prop (#2359).ListView.reverse and GridView.reverse props (#2335).Text.style type Deprecation warning (#2286).LineChartData.prevent_curve_over_shooting and LineChartData.prevent_curve_over_shooting_threshold props (#2354).flet build to add checks to allow certain build commands according to "build_on" platform (#2343).flet build gives "OSError: [WinError 193] %1 is not a valid Win32 application" for some users (#2318).DISPLAY instead of XDG_CURRENT_DESKTOP to check if linux machine is GUIless or not (#2373).Refactor code, add Enum deprecation utils (#2259).
flet build command to package Flet app for any platform (docs).CupertinoAppBar control (#2278).MenuBar, SubMenuButton and MenuItemButton controls (#2252).CupertinoNavigationBar control (#2241).
CupertinoSlider control and Slider.adaptive (#2224).
CupertinoSlider control and Slider.adaptive (#2224).CupertinoRadio control and Radio.adaptive (#2225).NavigationBar.label_behavior (#2229).CupertinoSwitch control (docs).ValueError on web page resize (#1564).Your coding agent can read these notes before it upgrades. Set up the MCP server →