Run embedded FletApps over the in-process dart_bridge transport - #6723
Merged
Conversation
Updates the FVM-pinned Flutter SDK from 3.44.7 to 3.44.8 so local and CI environments use the newer patch release consistently.
Fixes 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 -- 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 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/simulator don't
dead-strip, and Android was never affected (its dart_bridge is a dynamic
.so that exports its symbols).
serious_python 4.4.0 ships dart_bridge as a dynamic framework, embedded
and signed into the app like Python.xcframework with its symbols
exported. Its bundled python-build snapshot moves to 20260725
(dart_bridge 1.5.1 -> 1.6.1, Pyodide 3.14 314.0.2 -> 314.0.3), so
PYTHON_BUILD_RELEASE_DATE is re-pinned to match -- the two must reference
the same python-build release. Bundled Python versions (3.12.13 /
3.13.14 / 3.14.6) are unchanged.
Verified the pinned manifest resolves: 3.12.13 / 3.13.14 / 3.14.6 with
Pyodide 314.0.3 on 3.14.
An embedded FletApp (a Flet program hosted inside another Flet app -- a
gallery, a preview) could only reach its host over a socket. On mobile that
means a Unix domain socket, whose path is capped at ~104 bytes: on the iOS
simulator the container path overflows it and every embedded app fails with
"AF_UNIX path too long". It is also needlessly slow for two programs sharing
one process.
Embedded apps can now use dart_bridge, the same in-process transport the
root app already uses. dart_bridge channels are keyed by a Dart-allocated
native port, so the rendezvous is inverted compared to the socket flow:
- FletAppControl sees url="dartbridge://", asks the registered connector
for a channel, and hands the allocated port to the host's Python via a
new FletApp "connect" control event.
- The host serves that port with a FletDartBridgeServer. The channel's
existing send-retry loop covers the window before the handler registers.
The flet package stays free of any serious_python dependency: it exposes a
process-global embeddedDartBridgeConnector hook that the build template's
native_runtime.dart registers, reusing the PythonBridge-backed channel and
data-channel factory already defined there. Each embedded app mints its own
PythonBridge, and high-throughput DataChannels (RawImage, MatplotlibChart)
get dedicated bridges as before.
Opt-in and backwards compatible: without the scheme, or where dart_bridge
does not exist (web, desktop dev), FletApp keeps using the URL-scheme
channel factory, so hosts can fall back to a socket URL.
Deploying flet-website-v2 with
|
| Latest commit: |
042dca5
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://63210043.flet-website-v2.pages.dev |
| Branch Preview URL: | https://flet-app-dart-bridge.flet-website-v2.pages.dev |
Updates the build template to use `serious_python` 4.4.1 and advances the pinned python-build release date from `20260725` to `20260726` in the CLI. The changelog entry was adjusted to match the new snapshot date for the iOS startup crash fix notes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lets an embedded
FletApp— a Flet program hosted inside another Flet app (a gallery, a preview) — run over the in-processdart_bridgetransport instead of a socket. Also pinsserious_python4.4.0 / python-build 20260725.Why
An embedded app could only reach its host over a socket. On mobile that's a Unix domain socket, whose path is capped at ~104 bytes (
sun_path) — on the iOS simulator the container path overflows it and every embedded app dies withAF_UNIX path too long. It's also needlessly slow for two programs sharing one process.dart_bridgeis the same in-process transport the root app already uses, and it's already wired up in everyflet buildoutput.The rendezvous
dart_bridgechannels are keyed by a Dart-allocated native port, so the flow inverts compared to sockets (where Python creates the socket and hands over a path):FletAppControlseesurl="dartbridge://"and asks the registered connector for a channel.FletApp.on_connectevent.FletDartBridgeServer.The channel's existing send-retry loop covers the window before Python registers its handler, so there's no ordering requirement between the two sides.
This mirrors how
DataChannelalready propagates a Dart-allocated port to Python (RawImagefiresdata_channel_openwithchannel_id) — same pattern, applied to a whole embedded app.Keeping
fletfree ofserious_pythonThe
fletpackage can't depend onserious_python(it has to compile for web, wheredart:ffidoesn't exist). Sofletexposes a process-global hook:The build template's
native_runtime.dart— which already ownsPythonBridge— registers it ininitBridges(), reusing the_DartBridgeBackendChanneland_PythonBridgeDataChannelFactoryalready defined there. Each embedded app mints its ownPythonBridge, and high-throughputDataChannels (RawImage,MatplotlibChart) still get dedicated bridges.Opt-in and backwards compatible
Without the
dartbridge://scheme — or anywheredart_bridgedoesn't exist (web, desktop dev) — the connector is null andFletAppuses the URL-scheme channel factory exactly as before, so hosts can fall back to a socket URL. Existing embedded apps are unaffected.Also in this PR
Pins
serious_python4.4.0 andPYTHON_BUILD_RELEASE_DATE20260725 (they must reference the same python-build release). 4.4.0 shipsdart_bridgeas a dynamic framework, fixing iOS release builds crashing at startup withFailed to lookup symbol 'serious_python_run'— see flet-dev/serious-python#240, flet-dev/dart-bridge#11 and #12. Bundled Python versions are unchanged (3.12.13 / 3.13.14 / 3.14.6).Verification
Validated end to end on a real iPhone with Flet Studio's gallery, which hosts each example as an embedded
FletApp:dart_bridge; theAF_UNIX path too longfailure is gone.DataChannelpath.dispose()runs on unmount).flet run, wheredart_bridgeis absent, still runs the same examples over the socket fallback.flutter analyzeclean.Summary by Sourcery
Enable embedded Flet apps to use an in-process dart_bridge transport via a new connector and event-based rendezvous, while keeping socket-based communication as a fallback where dart_bridge is unavailable.
New Features:
Bug Fixes:
Enhancements:
Build:
Documentation: