Contributing to Flutter — part 3

Fabio de Matos
Flutter Community
Published in
5 min readMay 24, 2018

The tale of PR #16413 aka scan folders for all its assets.

Here’s the tale of Flutter PR #16413, who enables developers to add lots of assets by simply adding their folder name on pubspec.yaml. It lived for 1 month 13 days 😨. Nothing compared to its parent Issue #4890, which was getting near it’s second birthday 😵 when it got closed!

Here’s a glimpse of what it can and cannot do. And why.

Imagine you have dozens or hundreds of images or json files that you want to bundle with your flutter app. Before this feature you had to do something like the flutter_svg package (https://github.com/dnfield/flutter_svg.git) :

. . .  assets:    - assets/flutter_logo.svg    - assets/dart.svg    - assets/w3samples/alphachannel.svg    - assets/w3samples/aa.svg    - assets/deborah_ufw/new-action-expander.svg    - assets/deborah_ufw/new-camera.svg    - assets/deborah_ufw/new-gif-button.svg    - assets/deborah_ufw/new-gif.svg    - assets/deborah_ufw/new-image.svg    - assets/deborah_ufw/new-mention.svg    - assets/deborah_ufw/new-pause-button.svg    - assets/deborah_ufw/new-play-button.svg    - assets/deborah_ufw/new-send-circle.svg    - assets/deborah_ufw/numeric_25.svg    - assets/simple/clip_path_3.svg    - assets/simple/clip_path_2.svg    - assets/simple/clip_path.svg    - assets/simple/ellipse.svg    - assets/simple/group_opacity.svg    - assets/simple/nested_group.svg    - assets/simple/rect_rrect.svg    - assets/simple/linear_gradient.svg    - assets/simple/linear_gradient_2.svg    - assets/simple/radial_gradient.svg    - assets/simple/dash_path.svg    - assets/simple/text.svg    - assets/simple/style_attr.svg    - assets/wikimedia/Ghostscript_Tiger.svg    - assets/wikimedia/chess_knight.svg    - assets/android_vd/battery_charging.xml. . .

There are exactly 29 lines dedicated assets, one per file present on disk. How nice would it be if we could make that shorter? With this feature it’s enough to specify the folder followed by a /

. . .  assets:    - assets/    - assets/w3samples/    - assets/deborah_ufw/    - assets/simple/    - assets/wikimedia/    - assets/android_vd/. . .

That’s the gist of it, and although not perfect I hope it helps a lot.

Why can’t it do X?

Now, a common question is why not specify simply -assets/ and support recursive scanning, globbing and wildcards as originally suggested? In the ideal case the above project could simply reference the parent folder and Flutter would take care of finding all the assets:

. . .  assets:    - assets/. . .

Easy right? Well…

The reason is how variants are handled in Flutter, which makes it tricky. Variant is a name used in Android to cover differences in phone resolutions among other things. A quick Flutter example: if you include both files assets/foobar.png and assets/3.0x/foobar.png they should be automatically linked, and one should be used for low-res phones while the second would be chosen on flagship ones (better examples at the official docs). And by doing a naive implementation of subdirectory scanning we could end up having 2 unlinked assets and fail to use the high-res assets/3.0x/foobar.png at the appropriate places, having the user seeing the less beautiful version. That’s the short story.

A slightly smarter implementation could use some regex to identify that those 2 files are linked. As easy as it sounds it can bring a couple unexpected surprises if both the scanning (build time) and painting (run time) code don’t agree. Adding to it that currently in Flutter variants are used exclusively for image resolution, but if later it’s expanded in a similar way as in Android to cover things such as localization, screen size or orientation, and we could end up in a situation where upgrading the flutter version could break your build. Consider the hypotetical files:

assets/hero.pngassets/3.0x/hero.pngassets/landscape/hero.pngassets/landscape/3.0x/hero.png

Today it means that we’re talking about 2 assets — assets/hero.png and assets/landscape/hero.png, as well as a their 3.0 variants. But it’s not possible to guarantee that a future flutter feature (😮 pun intended) will decide to handle landscape variants, which could potentially misinterpret the developers’ intentions and treat those 4 files as one asset + 3 variants. The result would probably be detected when the app tries to reference those files, which makes it quite tricky to detect, specially if the developer is not aware of the change in behaviour.

There is at least one solution to this problem, but it’s much better to enjoy the non-controversial part of the feature before getting it perfect, right?

How do I benefit from it?

Any time you have multiple asset files in the same folder you can stop adding them one by one and simply add their folder name, followed by /. If you forget to add that character at the end there will be a nice error message: “No file or variants found for asset: assets/images”. That’s the same message when you mention a file that doesn’t exist, because Flutter doesn’t know you would like it to be treated as a folder.

Also now that the role of image variants is clear, remember to always pack hi-res images for those nice devices with high dpi. For reference, the ideal situation is adding files for 1.0x ( asset/filename.png) as well as 2.0x and 3.0x (asset/2.0x/filename.pngand asset/3.0x/filename.png). But if you want to add a single file for each asset you should skip the 1.0x resolution and just include the 3.0x version. When adding the folder to pubspec.yaml you will still reference the 1.0x variant AS IF it were present on disk (-asset/), and Flutter will understand that only the 3.0x variant should be used in all devices no matter what.

A nice alternative is using svg format through the flutter_svg package, which is better both because these files are smaller and also because it has less problems with rescaling for the exact resolution of the phone. It may use a bit more of CPU and battery in the typical case, but that’s a small price to pay for the benefits.

How do I use it with font files?

This is actually a completely separated feature, because of the way the schema for fonts work. Fonts a) need the developer to specify the font family name as a string, and b) have optional parameters for font weight, things get a bit more complex. It’s definitely possible to come up with something better, but that’s a subject for another PR.

What’s in the future?

As I write this is feature about to travel from master channel to the dev channel, until it eventually reaches beta. Big thanks to github user @tvolkert who had a LOT of patience to get me out of all the rabbit wholes every time I got lost.

What do I see coming next?

- Documentation will be updated as soon as the feature reaches beta

- Analyzer currently tells us things like “warning: The asset assets/w3samples/ does not exist. (asset_does_not_exist at [flutter_svg] pubspec.yaml:38)

- Adoption by developers ;)

- Stop using strings to reference images and assets (the idea is for developers to stop using new Image.asset("asset/folder/filename.png") and start using something likenew Image.asset(AppPackage.filename);

- Scan for font files and use some heuristics to figure out family name and font weight automatically; encourage developers to stop referencing them by strings in dart code similar to the proposed new feature for images

- And subdirectory scanning, globbing and wildcards

I’m open to ideas, and the Flutter team accepts PRs, so if anyone feels there’s something important or urgent missing there’s the opportunity to step in and do it.

--

--