Introduction

Flutter apps can include both code and assets (sometimes called resources). An asset is a file that is bundled and deployed with your app, and is accessible at runtime. Common types of assets include static data (for example, JSON files), configuration files, icons, and images.

Specifying assets

Flutter uses the flutter.yaml file, located at the root of your project, to identify assets required by an app.

Here is an example:

assets:
  - assets/my_icon.png
  - assets/background.png

The assets section specifies files that should be included with the app. Each asset is identified by an explicit path (relative to the flutter.yaml file) where the asset file is located. The order in which the assets are declared does not matter.

During a build, Flutter places assets into a special archive called the asset bundle, which apps can read from at runtime.

Asset variants

The build process supports the notion of asset variants: different versions of an asset that might be displayed in different contexts. When an asset’s path is specified in the assets section of flutter.yaml, the build process looks for any files with the same name in adjacent subdirectories. Such files are then included in the asset bundle along with the specified asset.

For example, if you have the following assets:

  - assets/my_icon.png
  - assets/background.png

and your flutter.yaml file contains:

assets:
  - assets/background.png

then both assets/background.png and assets/dark/background.png will be included in your asset bundle. The former is considered the main asset, while the latter is considered a variant.

Flutter uses asset variants when choosing resolution appropriate images; see below. In the future, this mechanism may be extended to include variants for different locales or regions, reading directions, etc.

Loading assets

Your app can access its assets through an AssetBundle object.

The two main methods on an asset bundle allow you to load a string/text asset (loadString) or an image/binary asset (load) out of the bundle, given a logical key. The logical key maps to the path to the asset specified in the flutter.yaml file at build time.

Loading text assets

Each Flutter app has a rootBundle object for easy access to the main asset bundle. It is possible to load assets directly using the rootBundle global static from package:flutter/services.dart.

However, it’s recommended to obtain the AssetBundle for the current BuildContext using DefaultAssetBundle. Rather than the default asset bundle that was built with the app, this approach enables a parent widget to substitute a different AssetBundle at run time, which can be useful for localization or testing scenarios.

Typically, you’ll use DefaultAssetBundle.of() to indirectly load a JSON file asset from the app’s runtime rootBundle.

Or, use rootBundle to directly load a JSON file asset that was specified at build time, for example:

import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;

Future<String> loadAsset() async {
  return await rootBundle.loadString('assets/config.json');
}

Loading image images

Flutter can load resolution-appropriate images for the current device pixel ratio.

Declaring resolution-aware image assets

AssetImage understands how to map a logical requested asset onto one that most closely matches the current device pixel ratio. In order for this mapping to work, assets should be arranged according to a particular directory structure:

  • …/image.png
  • …/Mx/image.png
  • …/Nx/image.png
  • …etc.

Where M and N are numeric identifiers that correspond to the nominal resolution of the images contained within. The main asset is assumed to correspond to a resolution of 1.0. For example, consider the following asset layout for an image named my_icon.png:

  • …/my_icon.png
  • …/2.0x/my_icon.png
  • …/3.0x/my_icon.png

On devices with a device pixel ratio of 1.8, the asset .../2.0x/my_icon.png would be chosen. For a device pixel ratio of 2.7, the asset .../3.0x/my_icon.png would be chosen.

If the width and height of the rendered image are not specified, the nominal resolution is used to scale the asset so that it will occupy the same amount of screen space as the main asset would have, just with a higher resolution. That is, if .../my_icon.png is 72px by 72px, then .../3.0x/my_icon.png should be 216px by 216px; but they both will render into 72px by 72px (in logical pixels) if width and height are not specified.

Loading images

To load an image, use the AssetImage class in a widget’s build method.

For example, your app can load the dark background image from the asset declarations above:

Widget build(BuildContext context) {
  // ...
  return new DecoratedBox(
    decoration: new BoxDecoration(
      backgroundImage: new BackgroundImage(
        image: new AssetImage('assets/my_asset.png'),
        // ...
      ),
      // ...
    ),
  );
  // ...
}

The way this works is through an object called AssetImage established at the top of the build tree. AssetImage fetches an image from an AssetBundle, based on the context.

Anything using the default asset bundle will inherit resolution awareness when loading images. (If you work with some of the lower level classes, like ImageStream or ImageCache, you’ll also notice parameters related to scale.)