Performance improvements, new Firebase features, desktop status, tooling updates and more!
It’s that time of year in the northern hemisphere: the leaves are turning, the temperature is cooling and the final stable release of the year is here. Hello and welcome to Flutter 2.8! This release represents the hard work of 207 contributors and 178 reviewers, producing 2,424 PRs merged and 2976 issues closed. Special thanks to the top community contributor of this release, Bartosz Selwesiuk, a Flutter Engineer at Very Good Ventures, who provided 23 PRs, most of which were primarily “focused” (sic) around the camera plugin for web.
All of this collective work produced significant performance improvements in both the engine and in Flutter DevTools, a stable release of the Google Mobile Ads SDK for Flutter, a slew of new Firebase features and improvements, WebView 3.0, a new batch of Flutter Favorite packages, a raft of updates to desktop on our way to a stable release, and a new version of DartPad with support for more packages, including Firebase itself. This might be the last release of the year but it’s by no means the least. Let’s get to it!
As always, job #1 with Flutter is quality. We spend much of our time ensuring that Flutter runs as smoothly and as robustly as it can across the range of supported devices.
This release includes improvements to application startup latency. Testing these improvements against Google Pay, a large, popular app with more than 1 million lines of code to ensure that these changes result in perceivable impact in the real-world. All together these improvements have resulted in reduction in startup latency for Google Pay of 50% when running on a low-end Android device, and a 10% improvement on high-end devices.
Improvements to the way that Flutter influences Dart VM garbage collection policy now helps avoid ill-timed GC cycles during the application startup sequence. For example, before the first frame is rendered on Android, Flutter now only notifies the Dart VM of memory pressure for TRIM_LEVEL_RUNNING_CRITICAL and above signals. In local testing, this change reduced the time to first frame by up to 300ms on a low-end device.
Due to an abundance of caution, in previous releases, Flutter blocked the platform thread while creating platform views. Careful reasoning and testing determined that some of the serialization could be removed, which removed >100ms of blockage during startup of Google Pay on a low-end device.
Previously, setting up the default font manager introduced an artificial delay when setting up the first Dart isolate. Delaying the default font manager setup to run concurrently with Dart Isolate setup both improved startup latency, and made the effects of the above optimizations much more visible, as this was the primary bottleneck.
Flutter developers targeting memory constrained devices were having problems taking performance traces due to Flutter eagerly loading the Dart VM’s “service isolate”, whose AOT code was bundled with the app such that Flutter was reading both into memory simultaneously. For Android in the 2.8 release, the Dart VM’s service isolate was split into its own bundle that can be loaded separately, which results in a memory savings of up to 40 MB until the service isolate is needed. The memory footprint has been further reduced by up to 10% by the Dart VM informing the OS that the pages in memory used by the AOT program are backed by a file that likely won’t need to be read again. Therefore, the pages that had been holding a copy of the file-backed data can then be reclaimed and put to other uses.
Sometimes developers want to view performance trace data from Flutter alongside Android native tracing events. Furthermore, they’d often like to see trace events even in release mode builds to get a better understanding of performance issues in their deployed applications. To that end, the 2.8 stable release now sends tracing events to the Android systrace recorder if it is enabled at application startup, and these events are sent even when the Flutter application is built in release mode.
Flutter tracing events are now shown (bottom) in the Android systrace recording tooling
Additionally, to help create animations with less jank, some of you wanted more information in performance traces about the behavior of the raster cache, which allows Flutter to blit expensive, reused pictures instead of re-drawing them on each frame. New flow events in performance traces now allow you to track the lifetimes of raster cached pictures.
For debugging performance issues, this release of DevTools adds a new “Enhance Tracing” feature to help you diagnose UI jank stemming from expensive build, layout, and paint operations.
When any of these tracing features are enabled, the Timeline includes new events for widgets built, render objects laid out, and render objects painted, as appropriate.
In addition, this release of DevTools adds new support for profiling the performance of your app’s startup. This profile contains CPU samples from the initialization of the Dart VM up until the first Flutter frame has been rendered. After you press the “Profile app start up” button and the app startup profile has been loaded, you will see that the “AppStartUp” user tag is selected for the profile. You can also load the app startup profile by selecting this user tag filter, when present, in the list of available user tags. Selecting this tag shows your profile data for your app’s startup.
Web platform views
Android and iOS aren’t the only platforms getting performance improvements. This release also improves the performance of platform views for Flutter web. If you’re unfamiliar with platform views, they’re the way that Flutter allows you to host native UI components from the underlying platform in your app. Flutter web implements this with the HtmlElementView widget, which allows you to host HTML elements inside your Flutter web app. If you’re using the web versions of the google_maps_flutter plugin or the video_player plugin, or you’re following the Flutter team’s advice about how to optimize the display images on the web, then you’re using platform views.
In previous versions of Flutter, embedding a platform view immediately created a new canvas and each extra platform view added another canvas. The extra canvases are expensive to create, as each is the size of the entire window. This release reuses canvases created for earlier platform views so, rather than incurring the cost 60x per second, you incur the cost once in the entire lifetime of the app. This means that you can have multiple HtmlElementView instances in your web apps without degrading performance, while also reducing scrolling jank when platform views are used.
Flutter isn’t just the framework, the engine, and the tools — there are more than 20,000 Flutter-compatible packages and plugins on pub.dev with more added every day. A significant amount of what Flutter developers interact with day-to-day is part of the larger ecosystem, so let’s take a look at what’s been going on in the Flutter ecosystem since the previous release.
GA of Flutter Ads
First and foremost is the release of the Google Mobile SDK for Flutter into general availability in November.
This release supports 5 ad formats, integrates both AdMob and Ad Manager support and includes a beta of a new mediation feature to help you optimize ad performance. For more information about integrating Google Ads into your Flutter app as well as other monetization options, check out the new monetization page on flutter.dev.
Another new release that comes with Flutter this time around is the 3.0 release of the webview_flutter plugin. We’ve bumped the version number because of the number of new features but also because of a potentially breaking change in the way web views work on Android. In previous versions of webview_flutter, the hybrid composition mode has been available but not the default. Hybrid composition fixes a number of issues that the previous default virtual displays mode has. Based on user feedback and issue tracking, we think it’s time for hybrid composition to become the default. In addition, webview_flutter also adds a number of highly requested features:
Support for POST as well as GET for populating content (4450, 4479, 4480, 4573)
Loading HTML from files and strings (4446, 4486, 4544, 4558)
Transparent background support (3431, 4569, 4570)
Writing cookies prior to loading content (4555, 4556, 4557)
Furthermore, in the 3.0 release, webview_flutter provides preliminary support for a new platform: the web. We’ve had many of you ask for the ability to host a webview in a Flutter web app, which allows you to build an app for mobile or web from a single code base. What does hosting a webview look like in a Flutter web app? Well, from a coding perspective, it looks just the same:
When running on the web, it works as you’d expect:
Note that the current implementation of webview_flutter for web has a number of limitations based around the fact that it’s built using an iframe, which only supports simple URL loading and has no ability to control or interact with the loaded content (for more info, check out the webview_flutter_web README). However, we’re making webview_flutter_web available due to popular demand as an unendorsed plugin. If you want to give it a try, add the following line to your pubspec.yaml:
If you have feedback on webview_flutter v3.0, either on the web or off, please log them on the Flutter repo as a webview issue. Also, if you haven’t used webview before or you’d like a refresher, check out the new webview codelab, which takes you step-by-step through the process of hosting web content in your Flutter app.
The Flutter Ecosystem Committee has met again to designate the following as Flutter Favorite packages:
Three custom router packages for the new Router API: beamer, routemaster, and go_router
drift, a rename of an already capable and popular reactive persistence library for Flutter and Dart, built on top of sqlite
freezed, a Dart “language patch” to provide a simple syntax for defining models, cloning objects, pattern matching, and more
And several great looking GUI packages: flex_color_scheme, flutter_svg, feedback, toggle_switch, and auto_size_text
The Flexfold app is built with flex_color_scheme
Congratulations to those package authors and thank you for supporting the Flutter community with your hard work. If you’re interested in nominating your favorite Flutter package for a Flutter Favorite award, follow the guidelines and instructions on the Flutter Favorite program page.
If you are a package author, one decision you must make is which platforms you’re going to support. If you’re building a plugin with platform-specific native code, you can do that using the pluginClass property in your project’s pubspec.yaml, which indicates the native class that’s providing the functionality:
However, as Dart FFI becomes more mature, it’s possible to implement platform-specific functionality in 100% Dart, like the path_provider_windows package does. When you don’t have any native class to use but you still want to designate your package as supporting only certain platforms, use the dartPluginClass property instead:
This setting in place, you have designates your package as only supporting certain platforms even if you don’t have any native code. You also must provide the Dart plugin class; learn more in the Dart-only platform implementations docs on flutter.dev.
Another big part of the Flutter ecosystem is FlutterFire, which is used by two-thirds of Flutter apps. This release adds a set of new features that make it easier to build applications using Flutter and Firebase:
All FlutterFire plugins are graduating from beta to stable
New support in DartPad for several Firebase services
New libraries to more easily build UI for authentication and live Firestore queries
New Firestore Object/Document Mapping for Flutter, available in Alpha
The FlutterFire plugins have (almost) all moved from beta to stable quality.
Plugins moving to stable for Android, iOS, and web include Analytics, Dynamic Links, In-App Messaging, Performance Monitoring, Realtime Database, Remote Config and, the new kid on the block, Installations. The App Check plugin and macOS platform support are still in beta because of the phase of the Firebase libraries themselves, which are also in beta. If you’ve worried about whether to choose Realtime Database, Analytics, or Remote Config because the FlutterFire libraries weren’t ready for prime-time, worry no more. These are now fully supported plugins ready for production use.
Dart-only Firebase Initialization
As packages have moved to production quality, we’ve added the ability to initialize Firebase on any supported platform from Dart:
This code initializes a Firebase app using the options appropriate for each supported platform as defined in the firebase_options.dart file, which contains per-platform data structures that look like this:
To gather the data for each platform’s initialization option data structure, check out the new flutterfire CLI tool.
This tool digs into the data in your platform-specific sub-folders to find the unique bundle ID and then uses that to look up the Firebase-project specific details for your matching platform-specific apps, even creating a new Firebase project and/or new platform-specific apps if there aren’t any. What this means for you is no more downloading and adding a json file to your Android project, downloading and adding a plist file to your iOS and macOS projects, or pasting code into your web project’s index.html — no matter which supported Firebase platform you’re targeting, this single snippet of Dart code initializes Firebase for your app. Note that this may not be the only initialization you have to do to get your FlutterFire app working; for example, you might want to integrate the creation of your Crashlytics symbols into your Android build or your iOS build, but it should get it up and running in minutes with any new Firebase project.
Use Firebase with DartPad
With this Dart-only initialization of FlutterFire, you can now use Firebase from within DartPad.
This example demonstrates a little chat app using Flutter, Firebase, and DartPad, all of which you can use right now with no installation. Today DartPad’s Firebase support already includes the core APIs, Authentication, and Firestore. Expect more Firebase services to appear in DartPad over time.
The other thing that FlutterFire support in DartPad enables is the ability to use an embedded instance of DartPad right in the docs.
In this example, you’re seeing the docs for Cloud Firestore with the code for the example application that you can run and edit directly in your browser without having to install a thing, create a test project, or even copy/paste the code. It’s all right there for your immediate use.
When integrating Firebase into an app, most apps have some kind of authentication flow. This includes allowing users to log in with email and password, or with a social auth provider like the one that Google provides. Firebase Authentication also allows for creating new accounts on the fly, validating email addresses, resetting passwords, and might even involve 2-step verification with SMS, logging in with a phone number, or even merging multiple user accounts into a single account. Firebase Authentication supports all of this functionality, but as a Flutter developer, you’re responsible for implementing the UI for all of it. Until today.
Today, we’re pleased to announce that the flutterfire_ui package can create a basic authentication experience with a small amount of code. As an example, assume that you’ve got Email and Google authentication setup in your Firebase project:
With this configuration, you can trigger an authentication experience as follows:
This initializes Firebase and, noticing that the user is not already logged in, shows the sign-in screen. The SigninScreen widget is configured with the Email and Google authentication providers. The code also listen to the user’s authentication state using the firebase_auth package, so once the user signs in you can display the rest of the application. With this code, you get a working login for all of the Firebase-supported platforms: Android, iOS, web, and macOS.
With a little more configuration, you can easily add an image and some custom text (details are available in the docs), which gives you a full-featured login experience:
This screenshot shows the mobile version, but because the flutterfire_ui screens are responsive, here’s what you get on a desktop device:
If the user has an email/password already, they can log in and be done. If they use Google auth, they’ll be shown the normal Google auth flow, whether they’re on mobile, web, or desktop. If they don’t have an account already, they can press the button on the login screen and get to the registration screen. Once they’ve logged in or registered, there are flows for validating their email address, resetting their password, logging out, and linking social authentication accounts. Logging in by email works on all platforms along with social auth support for Google, Facebook, and Twitter, with partial support for Apple (it doesn’t work on Android). Authentication support in flutterfire_ui supports a number of scenarios and navigation schemes, along with customization and localization options. Check out the detailed docs and samples in the firebase.flutter.dev docs.
Furthermore, authentication is not the only Firebase UI-related feature that flutterfire_ui supports. For showing users a live, infinite scroll list of data from a Firebase query, this release includes the FirestoreListView, which you can drop into your app with a live query as follows:
And this is what it looks like in action:
Or, if you’d like to provide your users with the ability to create, read, update, and delete entries in a table, you’ve got the beginnings of that in FirestoreDataTable:
Which works like this:
For details about authentication, list views, and data tables, check out the flutterfire_ui docs. As this is a preview release, additional features are planned. If you have a question or a feature request, please head over to the repo on GitHub to log issues or ask questions in the discussion section.
Firestore Object/Document Mapping
And last but not least, one new feature to the integration between Firebase and Flutter that you should be aware of: the alpha release of the Firestore Object/Document Mapper. The Firestore ODM is aimed at helping Flutter developers be more productive by simplifying use of Firestore through familiar type-safe, structured objects and methods. Using code generation, the Firestore ODM improves the syntax for interacting with documents and collections by allowing you to model your data in a type-safe way:
With these types in place, you can now execute type-safe queries:
The ODM also supports defining strongly typed sub-collections and provides built-in options for optimizing widget rebuilds with its select feature. You can read about all of this and more in the Firestore ODM docs. Since this is an alpha release, please provide feedback. To give feedback and ask questions, join the Firestore ODM thread of the FlutterFire discussion.
The Flutter 2.8 release includes another big step along the road to the stable release of Windows, macOS, and Linux. The quality bar is high, including internationalization and localization support like the recently landed Chinese IME support, Korean IME support, and Kanji IME support. Or, like the tight integration being built into Windows accessibility support. It’s not enough for Flutter to run on desktop on the stable channel (which it already does in beta behind a flag), it has to run well for languages and cultures around the world and for people of varying kinds of abilities. It’s not quite where we want to be yet, but it’s getting there!
One example of the ongoing work to prepare desktop for a stable release is the complete re-architecture of how Flutter handles keyboard events to allow for synchronous response. This enables a widget to handle a keystroke and cancel its propagation through the rest of the tree. The initial work landed in Flutter 2.5 and Flutter 2.8 adds fixes for issues and regressions as it approaches stable quality. This is in addition to the ongoing work to re-engineer how we handle device-specific keyboard input and a refactor of the way that Flutter handles text editing, all of which are necessary for keyboard input-intensive desktop apps.
In addition, we continue to expand Flutter’s support for visual density and expose alignment for dialogs, both to enable more desktop-friendly UI.
And finally, the Flutter team is not the only one working on Flutter desktop. As just one example, the desktop team at Canonical is working with Invertase on a Linux and Windows implementation of the most popular Firebase plugins for Flutter.
You can read more about the preview release on the Invertase blog.
A Flutter release is not complete without a look at the tooling improvements. This post focuses on the improvements in DartPad, the biggest of which is the support for a larger number of packages. In fact, 23 packages are available for import. In addition to several Firebase services, the list includes such popular packages as bloc, characters, collection, google_fonts, and flutter_riverpod. The DartPad team continues to add new packages, so if you’d like to see which packages are currently supported, click on the information icon in the lower right hand corner.
To learn the plan for adding new packages to DartPad over time, check out this article on the Dart wiki.
There’s another new DartPad feature that’s pretty handy, too. Previously, DartPad always ran the latest stable version. With this release, you can select the latest beta channel releases as well as the previous stable release (called the “old channel”), by using the new Channel menu in the status bar.
This can be very useful if, for example, you’re writing a blog post where the latest stable isn’t quite new enough…
Removing the dev channel
A Flutter “channel” governs how quickly the underlying Flutter framework and engine changes on your development machine, with stable representing the least churn and master representing the most. Due to resource constraints, we recently stopped updating the dev channel. While we did get some questions about this, we found that fewer than 3% of Flutter developers use the dev channel. We have therefore decided to start the process to formally decommission the dev channel. While few developers use the dev channel, it takes Flutter engineers considerable time and effort to maintain it. If you spend all of your time on the stable channel (as more than 90% of Flutter developers do), you won’t miss it. By dropping it, you have one fewer decision to make, and the Flutter team can spend its time and energy on other things.
You can decide which channel you’d like using the flutter channel command. Here’s how the Flutter team thinks about each channel:
The stable channel represents the highest-quality builds we have. They’re released quarterly (roughly), and are hotfixed for critical issues in between. This is the “slow” channel: safe, mature, long-term servicing.
The beta channel provides a fast-moving alternative to stable for those who are comfortable with a faster cadence. Currently released monthly, stabilized prior to release. This is the “fast” channel. If we find that the dev channel was serving needs that the beta channel cannot currently serve, we may change how we think of the beta channel to address those needs as well (for example, accelerating the release cadence for beta or reducing the level of testing and hot fixing that we perform on beta).
The master channel is our active development channel. We provide no support on this channel, but we run a comprehensive suite of unit tests against it. This is the right channel for contributors or advanced users who are comfortable with unstable builds. On this channel, we run fast and break things (and then fix them pretty fast, too).
As we decommission the dev channel in the coming months, consider the beta or master channels, depending on your tolerance for churn and your need for the latest and greatest.
As always, we strive to reduce the number of breaking changes in each release. In this release, Flutter 2.8 is free of breaking changes aside from deprecated APIs that have expired and been removed according to our breaking change policy.
90292 Remove autovalidate deprecations
90293 Remove FloatingHeaderSnapConfiguration.vsync deprecation
90294 Remove AndroidViewController.id deprecation
90295 Remove BottomNavigationBarItem.title deprecation
90296 Remove deprecated text input formatting classes
If you’re still using these APIs and would like details on how to update your code, you can read the migration guidance on flutter.dev. As always, many thanks to the community for contributing tests that help us identify these breaking changes.
As we close out 2021 and look forward to 2022, the Flutter team would like to express our gratitude for the work and support of the entire Flutter community. While it’s true that we’re building Flutter for the growing number of developers in the world, it’s also literally true that we couldn’t build it without you. The Flutter community is like no other and we’re grateful for all that you do. Have a happy holiday season and we’ll see you in the new year!