Mastering Dart & Flutter DevTools — Part 3: App Size Tool
by Ashita Prasad (LinkedIn, Twitter), fluttergems.dev
This is the third article in the “Mastering Dart & Flutter DevTools” series of in-depth articles. In this article, you will learn how to analyze an app’s size using the DevTools’ App Size Tool on a real-world open-source app — Wonderous. In case you want to check out any other article in this series, just click on the link provided below:
- Part 1: Introduction & Installation
- Part 2: Flutter Inspector
- Part 3: App Size Tool [You are Here]
- Part 4: Network View
- Part 5: Logging View
- Part 6: CPU Profiler View
- Part 7: Memory View
- Part 8: Performance View
Installation and setup of DevTools is a pre-requisite for this part. In case you missed it, the installation and setup details are provided in detail here.
As the number of apps are growing at a rapid pace (~100K new apps/month), they are competing for the most sought after digital real estate — A User’s Device Storage. Thus, an App’s size has become a major factor (lower is better!) that can influence the user’s decision to go ahead and download the app. As we add new features to an app, it’s size might increase by a few KBs or MBs which is perfectly fine. But, any significant increase in size may deter people from downloading the app. This is where the DevTools’ App size tool comes to our rescue and helps us in analyzing the size of our app in detail.
In this article we will walk through the App Size Tool and understand it better by analyzing the Wonderous App.
App Size Tool
DevTools’ App Size Tool helps developers measure and analyze the size of an app. This information is very useful for understanding the impact of an app on the device’s storage.
To better understand how this tool works, we will undertake two scenarios:
- Scenario #1: Size Analysis — In the first scenario, we will analyze the size of the recently released open-source Flutter App — Wonderous.
- Scenario #2: Size Difference Analysis— In this scenario, we will compare the size of Wonderous app with a refactored version of the app that replaces the existing state management package with another package.
The entire exercise will be demonstrated using VS Code IDE.
Scenario #1
Let us start with the first scenario where we will perform the size analysis of the Wonderous App.
Step 1: Getting the Source Code
Open the below mentioned repository.👇
Click on the Green Code
button and the Local
tab.
As mentioned in the image above, you can use any command-line tool or GitHub Desktop to clone the repository.
But, for this exercise let us click on Download ZIP
to download the entire source code and extract it.
We now have a local copy of the source in the folder flutter-wonderous-app-master
Step 2: Opening the Project in VS Code
Launch VS Code, open the project folder in VS Code and go to pubspec.yaml
file.
Click on Get Packages
to fetch all the packages required for the project. It runs the flutter pub get
command.
Now, as shown in the image below, click on the infos
status bar button. In case TERMINAL
tab is missing right click and select ✔Terminal.
Click on the TERMINAL
tab to access the shell inside VS Code.
Step 3: Running the Size Analysis Tool in VS Code Terminal
Compared to other tools that can run in debug or profile mode, App Size Tool requires generation of a unobfuscated release build that contains no debugging overhead and is close to the production version of an app the end user would download and install.
In the VS Code shell shown above, the size analysis tool can be invoked by passing the --analyze-size
flag while building the release version using one of the following commands:
flutter build apk --analyze-size
(any host)flutter build appbundle --analyze-size
(any host)flutter build ios --analyze-size
(only macos host)flutter build linux --analyze-size
(only linux host)flutter build macos --analyze-size
(only macos host)flutter build windows --analyze-size
(only windows host)
For this exercise we will build an Android App Bundle and perform a size analysis on it by executing the below command:
flutter build appbundle --analyze-size
The following error message will be displayed —
Cannot perform code size analysis when building for multiple ABIs.
Specify one of android-arm, android-arm64, or android-x64 in the
— target-platform flag.
As there are three main CPU architectures — ARM (android-arm
), ARM64(android-arm64
), or x86(android-x64
) in Android devices, we have to specify the target platform for code size analysis as the compiled binaries differ based on the target platform. The same is true in case you want to perform size analysis while using flutter build apk
command.
ARM64 is becoming the standard in newer android devices, so we will choose the target platform as android-arm64
and execute the following command:
flutter build appbundle --analyze-size --target-platform android-arm64
Post execution, the size analysis tool records the size of all resources and packages post code compilation. A summary drill-down of the app size is also displayed and a detailed size analysis is saved in *-code-size-analysis_*.json
file.
In our case the code size snapshot was saved in aab-code-size-analysis_01.json
file and the full path to the file was displayed (highlighted in the image above).
Step 4: Launching the Size Analysis Tool Page
1. Using VS Code Terminal
In case DevTools is not activated, run the following command in the VS Code terminal:
flutter pub global activate devtools
Now, you can launch the App Size Analysis tool and preload it with the generated size snapshot data directly using the command(s):
flutter pub global run devtools --appSizeBase=aab-code-size-analysis_01.json
2. Using VS Code Status Button
Click on Dart DevTools in the VS Code Status Bar.
The following page will open in the browser.
Now, click on the Open app size tool
button to open the App Size Tool page as shown in the image below.
Right on the top of this page, you can see the two types of size analysis options that are available - Analysis and Diff.
- Analysis — Helps you drill-down deeper into a single size information snapshot (file). This will be covered in the current scenario.
- Diff — This is useful for comparing two size information snapshots. It is used for cases when we want to visualize size changes between two snapshots (old ver. vs new ver.) after performing some app optimization. We will cover it in detail in Scenario #2.
Step 5: Using the App Size Tool
In the current scenario (Scenario #1), we want to perform the size analysis of a single snapshot. So, we will focus on the Analysis tab.
Click Import File
and select the aab-code-size-analysis_01.json
file by navigating to the path displayed on the terminal.
After selecting the file, just click on Analyze Size
to open the size analysis of the snapshot as shown in the image below.
You can immediately witness a hierarchical tree visualization (Treemap) as shown below.
Below this Tree-map, the snapshot size data is also available in the form of an explorer view table.
The current root node is Root which is also the complete app bundle whose size is 50.6 MB.
You can click on the node (Root) and expand it to view the size of child nodes.
These nodes (classes/folders/libraries) are Level 1 child nodes and they are shown on the treemap just below the breadcrumb navigator.
In the figure above, as the base
node (Level 1 child) represents 99.51% of its parent node’s size, so it occupies almost the entire scale.
Level 2 child nodes are the children of Level 1 nodes and are shown on the tree-map just below their parent node. These nodes are presented in a 2D map where the rectangular area occupied by a node is proportional to its size (in bytes). For example, base
has the following children — assets
, lib
, dex
, res
, and so on ..
As the size of assets
is 36.9 MB, it covers approx. 70% of the area.
If you click on any Level 1 or Level 2 node on the treemap, it is made the new root so that you can perform a deeper analysis of size contributors.
Let us try this out. In the tree-map,
- Go ahead and click on
assets
. - Then click on
flutter_assets
. - Now, click on
assets
.
The changes are immediately reflected in the tabular view as shown in the image below, where images
and fonts
are the immediate children of assets
(new root).
assets as its root
As shown in the image below, the tree-map is also updated, with assets [36.8 MB]
as its new root node. images
and fonts
(Level 1 nodes) are the immediate children of this new root node. And the children of images
and fonts
nodes are presented as a 2D tree-map below their parents.
Upon performing a broad-level inspection of the above tree-map, we can observe that the size of the nodes is in the following decreasing order — petra
, _commom
, machu_pichu
, taj_mahal
, and so on ..
Let us go ahead and click on petra
to view the image files inside it that have significantly larger size. The results are shown in the image below.
If we look at the current scenario, assets
(images and fonts) contribute to more that 70% of the app size.
Size Reduction Strategies
In almost any app, assets are always the primary size contributors. To reduce their impact on app size, you can follow some size reduction strategies such as:
- Removing unused assets.
- Optimizing (compressing) PNG / JPG images.
- Using modern animation file formats (lottie, rive) compared to GIFs.
- Not pre-bundling font files and using packages like
google_fonts
which fetches a specified font over the internet when the app runs for the first time. This font is subsequently cached in the device.
In case the size footprint of code-base is large, you should:
- Remove unused code.
- Split large classes that are difficult to optimize into smaller classes that will make it easier to identify and remove unnecessary code.
- Obfuscate your app to dramatically reduce code size.
- Choose efficient 3rd party packages that have a low size footprint. We will explore this point further in Scenario #2.
By following these suggestions, you can significantly reduce the size of your mobile app and improve its performance.
Dominator Tree or Call Graph
The Dominator Tree or Call Graph is another section of the App Size tool. One can switch between both the modes using the Toggle Switch button as shown below.
A dominator tree (shown below) is useful for understanding the root cause of existence of a piece of code in the application, where the package tree is arranged in such an order that each node’s children are those nodes that are immediately dominated by the parent.
For example, in the dominator tree of the wonders app (shown above), the package:url_launcher
(child) is dominated by package:youtube_player_iframe
(parent), as all paths to package:url_launcher
goes only through package:youtube_player_iframe
.
In case you want to get a better idea of the dependencies between the pieces of codes (packages) in order to understand why some code is included, Call graph can be used.
For example, in the above Call Graph of package:youtube_player_iframe
, we can observe that the wonders package calls it and it in turn calls package:url_launcher
, package:flutter_inappwebview
and other packages mentioned on the right.
With this we have come to an end of Scenario #1 where we performed a Size Analysis of the Wonderous app. Along with getting familiar with the usage of that Size Analysis Tool, we also got familiar with the various parts of its interface. Finally, we learnt various size reduction strategies that can help us reduce the size of the app.
Now, let us proceed with Scenario #2.
Scenario #2
In this scenario, we will be using the Diff Tab in the App Size Tool. This tab is useful when you want to visualize the difference in size between two snapshots — old version vs new size-optimized version.
In our case we will compare the following two size information snapshots:
- Snapshot #1 — The size information snapshot created in Scenario #1 of the Wonderous app.
- Snapshot #2 — The size information snapshot of a refactored version of the wonderous app that uses another 3rd party state management package instead of
provider
package used in the original app.
It can be seen in the image below, how the Diff tab requires two snapshots to be uploaded for comparison.
Let us clone the repo that has a refactored version of Wonderous app code. 👇
You can follow the same instructions for this project as provided in Scenario #1’s Step 1: Getting the Source Code and Step 2: Opening the Project in VS Code.
If you take a look at the pubspec.yaml
file, you can see that the 3rd party package provider
has been removed and the package fluttery_framework
has been included in its place.
Step 3: Running the Size Analysis Tool in VS Code Terminal
Execute the build command along with size analysis flag
flutter build appbundle --analyze-size --target-platform android-arm64
The new size information snapshot file aab-code-size-analysis_02.json
is generated.
Now, launch the App Size tool using the instruction provided in Scenario #1’s Step 4: Launching the Size Analysis Tool Page.
Step 5: Using the App Size Tool
Click on the Diff Tab.
Import the old file (aab-code-size-analysis_01.json
) and the new file (aab-code-size-analysis_02.json
).
Click Analyze Diff button to generate a difference tree-map as shown below.
The colour of the node indicates the change in size. Green colour indicates that there has been an increase in size, whereas red indicates a decrease in size. In this case ~0.5 MB increase has been detected in the refactored code.
Let us click on the libapp.so
node to view the cause of size changes due to the changes made in the app code.
It appears the package:dbus
, package:fluttery_framework
and package:state_extended
are some of the major contributors to this increase in size.
We can understand that using a new package will lead to addition code size, so package:fluttery_framework
and its dependency package:state_extended
is expected, but where did this package:dbus
come from that is causing ~30% size increase?
Let us click on package:dbus
and check the Dominator tree as shown below:
As shown above, package:dbus
is being dominated by package:nm
which in turn is dominated by package:connectivity_plus_linux
.
Let us now use the call graph to check who is calling the package package:connectivity_plus_linux
.
Turns out there is only one package that is calling package:connectivity_plus_linux
and that is package:fluttery_framework
.
In Scenario #2, we saw how App Size Tool’s Diff tab can be used to perform investigation of size changes between two snapshots. In this exercise, we also observed how replacing an existing package with a new 3rd party package fluttery_framework
led to an increase in the app size. Thus, App Size Tool is also a very useful tool for assessing the size impact of 3rd party packages in your app.
In this article, we took a deep dive into the App Size Tool and performed a Wonderous App case study using two scenarios:
- In Scenario #1, we analyzed how assets contributed to a major portion of the app size. We also went through the various strategies that can help you reduce the size of your app.
- In Scenario #2, we compared a refactored version of the Wonderous app with the original. Using the various features of the App Size Tool, we performed an in-depth investigation and first-hand witnessed how 3rd party packages have a direct impact on the app’s size.
We would definitely love to hear about your experience with the App Size Tool and any suggestions in the comments. In case you faced any issues while going through this exercise or while running the tool for your project, please feel free to mention it in the comments and we can definitely take a look at it.
In the remaining articles of this series, we have discussed other tools available in the DevTools suite that can help you build high-performance Flutter apps. Don’t forget to check out the links below to navigate to the tool you want to learn next:
- Part 1: Introduction & Installation
- Part 2: Flutter Inspector
- Part 4: Network View
- Part 5: Logging View
- Part 6: CPU Profiler View
- Part 7: Memory View
- Part 8: Performance View
Source Code(s) used in this article:
Special thanks to Kamal Shree (GDE — Dart & Flutter) for reviewing this article.