Flutter 3.29 Merges Platform and UI Threads: What It Means for Cross-Platform Development
Flutter 3.29 merges the Android/iOS platform thread with the Flutter UI thread, causing Dart code to run on the app’s main thread, simplifying task‑runner coordination, microtask handling, and synchronous platform interactions—while improving rendering and text input, it may break unadapted plugins unless the feature is disabled via metadata.
Flutter 3.29 introduced a significant architectural change by merging the Android and iOS platform threads with the Flutter UI thread. This means that on Android and iOS, Flutter now executes Dart code on the application's main thread, eliminating the separate Dart UI thread that existed previously.
The change involves several key concepts. Dart code runs within isolates, with the main entry point (main) running in the root isolate, which serves as the Dart main thread. Runners are Flutter's abstract concept for task execution - they don't have a direct relationship with isolates. The Flutter engine can submit tasks to runners, which is why runners are also called TaskRunners. Flutter has four task runners: UI, GPU, IO, and Platform.
Previously, separate threads were created for UI, GPU, and IO tasks, with the UI Task Runner being the Dart root isolate. The Platform Runner was the device platform's main thread. This separation meant Flutter's UI Runner and the platform's Platform Runner ran on different threads, requiring asynchronous platform channels for communication between Dart and native code.
In Flutter 3.29, these threads are merged by default (merged_platform_ui_thread=true), meaning the UI Runner now equals the Platform Runner. This change allows the Dart root isolate to associate directly with the Platform Runner. The engine doesn't care which thread a runner executes on - it just needs a place to run tasks.
The change affects how microtasks are handled. Previously, UI runners used independent MessageLoopTaskQueues for microtask processing. After merging, since the UI Runner becomes the Platform Runner, there's no associated task queue, requiring manual microtask flushing after running tasks.
Most PostTask calls have become RunNowOrPostTask, with execution location determined by checking MessageLoop initialization status. On iOS, the same principle applies - using the current MessageLoop directly.
The benefits of this change include: supporting rendering PlatformView on iOS without merging raster threads, simplifying text input by allowing synchronous FFI execution of platform interactions, reducing memory caching of text and state, and simplifying scenarios like Android WebView's shouldOverrideUrlLoading that require immediate synchronous responses.
While this change may cause issues for plugins that aren't properly adapted (potentially causing ANR in extreme cases), it represents Flutter's direction toward eliminating platform/message channels entirely. The Flutter team views this as inevitable, with synchronous calls and interoperability being the trend in cross-platform development, similar to React Native.
Developers can disable this feature by adding specific metadata configuration to maintain the previous behavior if needed.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.