What’s new in Flutter 2.5

Performance improvements, DevTools updates, new Material You support, a new app template, and more!

Chris Sells
Flutter

--

Hello and welcome to Flutter 2.5! This is a big release, with the 2nd highest stats in the history of Flutter releases: 4600 issues closed and 3932 PRs merged from 252 contributors with 216 reviewers. If we look back over the last year, we see a huge 21,072 PRs created by 1337 contributors, of which 15,172 of them were merged. While the “what’s new in Flutter” blog posts focuses on new features, our #1 job with Flutter is always making sure you have the features you need at the highest possible quality level.

And in fact, this release continues a number of important performance and tooling improvements to track down performance problems in your own app. At the same time, there are a number of new features, including full screen support for Android, more Material You (also called v3) support, updated text editing to support switchable keyboard shortcuts, a new, more detailed look at your widgets in the Widget Inspector, new support for adding dependencies in your Visual Studio Code projects, new support for getting coverage information from your test runs in IntelliJ/Android Studio and a whole new app template to serve as a better foundation for your real-world Flutter apps. This release is jam-packed with exciting new updates, so let’s get started.

Performance: iOS shader warmup, async tasks, GC & message passing

This release comes with several performance improvements. First on this list is a PR to wire up Metal shader precompilation from offline training runs (#25644), which (as our benchmarks show) cuts worst case frame rasterization times by 2/3s, and the 99th percentile frame by half. We continue to make progress on reducing iOS jank and this is another step along that path. Shader warmup is but one source of jank, however. Previously, processing asynchronous events from the network, filesystem, plugins, or other isolates could interrupt animations, another source of jank. Following improvements to scheduling policies (#25789) on the UI isolate’s event loop in this release, frame processing now takes priority over processing other asynchronous events, eliminating jank from this source in our testing.

Frame lag due to processing asynchronous event results before and after

Another cause of jank is when the garbage collector (GC)pauses the UI thread to reclaim memory. Previously, memory for some images would only be reclaimed lazily in response to GC performed by the Dart VM. As a workaround in earlier releases, the Flutter Engine would hint to the Dart VM that image memory could be reclaimed by a GC, which in theory could lead to more timely memory reclamation. Unfortunately, in practice this led to too many major GCs, and the memory would still sometimes not be reclaimed quickly enough to avoid low-memory situations on memory constrained devices. In this release, memory for unused images is reclaimed eagerly (#26219, #82883, #84740), reducing GCs considerably.

GCs before and after adding the fix to eagerly reclaim unused large image memory

For example, in one of our tests, playing a 20 second animated GIF went from needing 400+ GCs to needing just 4. Fewer major GCs means that animations involving images appearing and disappearing will have less jank, and consume less CPU and power.

Another performance improvement in Flutter 2.5 is the latency when sending messages between Dart and Objective-C/Swift (iOS) or Dart and Java/Kotlin (Android). As part of tuning-up message channels generally, removing unnecessary copies from messaging codecs reduced latencies by up to 50% depending on message size and device (#25988, #26331).

iOS message latencies before and after

You can read more about the details of this work in the Improving Platform Channel Performance in Flutter blog post by Aaron Clarke.

One final performance update if you’re targeting iOS: In this release, Flutter apps built on on Apple Silicon M1 Macs run natively on ARM iOS simulators (#pull/85642). This means there’s no Rosetta translation between the Intel x86_64 instructions and ARM, which increases performance during your iOS app testing and allows you to avoid some subtle Rosetta issues (#74970, #79641). This is another step along the path for full support in Flutter for Apple Silicon. Stay tuned for more.

Dart 2.14: formatting, language features, pub & linting out-of-the-box

Of course, Flutter isn’t Flutter without the Dart language and runtime on which it builds. This release of Flutter comes with Dart 2.14. The new release of Dart comes with new formatting to make cascades more clear, new pub support for ignoring files, and new language features, including the return of the legendary triple shift operator. In addition, and one of the best things about Dart 2.14, is that this release has created a standard set of lints shared between new Dart and Flutter projects that come right out of the box.

`flutter create` comes out of the box with an analysis_options.yaml file pre-populated with recommended Flutter lints

Not only do you get these lints when you create a new Dart or Flutter project, but with just a few steps, you can add this same analysis to your existing apps as well. For the details of these lints, the new language features and more, check out the release announcement for Dart 2.14.

Framework: Android full screen, Material You & text editing shortcuts

The Flutter 2.5 release includes a number of fixes and improvements to the framework. Starting with Android, we’ve fixed a set of related issues around full screen modes with nearly 100 thumbs up between them. The names of the modes themselves makes this one of our favorite new features: lean back, sticky, sticky immersive, and edge to edge. This change also added a way to listen to fullscreen changes in the other modes. For example, if the user engages with the app, when the system UI comes back, developers can now write their code to return to fullscreen or do something else.

New Android edge-to-edge mode: normal mode (left), Edge to Edge mode (center), Edge to Edge with a custom SystemUIOverlayStyle (right)

In this release, we continue to build support for the new Material You (aka v3) specification, including updates to floating action button sizes and theming (#86441), and a new MaterialState.scrolledUnder state that you can see in action with the sample code in the PR (#79999).

New Material You FAB sizes
New MaterialState.scrolledUnder state in action

And while we’re talking about scrolling, another improvement is the addition of scroll metrics notifications (#85221, #85499), which provide notifications of scrollable areas even if the user isn’t scrolling. For example, the following shows the scrollbar appearing or disappearing as appropriate based on the underlying size of the ListView:

The new scroll metrics notifications enabling the scrollbar to appear and disappear automatically without scrolling

In this case, you don’t have to write any code but if you want to capture the ScrollMetricNotificationchanges, you can. Special thanks goes out to community contributor xu-baolin who worked hard on this and came up with a great solution.

Another excellent contribution from the community is the addition of Material banner support to the ScaffoldMessenger. You may remember the ScaffoldMessenger from the Flutter 2.0 release announcement as a more robust way to show SnackBars at the bottom of the screen to provide users with notifications. In Flutter 2.5, you can now add a banner to the top of your scaffold that stays in place until the user dismisses it.

Your app can get this behavior by calling the showMaterialBanner method of ScaffoldMessenger:

The Material guidelines for banners state that your app should show only one at a time, so if your app calls showMaterialBanner more than once, the ScaffoldMessenger will maintain a queue, showing each new banner as the previous one is dismissed. Thanks to Calamity210 for this great addition to the Material support in Flutter!

Building further on Flutter 2.0 and its new text editing features, like text selection pivot points and being able to stop propagation of a keyboard event once it’s been handled, in this release, we’ve added the ability to make text editing keyboard shortcuts overridable (#85381). If you want Ctrl-A to do something custom instead of selecting all text, you can do that. The DefaultTextEditingShortcuts class contains a list of every keyboard shortcut supported by Flutter on each platform. If you want to override anything, use Flutter’s existing Shortcuts widget to remap any shortcut to an existing or custom intent. You can place that widget anywhere in your widget tree where you want the override to apply. Check out some examples in the API reference.

Plugins: camera, image picker & plus plugins

Another plugin that’s seen a lot of improvements is the camera plugin:

  • 3795 [camera] android-rework part 1: Base classes to support Android Camera features
  • 3796 [camera] android-rework part 2: Android auto focus feature
  • 3797 [camera] android-rework part 3: Android exposure related features
  • 3798 [camera] android-rework part 4: Android flash and zoom features
  • 3799 [camera] android-rework part 5: Android FPS range, resolution and sensor orientation features
  • 4039 [camera] android-rework part 6: Android exposure- and focus point features
  • 4052 [camera] android-rework part 7: Android noise reduction feature
  • 4054 [camera] android-rework part 8: Supporting modules for final implementation
  • 4010 [camera] Do not trigger flat device orientation on iOS
  • 4158 [camera] Fix coordinate rotation for setting focus- and exposure points on iOS
  • 4197 [camera] Fix camera preview not always rebuilding on orientation change
  • 3992 [camera] Prevent crash when setting unsupported FocusMode
  • 4151 [camera] Introduce camera_web package

There’s also been a lot of work on the image_picker plugin focusing on the end-to-end camera experience:

  • 3898 [image_picker] Image picker fix camera device
  • 3956 [image_picker] Change storage location for camera captures to internal cache on Android, to comply with new Google Play storage requirements
  • 4001 [image_picker] Removed redundant request for camera permission
  • 4019 [image_picker] Fix rotation when camera is a source

This work improves the functionality and robustness of the camera and image_picker plugins for Android. In addition, you’ll notice an early version of the camera plugin is available with web support (#4151). This preview provides basic support for viewing camera preview, taking a picture, using flash and zoom controls, all on the web. It is currently not an endorsed plugin, so you will need to add it explicitly to be used in your web app.

The initial Android camera rewrite work was contributed by acoutts. The camera and image_picker work was landed by Baseflow, a consulting firm specializing in Flutter and well-known for their own packages on pub.dev. The camera_web work was largely done by Very Good Ventures, a US-based Flutter consulting firm. Many thanks to all of you for your contributions to the Flutter community!

Another valuable community contribution is by the Flutter Community organization, known for the “plus” plugins. With this release of Flutter, each of the corresponding plugins from the Flutter team now carry a recommendation just like this one for battery:

Furthermore, since these plugins are no longer actively maintained, they are no longer marked as Flutter Favorite plugins. If you haven’t already done so, we recommend moving to the plus versions of the following plugins:

Flutter DevTools: performance, Widget inspector, & polish

This release of Flutter comes with a number of improvements to Flutter DevTools. First and foremost is the added support in DevTools to take advantage of engine updates (#26205, #26233, #26237, #26970, #27074, #26617). One set of these updates enables Flutter to do a better job of associating trace events with specific frames, which helps developers to determine why a frame might be going over budget. You can see this reflected in the DevTools Frames chart that has been rebuilt to be “live”; frames are populated in this chart as they are rendered in your app. Selecting a frame from this chart navigates to the timeline events for that frame:

The Flutter engine now also identifies shader compilation events in the timeline. Flutter DevTools uses these events to help you diagnose shader compilation jank in your app.

DevTools detecting lost frames due to shader compilation

With this new feature, DevTools detects when you’ve lost frames to shader compilation so that you can fix the issue. To run your app as if it’s the first time (before your shader cache has been populated as it would be for any user), use flutter runwith the --purge-persistent-cache flag. This clears the cache to ensure you are reproducing the environment that users see for the “first run” or “re-open” (iOS) experience. This feature is still under development, so please file issues for problems you find, or for any improvements we can make to help debug shader compilation jank.

In addition, when you’re tracking down CPU performance issues in your app, you may have been swamped in profiling data from Dart and Flutter libraries and/or the native code of the engine. If you’d like to turn any of these off to focus on your own code, you can do that with the new CPU Profiler feature (#3236) that enables you to hide profiler information from any of these sources.

For any of the categories you don’t filter out, they’ve now been color-coded (#3310, #3324) so that you can easily see what parts of the CPU Frame Chart come from what parts of the system.

Colored frame chart to identify app vs. native vs. Dart vs. Flutter code activities in your app

Performance isn’t the only thing that you’ll want to debug. This release of DevTools comes with an update to the Widget Inspector that allows you to hover over a widget to evaluate the object, view properties, widget state, and so on.

And, when you select a widget, it automatically populates in the new Widget Inspector Console, where you can explore the widget’s properties.

When paused at a breakpoint, you can also evaluate expressions from the console.

In addition to the new features, the Widget Inspector has undergone a facelift. To make DevTools a more useful destination for understanding and debugging your Flutter apps, we partnered with Codemate, a creative tech agency in Finland, to make some updates.

Flutter DevTools polished UX for greater ease of use

In this screenshot, you can see the following changes:

  • Better communicating what the debug toggle buttons do — those buttons have new icons, task-oriented labels, as well as rich tooltips that describe what they do and when to use them. Each tooltip further links out to detailed documentation of the feature.
  • Easier to scan and locate widgets of interest — frequently used widgets from the Flutter framework now show icons in the widget tree view on the left hand side of the inspector. They’re further color coded based on their categories. For example, layout widgets are displayed in blue while content widgets are displayed in green. Furthermore, each Text widget now shows a preview of its content.
  • Aligning the color scheme of the layout explorer and the widget tree — it’s now easier to identify the same widget from the layout explorer and the widget tree. For example, the “Column” widget in the screenshot below is on a blue background in the layout explorer, and it has a blue icon in the widget tree view.

We’d love to hear your thoughts about any issues that stem from these updates or any other improvements we can make to ensure that DevTools works great. And these highlights are just the start. For a full list of what’s new in DevTools with this release of Flutter, check out the release notes:

IntelliJ/Android Studio: integration tests, test coverage, and icon previews

The IntelliJ/Android Studio plugin for Flutter has also undergone a number of improvements with this release, starting with the ability to run integration tests (#5459). Integration tests are whole-app tests that run on a device, live in the integration_test directory and use the same testWidgets() functionality from widget unit tests.

Integration testing your Flutter app in IntelliJ/Android Studio

To add an integration test to your project, follow the instructions on flutter.dev. To connect the test with IntelliJ or Android Studio, add a run configuration that launches the integration tests and connect a device for the test to use. Running the configuration allows you to run the test, including setting breakpoints, stepping, etc.

In addition, the latest IJ/AS plugin for Flutter allows you to see the coverage information for both unit test and integration test runs. You can access this from the toolbar button next to the “Debug” button:

Coverage info is displayed using red and green bars in the gutter of the editor. In this example, lines 9–13 were tested, but lines 3 and 4 were not.

The latest release also includes the new ability to preview icons used from packages from pub.dev built around TrueType font files (#5504, #5595, #5677, #5704), just as the Material and Cupertino icons support previewing.

Icon preview in IntelliJ/Android Studio

To enable icon previews you need to tell the plugin which packages you are using. There is a new text field in the plugin settings/preferences page:

Note that this works for icons defined as static constants in a class, as shown in the sample code in the screen shot. It won’t work for expressions, such asLineIcons.addressBook() or LineIcons.values['code']. If you are the author of an icon package that does NOT work with this feature, please create an issue.

That are lots more updates for the IntelliJ/Android Studio plugin for Flutter that you can read about in the release notes:

Visual Studio Code: dependencies, Fix All, and Test Runner

The Visual Studio Code plugin for Flutter has also improved in this release, beginning with two new commands “Dart: Add Dependency” and “Dart: Add Dev Dependency” (#3306, #3474).

Adding a Dart dependency in Visual Studio Code

These commands provide functionality like the Pubspec Assist plugin by Jeroen Meijer has been providing for awhile now. These new commands come right out of the box and provide a type-to-filter list of packages periodically fetched from pub.dev.

You may also be interested in the “Fix All” command (#3445, #3469) that’s available for Dart files and can fix all of the same issues as dart fix for the current open file in one step.

Using Flutter Fix rules to fix all known issues in your code

This can also be set to run on-save by adding source.fixAll to the editor.codeActionsOnSave VS Code setting.

Or, if you’d like to give the preview feature a try, you can enable the dart.previewVsCodeTestRunner setting and see Dart and Flutter tests run via the new Visual Studio Code test runner.

Using the new Visual Studio Code test runner test your Dart and Flutter code

The Visual Studio Code test runner looks a little different than the current Dart and Flutter test runner and will persist results across sessions. The Visual Studio Code test runner also adds new gutter icons showing the last state of a test that can be clicked to run the test (or right-clicked for a context menu).

In coming releases, the existing Dart and Flutter test runner will be removed in favor of the new Visual Studio Code test runner.

And this is just the tip of the iceberg with new Visual Studio Code features and fixes. For all of the details, check out the release notes:

  • v3.26 VS Code Test Runner integration, Flutter Create Settings, …
  • v3.25 Additional Dependency Management improvements, Fix All in File / On-Save, …
  • v3.24 Dependencies tree improvements, Easier launch configurations, Editor improvements
  • v3.23 Profile Mode improvements, Improved dependencies tree, LSP improvements

Tools: exceptions, new app template & Pigeon 1.0

In previous versions of Flutter, you may have been frustrated by exceptions that you expected to be unhandled so that you could trigger the debugger and figure out where they originated only to find that the Flutter framework did not let the exception through to trigger the “unhandled expectation” handler in your debugger. In this release, debuggers now break correctly on unhandled exceptions that previously were just caught by the framework (#17007). This improves the debugging experience as your debugger can now point you directly to the throwing line in their code instead of pointing to a random line deep in the framework. A related new feature enables you to decide if a FutureBuilder should rethrow or swallow errors (#84308). This should give you a large number of additional exceptions to help track down the issues in your Flutter apps.

Since the dawn of Flutter, there has been the Counter app template, which has many good qualities: it shows off many features of the Dart language, demonstrates several key Flutter concepts and it’s small enough to fit into a single file, even with a lot of explanatory comments. However, what it doesn’t do is provide a particularly good jumping off point for a real-world Flutter app. In this release, there’s a new template (#83530) available via the following command:

$ flutter create -t skeleton my_app

The new Flutter skeleton template in action

The skeleton template generates a two-page List View Flutter app (with Detail View) that follows community best practices. It was developed with a great deal of internal and external review to provide a better base on which to build a production quality app and supports the following features:

  • Uses ChangeNotifier to coordinate multiple widgets
  • Generates localizations by default using arb files
  • Includes an example image and establishes 1x, 2x, and 3x folders for image assets
  • Uses a “feature-first” folder organization
  • Supports shared preferences
  • Supports light and dark theming
  • Supports navigation between multiple pages

Over time, as Flutter best practices evolve, expect this new template to evolve with them.

If, on the other end of the spectrum, you’re developing a plugin and not an app, you may be interested in the 1.0 release of Pigeon. Pigeon is a codegen tool for generating typesafe interop code between Flutter and its host platform. It allows you to define a description of your plugin’s API and generate skeleton code for Dart, Java, and Objective-C (which are accessible to Kotlin and Swift, respectively).

Sample generated Pigeon code

Pigeon is already used in some of the plugins from the Flutter team. With this release, which provides more helpful error messages, added support for generics, primitive data types as arguments and return types, and multiple arguments, expect it to be used more heavily in the future. If you’d like to take advantage of Pigeon in your own plugin or add-to-app projects, you can find out more information at the pigeon plugin page.

Breaking changes & deprecations

The following are the breaking changes in the Flutter 2.5 release:

For the full list of breaking changes since the 1.17 release, see flutter.dev.

As we continue to update Flutter Fix (available in your IDE and via the dart fix command), we have a grand total of 157 rules to automatically migrate your code affected by these or past breaking changes, as well as any deprecations. As always, many thanks to the community for contributing tests, they help us identify these breaking changes. To learn more, check out our breaking change policy.

Also, with the Flutter 2.5 release, we are deprecating support for iOS 8 as announced in Sept, 2020. Dropping support for iOS 8, which has less than 1% market share, allows the Flutter team to focus on new platforms in wider usage. Deprecation means that these platforms may work but that we will not test new versions of Flutter or the plugins on these platforms. You can see the list of currently supported Flutter platforms on flutter.dev.

Summary

In closing, thank you as always to the Flutter community around the world that makes all of this possible. To the hundreds of developers who have contributed and reviewed the 1000s of PRs in this update, here’s to the fruits of each of your efforts. Together, we’re working to transform the app development process for developers around the world so you can ship more, faster, deploying to the platforms you care about from a single codebase.

Stay tuned for more updates from all of us on the Flutter team at Google. The year is not over yet!

--

--

Chris Sells
Flutter

Chris Sells is a Google Product Manager on the Flutter development experience. He enjoys long walks on the beach and various technologies.