Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

docs.flutter.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic.

Learn more

Flutter 3.41 is live! Check out theFlutter 3.41 blog post!

Deferred components for Android and web

How to create deferred components for improved download performance.

Introduction

#

With Flutter, Android and web apps have the capability to download deferred components (additional code and assets) while the app is already running. This is helpful if you have a large app and only want to install components if and when they are needed by the user.

While Flutter supports deferred loading on Android and the web, the implementations differ. Both requireDart's deferred imports.

  • Android'sdynamic feature modules deliver the deferred components packaged as Android modules.

    When building for Android, though you can defer loading modules, you must build the entire app and upload that app as a singleAndroid App Bundle (AAB). Flutter doesn't support dispatching partial updates without re-uploading new Android App Bundles for the entire application.

    Flutter performs deferred loading when you compile your Android app inrelease or profile mode, but debug mode treats all deferred components as regular imports.

  • The web creates deferred components as separate*.js files.

For a deeper dive into the technical details of how this feature works, seeDeferred Components on theFlutter wiki.

How to set your Android project up for deferred components

#

The following instructions explain how to set up your Android app for deferred loading.

Step 1: Dependencies and initial project setup

#
  1. Add Play Core to the Android app'sbuild.gradle dependencies.Inandroid/app/build.gradle add the following:

    android/app/build.gradle.kts
    kotlin
    ...dependencies{...implementation("com.google.android.play:core:1.8.0")...}
    android/app/build.gradle
    groovy
    ...dependencies{...implementation"com.google.android.play:core:1.8.0"...}
  2. If using the Google Play Store as thedistribution model for dynamic features,the app must supportSplitCompat and provide an instanceof aPlayStoreDeferredComponentManager.Both of these tasks can be accomplished by settingtheandroid:name property on the application inandroid/app/src/main/AndroidManifest.xml toio.flutter.embedding.android.FlutterPlayStoreSplitApplication:

    xml
    <manifest ...<applicationandroid:name="io.flutter.embedding.android.FlutterPlayStoreSplitApplication"...</application></manifest>

    io.flutter.app.FlutterPlayStoreSplitApplication handlesboth of these tasks for you. If you useFlutterPlayStoreSplitApplication,you can skip to step 1.3.

    If your Android applicationis large or complex, you might want to separately supportSplitCompat and provide thePlayStoreDynamicFeatureManager manually.

    To supportSplitCompat, there are three methods(as detailed in theAndroid docs), any of which are valid:

    • Make your application class extendSplitCompatApplication:

      java
      publicclassMyApplicationextendsSplitCompatApplication{...}
    • CallSplitCompat.install(this);in theattachBaseContext() method:

      java
      @OverrideprotectedvoidattachBaseContext(Contextbase){super.attachBaseContext(base);// Emulates installation of future on demand modules using SplitCompat.SplitCompat.install(this);}
    • DeclareSplitCompatApplication as the applicationsubclass and add the Flutter compatibility code fromFlutterApplication to your application class:

      xml
      <application...android:name="com.google.android.play.core.splitcompat.SplitCompatApplication"></application>

    The embedder relies on an injectedDeferredComponentManager instance to handleinstall requests for deferred components.Provide aPlayStoreDeferredComponentManager intothe Flutter embedder by adding the following codeto your app initialization:

    java
    importio.flutter.embedding.engine.dynamicfeatures.PlayStoreDeferredComponentManager;importio.flutter.FlutterInjector;...PlayStoreDeferredComponentManagerdeferredComponentManager=newPlayStoreDeferredComponentManager(this,null);FlutterInjector.setInstance(newFlutterInjector.Builder().setDeferredComponentManager(deferredComponentManager).build());
  3. Opt into deferred components by addingthedeferred-components entry to the app'spubspec.yamlunder theflutter entry:

    yaml
    ...flutter:...deferred-components:...

    Theflutter tool looks for thedeferred-componentsentry in thepubspec.yaml to determine whether theapp should be built as deferred or not.This can be left empty for now unless you alreadyknow the components desired and the Dart deferred librariesthat go into each. You will fill in this section laterinstep 3.3 oncegen_snapshot produces the loading units.

Step 2: Implementing deferred Dart libraries

#

Next, implement deferred loaded Dart libraries in your app's Dart code. The implementation doesn't need to be feature complete yet. The example in the rest of this page adds a new simple deferred widget as a placeholder. You can also convert existing code to be deferred by modifying the imports and guarding usages of deferred code behindloadLibrary()Futures.

  1. Create a new Dart library.For example, create a newDeferredBox widget thatcan be downloaded at runtime.This widget can be of any complexity but,for the purposes of this guide,create a simple box as a stand-in.To create a simple blue box widget,createbox.dart with the following contents:

    box.dart
    dart
    import'package:flutter/material.dart';/// A simple blue 30x30 box.classDeferredBoxextendsStatelessWidget{constDeferredBox({super.key});@overrideWidgetbuild(BuildContextcontext){returnContainer(height:30,width:30,color:Colors.blue);}}
  2. Import the new Dart librarywith thedeferred keyword in your app andcallloadLibrary() (seelazily loading a library).The following example usesFutureBuilderto wait for theloadLibraryFuture (created ininitState) to complete and display aCircularProgressIndicator as a placeholder.When theFuture completes, it returns theDeferredBox widget.SomeWidget can then be used in the app as normal andwon't ever attempt to access the deferred Dart code untilit has successfully loaded.

    dart
    import'package:flutter/material.dart';import'box.dart'deferredasbox;classSomeWidgetextendsStatefulWidget{constSomeWidget({super.key});@overrideState<SomeWidget>createState()=>_SomeWidgetState();}class_SomeWidgetStateextendsState<SomeWidget>{lateFuture<void>_libraryFuture;@overridevoidinitState(){super.initState();_libraryFuture=box.loadLibrary();}@overrideWidgetbuild(BuildContextcontext){returnFutureBuilder<void>(future:_libraryFuture,builder:(context,snapshot){if(snapshot.connectionState==ConnectionState.done){if(snapshot.hasError){returnText('Error:${snapshot.error}');}returnbox.DeferredBox();}returnconstCircularProgressIndicator();},);}}

    TheloadLibrary() function returns aFuture<void>that completes successfully when the code in the libraryis available for use and completes with an error otherwise.All usage of symbols from the deferred library should beguarded behind a completedloadLibrary() call. All importsof the library must be marked asdeferred for it to becompiled appropriately to be used in a deferred component.If a component has already been loaded, additional callstoloadLibrary() complete quickly (but not synchronously).TheloadLibrary() function can also be called early totrigger a pre-load to help mask the loading time.

    You can find another example of deferred import loading inFlutter Gallery'slib/deferred_widget.dart.

Step 3: Building the app

#

Use the followingflutter command to build a deferred components app:

flutter build appbundle

This command assists you by validating that your project is properly set up to build deferred components apps. By default, the build fails if the validator detects any issues and guides you through suggested changes to fix them.

Note

You can opt out of building deferred components with the--no-deferred-components flag. This flag causes all assets defined under deferred components to be treated as if they were defined under the assets section ofpubspec.yaml. All Dart code is compiled into a single shared library andloadLibrary() calls complete in the next event loop boundary (as soon as possible while being asynchronous). This flag is also equivalent to omitting thedeferred-components: entry inpubspec.yaml.

  1. Theflutter build appbundle commandruns the validator and attempts to build the app withgen_snapshot instructed to produce split AOT shared librariesas separate SO files. On the first run, the validator willlikely fail as it detects issues; the tool makesrecommendations for how to set up the project and fix these issues.

    The validator is split into two sections: prebuildand post-gen_snapshot validation. This is because anyvalidation referencing loading units can't be performeduntilgen_snapshot completes and produces a final setof loading units.

    Note

    You can opt to have the tool attempt to build yourapp without the validator by passing the--no-validate-deferred-components flag.This can result in unexpected and confusinginstructions to resolve failures.This flag is meant to be used incustom implementations that don't rely on the defaultPlay-store-based implementation that the validator checks for.

    The validator detects any new, changed, or removedloading units generated bygen_snapshot.The current generated loading units are tracked in your<projectDirectory>/deferred_components_loading_units.yaml file.This file should be checked into source control to ensure thatchanges to the loading units by other developers can be caught.

    The validator also checks for the following in theandroid directory:

    • <projectDir>/android/app/src/main/res/values/strings.xml
      An entry for every deferred component mapping the key${componentName}Name to${componentName}.This string resource is used by theAndroidManifest.xmlof each feature module to define thedist:title property.For example:

      xml
      <?xml version="1.0" encoding="utf-8"?><resources>...<string name="boxComponentName">boxComponent</string></resources>
    • <projectDir>/android/<componentName>
      An Android dynamic feature module foreach deferred component exists and contains abuild.gradleandsrc/main/AndroidManifest.xml file.This only checks for existence and doesn't validatethe contents of these files. If a file doesn't exist,it generates a default recommended one.

    • <projectDir>/android/app/src/main/res/values/AndroidManifest.xml
      Contains a meta-data entry that encodesthe mapping between loading units and component name theloading unit is associated with. This mapping is used by theembedder to convert Dart's internal loading unit idto the name of a deferred component to install. For example:

      xml
      ...<applicationandroid:label="MyApp"android:name="io.flutter.app.FlutterPlayStoreSplitApplication"android:icon="@mipmap/ic_launcher">...<meta-data android:name="io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping" android:value="2:boxComponent"/></application>...

    Thegen_snapshot validator won't run until the prebuildvalidator passes.

  2. or each of these checks,the tool produces the modified or new filesneeded to pass the check.These files are placed in the<projectDir>/build/android_deferred_components_setup_files directory.It is recommended that the changes be applied bycopying and overwriting the same files in theproject'sandroid directory. Before overwriting,the current project state should be committed tosource control and the recommended changes should bereviewed to be appropriate. The tool won't make anychanges to yourandroid/ directory automatically.

  3. Once the availableloading units are generated and logged in<projectDirectory>/deferred_components_loading_units.yaml,it is possible to fully configure the pubspec'sdeferred-components section so that the loading unitsare assigned to deferred components as desired.To continue with the box example, the generateddeferred_components_loading_units.yaml file would contain:

    yaml
    loading-units:-id:2libraries:-package:MyAppName/box.Dart

    The loading unit id ('2' in this case) is usedinternally by Dart, and can be ignored.The base loading unit (id '1') is not listedand contains everything not explicitly containedin another loading unit.

    You can now add the following topubspec.yaml:

    yaml
    ...flutter:...deferred-components:-name:boxComponentlibraries:-package:MyAppName/box.Dart...

    To assign a loading unit to a deferred component,add any Dart library in the loading unit into thelibraries section of the feature module.Keep the following guidelines in mind:

    • Loading units shouldn't be includedin more than one component.

    • Including one Dart library from aloading unit indicates that the entire loadingunit is assigned to the deferred component.

    • All loading units not assigned toa deferred component are included in the base component,which always exists implicitly.

    • Loading units assigned to the samedeferred component are downloaded, installed,and shipped together.

    • The base component is implicit andneed not be defined in the pubspec.

  4. Assets can also be included by addingan assets section in the deferred component configuration:

    yaml
    deferred-components:-name:boxComponentlibraries:-package:MyAppName/box.Dartassets:-assets/image.jpg-assets/picture.png# wildcard directory-assets/gallery/

    An asset can be included in multiple deferred components,but installing both components results in a replicated asset.Assets-only components can also be defined by omitting thelibraries section. These assets-only components must beinstalled with theDeferredComponent utility class inservices rather thanloadLibrary().Since Dart libraries are packaged together with assets,if a Dart library is loaded withloadLibrary(),any assets in the component are loaded as well.However, installing by component name and the services utilitywon't load any Dart libraries in the component.

    You are free to include assets in any component,as long as they are installed and loaded when theyare first referenced, though typically,assets and the Dart code that uses those assetsare best packed in the same component.

  5. Manually add all deferred componentsthat you defined inpubspec.yaml into theandroid/settings.gradle file as includes.For example, if there are three deferred componentsdefined in the pubspec named,boxComponent,circleComponent,andassetComponent, ensure thatandroid/settings.gradlecontains the following:

    android/settings.gradle.kts
    kotlin
    include(":app",":boxComponent",":circleComponent",":assetComponent")...
    android/settings.gradle
    groovy
    include':app',':boxComponent',':circleComponent',':assetComponent'...
  6. Repeat steps3.1 through 3.6 (this step)until all validator recommendations are handled and the toolruns without further recommendations.

    When successful, this command outputs anapp-release.aabfile inbuild/app/outputs/bundle/release.

    A successful build doesn't always mean the app wasbuilt as intended. It is up to you to ensure that all loadingunits and Dart libraries are included in the way you intended.For example, a common mistake is accidentally importing aDart library without thedeferred keyword,resulting in a deferred library being compiled as part ofthe base loading unit. In this case, the Dart library wouldload properly because it is always present in the base,and the library wouldn't be split off. This can be checkedby examining thedeferred_components_loading_units.yamlfile to verify that the generated loading units are describedas intended.

    When adjusting the deferred components configurations,or making Dart changes that add, modify, or remove loading units,you should expect the validator to fail.Follow steps3.1 through 3.6 (this step) to apply anyrecommended changes to continue the build.

Running the app locally

#

Once your app has successfully built an AAB file, use Android'sbundletool to perform local testing with the--local-testing flag.

To run the AAB file on a test device, download the bundletool jar executable fromgithub.com/google/bundletool/releases and run:

java -jar bundletool.jar build-apks --bundle=<your_app_project_dir>/build/app/outputs/bundle/release/app-release.aab --output=<your_temp_dir>/app.apks --local-testingjava -jar bundletool.jar install-apks --apks=<your_temp_dir>/app.apks

Where<your_app_project_dir> is the path to your app's project directory and<your_temp_dir> is any temporary directory used to store the outputs of bundletool. This unpacks your AAB file into an APK file and installs it on the device. All available Android dynamic features are loaded onto the device locally and installation of deferred components is emulated.

Before runningbuild-apks again, remove the existing app APK file:

rm <your_temp_dir>/app.apks

Changes to the Dart codebase require either incrementing the Android build ID or uninstalling and reinstalling the app, as Android won't update the feature modules unless it detects a new version number.

Releasing to the Google Play Store

#

The built AAB file can be uploaded directly to the Play store as normal. WhenloadLibrary() is called, the needed Android module containing the Dart AOT library and assets is downloaded by the Flutter engine using the Play store's delivery feature.

Was this page's content helpful?

Unless stated otherwise, the documentation on this site reflects Flutter 3.38.6. Page last updated on 2026-02-07.View source orreport an issue.


[8]ページ先頭

©2009-2026 Movatter.jp