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.
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
fiThe 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”.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
