Mobile Development 28 min read

Flutter Package Size Optimization Using Dynamic Delivery

The Meituan Waimai team tackled Flutter’s excessive binary growth by splitting engine, assets, and data into downloadable modules, implementing custom build flags and runtime loaders for iOS and Android, achieving up to 95 % APK size reduction and over 30 % IPA shrinkage while shifting payload to on‑demand delivery.

Meituan Technology Team
Meituan Technology Team
Meituan Technology Team
Flutter Package Size Optimization Using Dynamic Delivery

Flutter is a modern, reactive, cross‑platform mobile development framework that offers good performance, stability and a consistent experience across multiple devices. Since its open‑source release it has gained widespread adoption among developers.

However, integrating Flutter often leads to a noticeable increase in the application package size, which brings significant concerns for many development teams. The Meituan Waimai front‑end team investigated the Flutter package‑size problem and designed a dynamic‑delivery based optimization solution to help developers reduce the binary size.

1. Background

With the continuous evolution of the Flutter framework, more teams are adopting it in production. In practice we found that adding a single Flutter demo page increases the package size by at least 5 MB on both Android and iOS, which is unacceptable for size‑sensitive applications.

The Flutter team has been improving the size through several releases:

Flutter v1.2 introduced Android App Bundles with Dynamic Module support.

Flutter v1.12 reduced the Hello‑World app size on Android from 3.8 MB to 3.7 MB (≈2.6 % reduction).

Flutter v1.17 introduced Dart PC Offset storage and other techniques, achieving an 18.5 % reduction.

Flutter v1.20 added Icon‑font tree shaking to remove unused icon fonts.

Beyond these SDK‑level optimizations, we explored further size‑reduction opportunities, focusing on dynamic delivery.

2. Flutter Package Size Analysis

The Flutter product consists of three main parts: the engine (fixed size), the Flutter framework & business code (grows with added features), and resources (mainly images). The engine size is constant, the framework size grows rapidly at first and then slows down due to Tree‑Shaking, and resource size scales with the amount of assets.

Figures (omitted) illustrate the composition of iOS and Android Flutter artifacts and the trend of each component.

3. Dynamic‑Delivery Based Optimization Scheme

We designed separate solutions for iOS and Android because of platform constraints.

3.1 iOS Solution

iOS cannot load executable code at runtime, so we split the non‑executable parts (flutter_assets, icudtl.dat, and the data sections of the snapshot) and deliver them dynamically. The engine is modified to load these resources from custom paths.

Key steps:

Introduce a new compilation command buildWithoutData (or flag --without-data) that generates an AOT snapshot without the data sections.

Customize FlutterDartProject to expose properties for icuDataPath, assetPath, isolateSnapshotDataPath and vmSnapshotDataPath.

During runtime, set these paths to files downloaded from the server.

Example of the settings struct (original source):

// settings
{
  // snapshot file address or memory address
  std::string vm_snapshot_data_path;
  MappingCallback vm_snapshot_data;
  std::string vm_snapshot_instr_path;
  MappingCallback vm_snapshot_instr;

  std::string isolate_snapshot_data_path;
  MappingCallback isolate_snapshot_data;
  std::string isolate_snapshot_instr_path;
  MappingCallback isolate_snapshot_instr;

  // library mode lib file path
  std::string application_library_path;
  // icu data file path
  std::string icu_data_path;
  // flutter assets folder path
  std::string assets_path;
}

We also added a custom compilation command in xcode_backend.sh to trigger the “thin” build:

if [[ $# == 0 ]]; then
  # Backwards‑compatibility: if no args are provided, build.
  BuildApp
else
  case $1 in
    "build")
      BuildApp ;;
    "buildWithoutData")
      BuildAppWithoutData ;;
    "thin")
      ThinAppFrameworks ;;
    "embed")
      EmbedFlutterFrameworks ;;
  esac
fi

The iOS workflow consists of three stages:

Custom compilation stage : generate AOT snapshots without data and package the data files separately.

Release integration stage : upload the split resources to Meituan Cloud and configure the build to exclude them from the IPA.

Runtime stage : download the resources on first launch, set the custom paths in FlutterDartProject, and start the engine.

3.2 Android Solution

Android allows runtime loading of native libraries, so we can dynamically deliver both libflutter.so, libapp.so and the flutter_assets bundle.

Key components:

Use the DynLoader framework to upload the split SO files and asset bundle to the server during the build phase.

At app startup, request the required bundles, download and unzip them if not cached.

Customize the Flutter engine initialization by overriding FlutterMain.startInitialization and FlutterMain.ensureInitializationComplete to load the SO files from the downloaded location.

Replace the default PlatformAssetBundle with a custom DynamicPlatformAssetBundle (injected via DefaultAssetBundle) that loads assets from the dynamic path.

Load fonts dynamically using FontLoader because static font loading fails after assets are removed.

Example of a custom engine initialization snippet:

class FlutterRouteUtil {
    public static void startFlutterActivity(final Context context, Intent intent) {
        FlutterDynamic.getInstance().ensureLoaded(context, new LoadCallback() {
            @Override
            public void onSuccess() {
                // Execute navigation after resources are ready
                context.startActivity(intent);
            }
        });
    }
}

And a custom FlutterActivity that ensures the engine is initialized before calling super.onCreate:

public class MainFlutterActivity extends FlutterActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Ensure custom engine initialization is complete
        FlutterDynamic.getInstance().ensureFlutterInit(this);
        super.onCreate(savedInstanceState);
    }
}

The Android workflow mirrors the iOS one: split the artifacts during the build, upload them, download at runtime, and load them via the customized engine and asset bundle.

4. Results and Outlook

The dynamic‑delivery solution has been deployed internally at Meituan. The Android APK size reduction reaches up to 95 % and the iOS IPA reduction exceeds 30 %. While the approach dramatically shrinks the initial download size, the total size is shifted to runtime downloads. Future work will explore further modularization and per‑feature splitting to keep runtime payloads small.

5. Authors

Yan Dong – Front‑end engineer at Meituan (joined 2018). Zong Wen – Senior front‑end engineer at Meituan (joined 2019). Hui Chao – Front‑end technical expert at Meituan (joined 2014).

Recruitment Information

Meituan Waimai is hiring senior/lead Android, iOS, and front‑end engineers. Interested candidates can send their resumes to [email protected] with the email title “Meituan Waimai Technical Team”.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

FlutteriOSAndroidPackage Size OptimizationDynamic Delivery
Meituan Technology Team
Written by

Meituan Technology Team

Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.