What’s new in Flutter 3.7

Material 3 updates, iOS improvements, and much more!

Kevin Chisholm
Flutter

--

We are excited to start 2023 with the release of Flutter 3.7! In Flutter 3.7, we as a community, continue to improve the framework with the addition of some great new features such as: the ability to create custom menu bars, cascading menus, tools to better support internationalization, new debugging tools, and much more.

We also continue to refine features such as global selection, faster rendering with Impeller, DevTools, and as always, performance!

Let’s go on a quick journey together to explore the new features in Flutter 3.7!

Enhanced Material 3 support

Material 3 support has been greatly enhanced in 3.7 with the migration of the following widgets:

To use these new features just turn on the useMaterial3 flag in your application’s ThemeData widget. To take full advantage of M3 support you will want a complete M3 color scheme. You can provide your own, use the new theme builder tool, or Flutter can generate one for you from a single seed color using the colorSchemeSeed parameter of the ThemeData constructor:

MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.green,
),
// …
);

For the latest details of Flutter’s Material 3 support, see the umbrella issue on GitHub.

To play with these components yourself, check out the interactive demo showing off all the new M3 features:

Menu bars and cascading menus

Flutter can now create menu bars and cascading context menus.

For macOS, create a menu bar using the PlatformMenuBar widget, which defines platform native menu bars rendered by macOS instead of Flutter.

And, for all platforms, you can define a Material Design menu that provides cascading menu bars (MenuBar), or standalone cascading menus triggered by another user interface element (MenuAnchor). These menus are fully customizable, and the menu items can be custom widgets, or you can use the new menu item widgets (MenuItemButton, SubmenuButton).

Impeller preview

The team is pleased to announce that the new Impeller rendering engine is ready for preview on iOS on the stable channel. We believe the performance of Impeller will meet or exceed the Skia renderer for most apps, and as for fidelity, Impeller implements all but a small number of rarely used corner cases. We expect to make Impeller the default renderer on iOS in a forthcoming stable release, so please continue to file Impeller feedback on GitHub.

While we are increasingly confident that Impeller on iOS will meet the rendering needs of nearly all existing Flutter apps, there are still a few gaps in API coverage. The small number of remaining gaps are listed on the Flutter wiki. Users might also notice minor visual differences in rendering between Skia and Impeller. These minor differences might be bugs, so please don’t hesitate to file issues.

Our progress on Impeller was greatly accelerated by contributions from the community. In particular, GitHub users ColdPaleLight, guoguo338, JsouLiang, and magicianA contributed 37 out of 291 (>12%) Impeller-related patches to this release. Thank you!

We continue to make progress on a Vulkan backend for Impeller (with fallback to OpenGL on older devices), but Impeller on Android isn’t yet ready for preview. Android support is under active development, and we hope to share more about it — with more news about support for desktop and web — in future releases.

Follow along with our progress in the Impeller project board on GitHub.

iOS release validation

When you release an iOS app, a checklist of settings to update ensures that your app is ready for submission to the App Store.

The flutter build ipa command now validates some of these settings, and informs you if there are changes that should be made to your app before release.

DevTools updates

In this release, there are several new tooling features and overall improvements to try out. The DevTools Memory debugging tool has undergone a complete overhaul. There are three new feature tabs, Profile, Trace, and Diff, that support all the previously supported memory debugging features and added more for your debugging ease. New features include the ability to analyze the current memory allocation for your app by class and memory type, investigate what code paths are allocating memory for a set of classes at runtime, and diff memory snapshots to understand memory management between two points in time.

All of these new memory features have been documented on docs.flutter.dev, so check out the documentation for more details.

The Performance page also has a couple notable new features. A new Frame Analysis tab at the top of the Performance page provides insights for the selected Flutter frame. Insights might include suggestions on how to trace expensive parts of the Flutter frame in more detail, or warnings about expensive operations detected in the Flutter frame.

These are just a couple highlights, but this release contains several bug fixes and improvements beyond the features mentioned here, including some important bug fixes for the Inspector, the Network profiler, and the CPU profiler. For a more in-depth list of updates, check out the release notes for the DevTools changes that made it into Flutter 3.7.

Custom context menus

You can now create custom context menus anywhere in a Flutter app. You can also use them to customize built-in context menus.

For example, you could add a “Send email” button to the default text selection toolbar that shows up when the user has selected an email address (code). See the contextMenuBuilder parameter, which has been added to existing widgets that show a context menu by default, like TextField. You can return any widget you want from contextMenuBuilder, including modifying the default platform-adaptive context menu.

This new feature works outside of text selection, too. You could, for example, create an Image widget that shows a Save button when right clicked or long pressed (code). Use ContextMenuController to display the current platform’s default context menu, or a custom one, anywhere in your app.

See a full suite of examples in Flutter’s samples repository.

CupertinoListSection and CupertinoListTile widgets

Thanks to the efforts of the Github user Campovski, Cupertino has two new widgets, CupertinoListSection and CupertinoListTile, for showing a scrollable list of widgets in the iOS style. They are the Cupertino versions of ListView and ListTile in Material.

Scrolling improvements

Several scrolling updates have arrived with this release: polish and refinement for trackpad interactions, new widgets like Scrollbars and DraggableScrollableSheet, and improved handling for text selection within scrolling contexts.

Notably, MacOS apps will now experience higher fidelity with the addition of new scrolling physics to match the desktop platform.

New AnimatedGrid and SliverAnimatedGrid widgets animate items added to (or removed from) a list.

Lastly, we fixed a regression in the builder constructor of several scrolling widgets, like ListView. During the NNBD migration of the Flutter framework, the itemBuilder, which allows users to provide widgets on demand, was migrated to an IndexedWidgetBuilder. This meant that the itemBuilder could no longer return null, which (in the past) could be used to indicate that the end of the list had been reached. This functionality was restored with NullableIndexedWidgetBuilder. Thanks to @rrousselGit for noticing this — years after the migration — and sending a fix!

Internationalization tools and docs

Internationalization support has been completely revamped! We’ve completely rewritten the gen-l10n tool to support:

  • Descriptive syntax errors.
  • Complex messages involving nested/multiple plurals, selects, and placeholders.

For more information, see the updated Internationalizing Flutter apps page.

Global selection improvements

SelectionArea now supports keyboard selections. You can extend an existing selection with keyboard shortcuts such as shift+right.

Video example of the new global selection improvements

Background isolates

Now Platform Channels can be invoked from any Isolate. Previously, users were only able to invoke Platform Channels from Flutter’s supplied main isolate. This makes working with isolates and host platform code in Plugins or Add-to-app better. For more information, check out Writing custom platform-specific code on flutter.dev, and the in-depth article, Introducing background isolate channels, a free article on Medium.

Text magnifier

The magnifying glass that appears during text selection on Android and iOS now works in Flutter. This is enabled out of the box for all apps with text selection, but if you want to disable or customize it, see the magnifierConfiguration property.

Swift migration for plugins

With Apple focusing on Swift for their own APIs, we wanted to develop references to help Flutter plugin developers migrate or create new plugins with Swift. The quick_actions plugin has been migrated from Objective-C to Swift, and can be used as a demonstration of best practices. If you are interested in helping us migrate 1P plugins, see the Swift migration section of the wiki.

Resources for iOS developers

We have published several new resources for iOS developers, including:

Bitcode deprecation

Starting with Xcode 14, bitcode is no longer required for watchOS and tvOS applications, and the App Store no longer accepts bitcode submissions from Xcode 14. As such, bitcode support has been removed from Flutter.

By default, Flutter apps don’t have bitcode enabled, and we don’t expect this to impact many developers. However, if you have enabled bitcode manually in your Xcode project, disable it as soon as you upgrade to Xcode 14. You can do so by opening ios/Runner.xcworkspace and set Enable Bitcode to No. Add-to-app developers should disable it in the host Xcode project.

To learn more about bitcode distribution, Check out Apple’s documentation.

iOS PlatformView BackdropFilter

We’ve added the ability for native iOS views to be blurred when rendered underneath a blurred Flutter widget, and UiKitView widgets can now be wrapped inside a BackdropFilter.

For more information, see the iOS PlatformView BackdropFilter design doc.

Memory management

This release introduces a few improvements to memory management that have the collective effect of reducing jank caused by garbage collection pauses, reducing CPU utilization due to allocation velocity and background GC threads, and reducing the memory footprint.

As one example, we have expanded the existing practice of manually deallocating native resources that back certain dart:ui Dart objects. Previously, the native resources would be held by the Flutter engine until the Dart VM garbage collected the Dart objects. Through the analysis of user applications and our own benchmarks, we determined that this strategy in general doesn’t do enough to avoid ill-timed GCs and overuses memory. Therefore, in this release, the Flutter engine adds API for explicitly deallocating the native resources held by Vertices, Paragraph, and ImageShader objects.

In our benchmarks of the Flutter framework migrated to this API, these improvements reduced 90%-ile frame build times up to more than 30%, which end-users will experience as smoother animations with less jank.

Additionally, the Flutter engine no longer registers the size of GPU images with the Dart VM. As above, these images were already manually deallocated by the framework when no longer needed, so informing Dart’s GC policies of the size of the GPU memory backing the Dart heap objects needlessly increased Dart heap memory pressure, triggering ill-timed GCs that could not have collected any additional memory. Along similar lines, it’s now the policy of the Flutter engine to report to the Dart VM only the shallow size of the native objects that back dart:ui Dart objects.

In our benchmarks, this change eliminates synchronous GC work while building frames when a widget creates GPU resident images.

In this release, the Flutter Engine also does a better job of dynamically updating the Dart VM with information about Flutter application state. In particular, Flutter now uses the Dart VM’s RAIL style API to enter a low-latency mode during route transition animations. During this low-latency mode, the Dart VM’s memory allocator prefers heap growth over garbage collection to avoid interrupting transition animations with GC pauses. While this change didn’t entail any dramatic performance improvement, we plan to expand usage of this model in future releases to further eliminate ill-timed GC pauses. Additionally, we have fixed errors in the logic that decides when to notify the Dart VM that the Flutter engine is idle. Fixing these errors also prevents GC-related jank. Finally, for add-to-app Flutter applications, the Flutter engine now informs the Dart VM when the Flutter view is no longer displayed. This now causes the Dart VM to trigger a final major GC for the Isolate associated with the view. This change reduces Flutter’s memory footprint when no Flutter views are visible.

Sunsetting macOS 10.11 through 10.13

As previously announced, Flutter no longer supports macOS versions 10.11 and 10.12. Since that announcement, further analysis revealed that removing support for 10.13 as well would have limited additional impact, and would help the team to greatly simplify the codebase. This means that apps built against stable Flutter SDKs with this release and onward will no longer work on these versions, and the minimum macOS version supported by Flutter increases to 10.14 Mojave.

As a consequence, since all versions of iOS and macOS supported by Flutter include Metal support, the OpenGL backend has been removed from both the iOS and macOS embedders. Removing these backends reduced the compressed size of the Flutter engine by about 100KB.

toImageSync

This release adds the methods Picture.toImageSync and Scene.toImageSync to dart:ui, analogous to the asynchronous methods Picture.toImage, and Scene.toImage.Picture.toImageSync synchronously returns a handle to an Image from a Picture, with the rasterization for the Image taking place asynchronously in the background. The image is then kept as GPU resident when a GPU context is available, meaning that it is faster to draw compared to images produced by toImage. (Images produced by toImage could also be kept GPU resident, but this optimization has not yet been implemented in that scenario.)

The new toImageSync APIs support use-cases, such as:

  • Quickly snapping off an expensive-to-rasterize picture for reuse across multiple frames.
  • Applying multi-pass filters to a picture.
  • Applying custom shaders.

As one example, the Flutter framework now uses this API to improve the performance of page transitions on Android, which nearly halves frame rasterization times, reduces jank, and allows the animation to hit 90/120fps on devices that support those refresh rates.

Custom shader support improvements

This release includes numerous improvements to Flutter’s support for custom fragment shaders. The Flutter SDK now includes a shader compiler that compiles GLSL shaders listed in the pubspec.yaml file to the correct backend-specific format for the target platform. Additionally, custom shaders can now be hot reloaded for a convenient development cycle. Custom shaders are also now supported by both the Skia and Impeller backends on iOS.

We are very impressed by the demos that the community has already shared, and are excited to see further innovative use of custom shaders in Flutter:

https://twitter.com/reNotANumber/status/1599717360096620544

https://twitter.com/reNotANumber/status/1599810391625719810

https://twitter.com/wolfenrain/status/1600242975937687553

https://twitter.com/iamjideguru/status/1598308434608283650

https://twitter.com/rxlabz/status/1609975128758026247

https://twitter.com/RealDevOwl/status/1528357506795421698

https://twitter.com/TakRutvik/status/1601380047599808513

https://twitter.com/wolfenrain/status/1600601043477401606

See detailed documentation for writing and using custom fragment shaders on docs.flutter.dev, and a helpful package of utilities, flutter_shaders on pub.dev.

Font asset hot reload

Previously, adding new fonts to the pubspec.yaml file required rebuilding the application to see them, unlike other asset types that could be hot reloaded. Now changes to the font manifest, including additions of new fonts, can be hot reloaded into an application.

Reduce animation jank on iOS devices

Thanks to open source contributions from luckysmg, two improvements have reduced animation jank on iOS. In particular, the addition of a dummy CADisplayLink on the main thread during gestures now forces refreshes at the max refresh rate. Also, keyboard animations now set the refresh rate of the CADisplayLink to the same refresh rate used by Flutter engine’s animator. Thanks to these changes, users should notice more consistently smooth animations on 120Hz iOS devices.

Summary

It is an understatement to say that Flutter would not be the amazing experience that it is today without its community of talented and passionate contributors. As we continue this journey together, the Flutter team at Google wants you all to know that we could not do this without you. Thank you!

The momentum isn’t slowing down, stay tuned for future updates!

--

--

Kevin Chisholm
Flutter

Kevin Chisholm is a Technical Program Manager for Dart and Flutter at Google.