# Amazing performance improvements in Flutter 3 for Mac apps

The last major version of Flutter, Flutter 2, already offered official support for Android, iOS, web and Windows. Flutter 3 adds stable support for the remaining platforms, which are macOS and Linux. It also includes support for Apple's new M1 processors.

In this article I am going to delve into the official Flutter 3 support for macOS. I am going to build a very simple application using the [macos_ui](https://pub.dev/packages/macos_ui) plugin, which is used to give our application a macOS-style look n' feel, and finally I am going to make a performance comparison between Flutter 2 and Flutter 3 regarding the performance of a macOS desktop application.

> 📽 Video version available on [YouTube](https://youtu.be/FXkqVjCDCd8) and [Odysee](https://odysee.com/@svprdga:d/amazing-performance-improvements-in-flutter-3-for-mac-apps-macos-apple-silicon-m1-stable-support)

%[https://youtu.be/FXkqVjCDCd8]

### Performance improvements

In the [previous article](https://davidserrano.io/flutter-3-for-web-have-they-really-managed-to-increase-performance) I discussed the performance improvements that the Flutter team and its contributors applied to image processing on the web, we saw a substantial performance increase in Chromium-based browsers.

As this is a major update, and considering that the new app will run natively on my M1 mac (as opposed to Flutter 2, which depends on the Rosseta translation layer); I expect to see a performance improvement in this new release of Flutter. To see if there is any improvement I am going to use the FPS indicator included in AndroidStudio while running the application in profile mode.

But first we need to create an application to test, let's see how it is to create a desktop application for macOS using Flutter 3:

### macOS app creation

Let's start by creating a new project:

> Note: If you want also to do the performance tests, you should create the project with Flutter 2. This is because if you create the project with Flutter 3 the CLI tool will set your minimum dart SDK to an incompatible version with Flutter 2; also it will use an incompatible version of `flutter_lints`.

`flutter create macos_test`

We add the `macosui_test` dependency to `pubspec.yaml`, which looks like this:

```yaml
name: macosui_test
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1

environment:
   sdk: ">=2.16.2 <3.0.0"

dependencies:
   flutter:
     sdk:flutter
   cupertino_icons: ^1.0.2
   macos_ui: ^1.3.0

dev_dependencies:
   flutter_test:
     sdk:flutter
   flutter_lints: ^1.0.0

flutter:
   uses-material-design: true
```

Now replace the entire contents of `main.dart` with the following:

```dart
import 'package:flutter/material.dart';
import 'package:macos_ui/macos_ui.dart';

void main() {
  runApp(const App());
}

class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MacosApp(
      theme: MacosThemeData.light(),
      darkTheme: MacosThemeData.dark(),
      themeMode: ThemeMode.light,
    );
  }
}
```

The `MacosApp` widget acts in the same way as `MaterialApp` or `CupertinoApp`, it's a widget that should be at the root of the application and provides context and styles to the underlying widgets. Run the application, you will see an empty window appear; this is normal since we haven't added anything yet.

Now we are going to add a screen with two side tabs. Add the following widget:

```dart
class MainScreen extends StatefulWidget {
  const MainScreen({Key? key}) : super(key: key);
  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int _pageIndex = 0;

  @override
  Widget build(BuildContext context) {
    return MacosWindow(
      sidebar: Sidebar(
        minWidth: 180,
        builder: (context, scrollController) {
          return SidebarItems(
            currentIndex: _pageIndex,
            onChanged: (index) {
              setState(() => _pageIndex = index);
            },
            items: const [
              SidebarItem(
                leading: MacosIcon(CupertinoIcons.macwindow),
                label: Text('Main'),
              ),
              SidebarItem(
                leading: MacosIcon(CupertinoIcons.graph_circle),
                label: Text('Performance'),
              ),
            ],
          );
        },
      ),
      child: IndexedStack(
        index: _pageIndex,
        children: [
          MacosScaffold(
            children: [
              ContentArea(
                builder: ((context, scrollController) {
                  return const Center(
                    child: Text('Main'),
                  );
                }),
              ),
            ],
          ),
          MacosScaffold(
            children: [
              ContentArea(
                builder: ((context, scrollController) {
                  return const Center(
                    child: Text('Performance'),
                  );
                }),
              ),
            ],
          ),
        ],
      ),
    );
  }
}
```

And don't forget to set it has the `home` of `MacosApp`:

```dart
class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MacosApp(
      theme: MacosThemeData.light(),
      darkTheme: MacosThemeData.dark(),
      themeMode: ThemeMode.light,
      home: const MainScreen(), // <= Add the screen here
    );
  }
}
```

If you look at the content of the `build()` method, you will see that we are using the `MacosWindow` widget as the main display container. This container can have a resizable sidebar, items inside it, and a main content for each tab packed in `MacosScaffold`. If you are interested in learning more about each of these widgets, you can visit the [official guide](https://macosui.dev/docs/getting_started/first_app) of `macos_ui` which offers a much more extensive and detailed explanation.

Run the app to see the final result.

![macos_app.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1653031904544/t5v9G8ySy.png align="left")

### Performance test

Now we are going to test the difference in performance of this same application between Flutter 2 and Flutter 3.

First, I'm going to make the following changes in the _Performance_ tab to force Flutter to continually redraw its UI, so we'll be able to see more easily the performance differences:

```dart
class MainScreen extends StatefulWidget {
  const MainScreen({Key? key}) : super(key: key);
  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int _pageIndex = 0;

  @override
  Widget build(BuildContext context) {
    // Create 1000 loading widgets. I use this widget because is
    // an infinite animation, so Flutter will be redrawing the UI
    // indefinitely.
    List<Widget> widgets = [];
    for (var i = 0; i < 1000; i++) {
      widgets.add(const CupertinoActivityIndicator(
        color: CupertinoColors.systemGrey,
      ));
    }

    return MacosWindow(
      sidebar: Sidebar(
        minWidth: 180,
        builder: (context, scrollController) {
          return SidebarItems(
            currentIndex: _pageIndex,
            onChanged: (index) {
              setState(() => _pageIndex = index);
            },
            items: const [
              SidebarItem(
                leading: MacosIcon(CupertinoIcons.macwindow),
                label: Text('Main'),
              ),
              SidebarItem(
                leading: MacosIcon(CupertinoIcons.graph_circle),
                label: Text('Performance'),
              ),
            ],
          );
        },
      ),
      child: IndexedStack(
        index: _pageIndex,
        children: [
          MacosScaffold(
            children: [
              ContentArea(
                builder: ((context, scrollController) {
                  return const Center(
                    child: Text('Main'),
                  );
                }),
              ),
            ],
          ),
          MacosScaffold(
            children: [
              ContentArea(
                builder: ((context, scrollController) {
                  // Draw in a grid all the loadings created before.
                  return Center(
                    child: GridView.count(
                      crossAxisCount: 25,
                      children: widgets,
                    ),
                  );
                }),
              ),
            ],
          ),
        ],
      ),
    );
  }
}
```

The result that you are going to see below has been executed on a 2020 MacBook PRO M1 with 16 GB of RAM. The application runs in _profile_ mode:

![flutter_2_fps.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1653032637835/8pDz349yz.png align="left")

With Flutter 2 we can see that the application runs with a stable 30 frames per second.

![flutter_3_fps.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1653032646365/3yqUgPutC.png align="left")

After upgrading to Flutter 3, the meter goes up to 60 FPS.

This test demonstrates the huge performance improvement that Flutter 3 brings. This is probably due to the fact that the app runs natively on my Apple Silicon processor, instead of relying on a translation layer of the old `x86` architecture to the `ARM` architecture that the new M1 processors brings.

### Conclusion

In this article we have created a very simple Flutter 3 application for macOS using the `macos_ui` package. I've also demonstrated the performance differences between Flutter 2 and Flutter 3 when it comes to running a desktop app.

This opens up a wide range of possibilities for using Flutter. As in my previous article, I have to congratulate the Flutter team and their contributors for the amazing work that they've done, as well as the developer of the `macos_ui` plugin for the incredible job of recreating the visual style of macOS in a Flutter plugin.

You can find the source code of this project [here](https://github.com/svprdga/Flutter-3-macOS-and-macos_ui-test).

This is all for today, thank you very much for reading and have a great rest of your day.

