FLUTTERING UP

If Flutter is something new to you, then you should know that Flutter is a Google-backed cross-platform software development framework. A Flutter app can be developed, built for, and deployed on multiple platforms from a single codebase.

Currently, the supported platforms are Android, iOS, web, macOS, Linux, and Windows.

Almost a year ago I was taking a look at what Flutter was capable of in terms of cross-platform and why cross-platform might be a good choice. The points I made there are still valid.

Here, we'll go through a short timeline of Flutter, its current state, run a test app on all supported platforms (after a bit of setup), draw some insights and improvement ideas, and take a look at what the future might bring.

The past

Flutter started out targeting mobile platforms.

Codenamed Sky at its first version, it was working "only" on the Android operating system. In 2015, Android had over 60% mobile OS market share.

Already named Flutter, in 2016, it could be used to build apps for iOS too.

Fast forward 2 years later, on the 27th of February 2018, after 1 year since its alpha release, the first beta release of Flutter was announced. By now, the support for iOS was maturing, and its use in production-ready apps was starting to gain traction.

On the 4th of December same year, Flutter 1.0 was released at the Flutter Live event. It was its first stable version. Plans for supporting desktop (Linux, Mac, and Windows) were revealed. Also, upcoming support for the web was demonstrated with a project codenamed Hummingbird.

The following year, on the 11th of December 2019, Flutter 1.12 was released at the Flutter Interactive event. In 1.12 stable, the implementation of Dark Mode was completed, new Cupertino widgets were added, several UX tweaks were made, and the Add-to-App feature was improved. Add-to-App is the ability to integrate Flutter into an existing Android or iOS mobile apps. Web support was upgraded to the beta channel. macOS support entered alpha.

Quite recently, on the 6th of May 2020, version 1.17.0 was released. With this release, the performance on the iOS devices was improved with Metal API (by ~50%). Also, new network tracking and Material widgets were added.

More recently, Linux and Windows desktop support entered alpha.

I've put together a video playlist of key moments in the life of Flutter (feel free to comment if you think I missed any):

The present

"Flutter is Google's UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase."

Flutter has 4 channels: stable, beta, dev, and master. I use mostly the master channel because it provides the latest features, although it's the most unstable. For production-ready apps, depending on what platform you're targeting, you should use the stable, beta, or dev channels.

Flutter channels: stable (Android, iOS), beta (web browsers), dev (macOS, Windows, Linux), and master.
Flutter channels: stable, beta, dev, and master.

The current stable version is 1.22.x, although with the fast development cycle it might not stay the same for long.

For our snapshot of the current state of cross-platform development with Flutter, we'll use the master channel. The current master version is 1.26.0–2 This and the dev channel offer support for 6 platforms: Android, iOS, web, macOS, Linux, and Windows.

Testing time

To build a Flutter application we first have to set up an environment:

1st step is to choose an editor to write your app code in. Some developers might use any plain text editor and the command-line tools for compiling their apps, though the sane option is to choose a human-friendly alternative. There are some options for editors like Visual Studio Code (VS Code), Android Studio, IntelliJ IDEA Community Edition, and others. IntelliJ offers a lot of nice features like auto-saving (you can modify the VS Code editor to do the same) and is one of the best IDE I've used. Although, my editor of choice for Flutter is VS Code, this time I'll use the one from IntelliJ. The Community Edition is free and allows you to build commercial applications. As JetBrains says: "It can also be used for commercial development."

Just as a side note: inside Android Studio, Google uses the IntelliJ platform developed by JetBrains. That's why JetBrains is a co-developer for Android Studio and IntelliJ IDEA works more or less the same.

2nd, you'll want, and need, to install Flutter. You can do this on macOS, Windows, Linux, and Chrome OS.

To see which channel you are on, you can use the command flutter channel in your Terminal tab. Right after installing Flutter, the output should be:

Flutter channels:
  master
  dev
  beta
* stable

By default, you'll be on the stable channel. For switching the channel to master you should use the flutter channel master followed by the flutter upgrade in your Terminal tab. There will be a short download and a summary output with the status.

3rd, and last step, is to install the Flutter + Dart plugins for IntelliJ. You have to install the Android toolchain for building Android apps and Xcode for building iOS and macOS apps. You also could have Google Chrome installed for the web platform.

When running the command flutter doctor, if you are on a macOS, you should see something similar with:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel master, 1.26.0-2.0.pre.313, on Mac OS X 10.15.7 19H114 darwin-x64, locale en-NL)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] IntelliJ IDEA Community Edition (version 2020.3.1)
[✓] Connected device (1 available)

With everything in place, you can test that you can create a new project.

IntelliJ IDEA welcome screen with the New Project option

After selecting New Project, or going to FileNewProject… you'll get:

New Project creation flow with the new Flutter project option among other options.

The Flutter and Dart options for creating new projects will be available after installing the above-mentioned plugins.

New Project creation dialog for a new Flutter project with inputs for name, description, and organization among others.

On the last dialog from the New Project creation flow, you can and should set a name for your project, a description, and an organization name. The organization name is usually the reverse domain notation of your domain. If you don't own a domain you can leave it as is, or fill-in a fictitious domain. This convention helps to avoid namespace collisions.

Now that we have a new project created, let's see what Flutter can cover cross-platform wise in 2021:

Mobile

Flutter can use a single codebase to compile your app for Android and iOS.

By default, when we create a project using any channel of Flutter, we can compile this project for mobile (phones or tablets running Android or iOS).

The command flutter devices, when run in the Terminal, will display available devices (connected to the development machine). For example, on my machine it outputs:

3 connected devices:
AndroidDevice (mobile)
  • 94dcba0c                                 
  • android-arm64  
  • Android 10 (API 29)
iOSDevice (mobile)
  • 00008101-001455EC3620001E 
  • ios            
  • iOS 14.3
Chrome (web)     
  • chrome                                   
  • web-javascript 
  • Google Chrome 87.0.4280.88

This will be the app used to run on all platforms:

If you're not new to Flutter this app may seem familiar. It's the default Flutter counter app with small changes: the debug banner is hidden, the brightness is changed to dark, and all the extra comments are removed.

Also, I've set up 2 new virtual mobile devices: an Android emulator and an iOS simulator:

sdk gphone x86 64 arm64 (mobile) 
  • emulator-5554                        
  • android-x64    
  • Android 11 (API 30) (emulator)
iPhone 12 Pro Max (mobile)         
  • 6455E64D-2111-4452-A5B7-422E1341F5DE 
  • ios            
  • iOS 14.3 com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)

Android

Executing the command flutter run will ask you on which device you want to build your app. This is something specific to IntelliJ IDEA. VS Code doesn't ask and uses the first device in the list. [1]: sdk gphone x86 64 arm64 (emulator-5554) will be the choice for running the app on Android. The result is:

None
Flutter test app running on an Android emulator.

To create a release build we run the command flutter build apk. The result is located in build/app/outputs/flutter-apk/. The file named app-release.apk is around 16Mb in size.

iOS

Executing the flutter run -d 6455E64D-2111-4452-A5B7-422E1341F5DE will build the app on the iOS simulator. That long string is the device identifier. The result is:

None
Flutter test app running on an iOS simulator.

To run on iOS you'll need a machine running macOS. As you can see, there's no need for an actual iOS device.

To create a release build we run the command flutter build ipa. The result is located in build/ios/archive/. The file named Runner.xcarchive is around 220Mb in size. This needs to go through Xcode and after some steps explained here you get a slimmed-down *.ipa file that is under 6Mb.

Web

The web platform is supported on all channels except the stable channel.

To run on the web-javascript platform, we either use flutter run -d chrome or flutter run -d web-server.

The first option runs the app in the Chrome browser and the second one runs it in a web server.

The difference between the options is that the first one launches the app in Chrome and the other option just provides an address that you can navigate to with your preferred browser. Also, the Chrome option allows for advanced debugging and profiling.

The sample app running in Safari, Chrome, Firefox, Brave, Opera, Safari, and Microsoft Edge browsers on macOS:

When running and building apps for the web, you can choose between two different renderers:

  • HTML — which uses a combination of HTML elements, CSS, Canvas elements, and SVG elements
  • CanvasKit — which uses Skia compiled to WebAssembly and rendered using WebGL

The command-line option --web-renderer takes 3 possible values: auto (the default), html, or canvaskit. The auto value chooses the HTML renderer in mobile browsers and the CanvasKit renderer in desktop browsers. The html or canvaskit values always choose the namesake renderer.

The HTML renderer should have the smallest footprint regarding the size. The CanvasKit should add some extra weight to the final file that needs to be downloaded by the users (+ ~2Mb — according to the Flutter team). Surprisingly, for this test app, the result file was smaller by ~100Kb for the CavasKit build, compared to the HTML one (3.2Mb vs 3.3Mb). The advantage of using the CanvasKit renderer is that it helps with displaying your apps the same way across all platforms, wherein the HTML renderer might produce slightly different output in browsers compared to mobile and desktop devices.

So, if you need the best file size use flutter build web --web-renderer html --release, and if you want the best fidelity across platforms use flutter build web --web-renderer canvaskit —-release when building your web app.

The current release build for the test app we use is ~3.2Mb. From this size, ~800Kb represents a NOTICES file that will not be downloaded by the users. There are also fonts with a size of ~1.2Mb, which can be slimmed down to only icons, chars we use within our released application. So we're left with a bare minimum of ~1.2Mb web app which is not ideal for the web platform. I'm sure the Flutter team will work their magic in this area and bring down that size footprint even more.

Warning: Flutter's support for web development is not stable yet and hasn't been thoroughly tested in production environments.

Desktop

Unlike the web platform, which is in beta, the desktop platforms are in alpha.

macOS

From the project we just created using the master channel, the command flutter config --enable-macos-desktop will enable the support for desktop applications development on macOS (note that running and building such applications is possible only on a machine running macOS).

If we run the commandflutter devices, we should get a new device:

macOS (desktop) 
  • macos  
  • darwin-x64     
  • Mac OS X 10.15.7 19H114 darwin-x64

To add a build specific folder to an existing project we have to run the command flutter create ..

Finally, to run our desktop application on macOS we use the flutter run -d macos command.

None
Flutter test app running on macOS.

Linux

Instead of using a virtual machine, I went on and experienced the entire process of installing Ubuntu, IntelliJ IDEA CE, and Flutter on a physical machine. Thanks to the Linux desktop app support with Flutter enabled by Canonical (from which we have Ubuntu) everything went smoothly.

From the project we just created using the master channel, the command flutter config --enable-linux-desktop will enable the support for desktop applications development on Linux (note that running and building such applications is possible only on a machine running Linux).

If we run flutter device we get another new device:

Linux (desktop)     
  • linux     
  • linux-x64     
  • Linux

To add a build specific folder to an existing project we have to run the command flutter create ..

Finally, to run our desktop application on Linux we use the flutter run -d linux command.

None
Flutter test app running on Ubuntu (Linux).

Windows

From the project we just created using the master channel, the command flutter config --enable-windows-desktop will enable the support for desktop application development on Windows (note that running and building such applications is possible only on a machine running Windows).

If we run flutter devices we get yet another new device:

Windows (desktop) 
  • windows 
  • windows-x64    
  • Microsoft Windows [Version 10.0.19042.685]

To add a build specific folder to an existing project we have to run the commandflutter create ..

Finally, to run our desktop application on Windows we use the flutter run -d windows command.

None
Flutter test app running on Windows.

Distribution

It is not recommended to release and distribute desktop applications built with Flutter until the desktop support reaches stable.

If you want to break the "rules" you can use the flutter build followed by the platform you want to build on (macos, linux, or windows).

If everything works well you should see only a 1 line output in the Terminal: Building macOS/Linux/Windows application…

If anything goes wrong sometimes a good old restart or running the command flutter clean before building might help.

The test app had the following sizes:

  • macOS — located in build/macos/Build/Products/Release/ the self-contained cross_platform.app weighed a bit over 35Mb
  • Linux— located in build/linux/release/bundle/ the contents of the folder (cross_platform launcher, data, and lib folders) weighed almost 62Mb
  • Windows — located in build\windows\runner\Release\ the contents of the folder (cross_platform.exe, flutter_windows.dll, and data folder) weighed a bit over 18Mb

The file sizes from above will increase slightly with each new functionality added. As long as we don't add multimedia assets to the app and huge libraries or packages, the file size will stay about the same.

You can find more about distribution here.

The status

You should weigh in carefully if Flutter is suitable to solve your problem.

Sometimes a native single-platform approach is the best way to go and doing cross-platform just because you can is not a good enough reason.

Flutter goes out of the discussion if you plan to build something dealing with 3D (a 3D game, 3D editor, AR app involving 3D models, etc.). Maybe that'll change in the future, but for now, using something like Unity is more suitable for this.

Flutter can be enabled to access device-specific functionalities (like sensors, Bluetooth connectivity, and others) using plugins. When you settle on what you want to build you can check if those plugins exist and maybe test them out in a proof of concept before jumping in. If the plugins don't exist or don't work as expected then you have to implement them yourself. That might require native development for each specific platform. If your application will need plugins for most of its features, then you might consider as well developing it natively. Though, the beautiful UI enabled by Flutter might convince you otherwise.

The final application size can play a factor in not choosing Flutter.

On mobile, this issue can be resolved by packaging your release files correctly. iOS had a 200Mb limit for over-the-air downloads (downloads over a cellular network, not WiFi) in the past. Now that is just a soft limit (the phone will request a confirmation of the download). Your app's total uncompressed size must be less than 4GB for iOS. On Android, the max file size is 100Mb if you choose the APK distribution, or 150Mb if you choose the Android App Bundle distribution. The APK can accept 2 expansion files conceptually for the main expansion and a patch expansion (2Gb each). It seems that the new Android App Bundle distribution does not support APK's expansion files and will be the only way to publish new apps in the second half of 2021. Nevertheless, you can always download resources for your app from some CDN.

On the web, file size matters more than on mobile. The current 1.x Mb default file size is not small. A solution might be to split the embedded framework and the actual codebase and use the framework as a shared library among all web apps that are built with Flutter. This way, if a user has the library already on his system will be spared the hefty download. Other solutions will be stripping out anything that's not used when building the release (components, chars within fonts, etc.). Another thing developers can do is to play with the user's time perception. A nice and entertaining preloader might keep your users on the page and engaged for using the app they are loading. On the other hand, there must be a reason for 5G. As time passes file size becomes less and less an issue.

On the desktop platforms, file size matters the least. Ideally, the final application file size should be as small as possible, but you can get away with almost anything. It may be more cost-effective for you to distribute, less time-consuming for the users to download, and more space-saving for them to install your product if your final application is smaller. In general, a desktop has more storage and is better connected to the Internet compared to a smartphone. Keep in mind though, that the release build application should be small enough to be accepted by all of your users' file systems.

We've seen the file sizes Flutter produces for each platform and they're all acceptable (with some concerns regarding the web platform).

If you want to get started with Flutter you can jump right into the default sample app and start from there. There are plenty of resources to discover and use for building your app(s). You can also start with some Dart fundamentals, Dart being the secret sauce (programming language) that makes it all possible.

None
The platform groups supported by Flutter.

Flutter makes that dream of one codebase that can compile apps for multiple platforms a little more real with each iteration. It provides the desired visual consistency, and also the desired slight aesthetics and UX inconsistencies specific to each platform that users expect out of their device (to some extent). There are still limitations regarding capabilities, that can be resolved using plugins.

Software is never perfect and that sure is a consequence of us humans building it.

The future

The Flutter Engage event took place on the 3rd of March 2021. There were a lot of speculations in the Flutter community on what to expect.

Most were expecting Flutter support for the web platform to go from beta to stable. Some, more optimistic, expected also the desktop platforms to get a bump in support to stable. I thought that won't happen. The expected upgrade for desktop would have been from alpha to beta, though even this is too optimistic for all 3 desktop OSes Flutter supports (macOS, Windows, and Linux). There were also hopes for Fuchsia OS to be released in the wild into some beta form.

The date that was picked up by the Flutter team (03/03/21) indicated something revolving around the number 3. We've got 3 platform groups around which the development effort revolves and those are mobile, web, and desktop. So, the probability was that there will be updates on all these 3 fronts.

It could also indicate moving the web platform from beta to stable so that we get 3 platforms with sable support.

It could've been viewed as 03/03. If we sum up the 2, gives us 6 and that is the number of platforms Flutter currently supports (to a certain degree): Android, iOS, web, macOS, Linux, and Windows. This also indicated announcements across all platforms.

Flutter is designed to support 2D, so it could've been a surprising announcement extending the support to 3D (that was very unlikely and deviating from the road map). The Flutter Engage page and the 3Dness of it (environment, the new 3D Dash x 3, etc.) also pointed a bit towards this idea.

I thought we'll get null safety for all popular plugins and packages, especially those directly maintained by the Flutter team. Expecting a null safety migration in all packages from pub.dev was a stretch. There are a lot of reasons for this not to happen.

I also thought that Flutter web will get into the stable channel and that will come with some compromises at first. Currently, there are some use-cases in which Flutter web does a poor job compared to some other solutions.

Also thought that the desktop platforms may be promoted to beta. macOS might get even into stable, being the first desktop platform that entered alpha. Although, the Flutter team might move the entire desktop support at the same time to avoid confusion. Maybe the stable support for the desktop will come towards the end of 2021.

As long as Google invests in Flutter and promotes it, there is no other way to turn but better.

Definitely, I expected some announcements around tooling. There's certainly the need for some tools to be provided to help developers migrate their applications to null safety.

I didn't mind seeing other players entering the animation game (maybe Adobe adds to Animate some support for Flutter).

A bump in Flutter's major version was announced: Flutter 2. With it, all 6 supported platforms went into stable (Android, iOS, web, macOS, Linux, and Windows).

The desktop is not quite there on all fronts, but I think the move was done to simplify Flutter users' perception, improve its selling points, and ease of release management of the entire framework for the Flutter team.

Regarding tooling, there is a new dart fix command-line command that can help to migrate deprecated APIs and switch to adopt null safety.

The support for foldable devices, by Microsoft, and the in-car infotainment solution, based on Flutter, by Toyota were presented to showcase both its flexibility and portability.

Even if not all the hopes and wishes were met at the event in March, Flutter got closer to being the go-to solution for cross-platform software development. And with each fixed bug or newly added feature, it does this. As long as Google invests and promotes it there is no other way to turn but better.

Tha(nk|t')s all!