How to access asset file in pure dart package?

374

It is "impossible" at the first look, because the Dart package can be used anywhere - e.g. used in a non-Flutter environment. Then there is really no way to find it.

However, there is a workaround: The inverse of control. Example code:

// pure dart package

abstract class AbstractAssetFileFetcherService {
  String getAssetFileContent(String assetName);
}

AbstractAssetFileFetcherService? service;

void myFunctionThatUsesAssetFile() {
  var myFirstFileContent = service.getAssetFileContent('my-first-file-name.png');
  var mySecondFileContent = service.getAssetFileContent('my-second-file-name.json');
  // ... use the file content happily ...
}

And in the Flutter package which you want to use the pure-dart package:

void main() {
  service = AssetFileFetcherService(); // or use other IoC methods such as the `GetIt` Dart package
  myFunctionThatUsesAssetFile();
}

class AssetFileFetcherService extends AbstractAssetFileFetcherService {
  String getAssetFileContent(String assetName) {
    return rootBundle.loadString(assetName); // just use any normal method. you are in Flutter environment here.
  }
}

EDIT

Asset files of Flutter may not exist anywhere in the disk path - it can be compressed in the apk (android) file for example. In addition, you may not have sufficient permissions to do so.

https://flutter.dev/docs/development/ui/assets-and-images#asset-bundling

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

Share:
374
tmaihoff
Author by

tmaihoff

Updated on December 30, 2022

Comments

  • tmaihoff
    tmaihoff over 1 year

    Original Question

    I wrote a dart package which is being used by my flutter application. Inside the dart package I want to store some static data in a json file which I want to read from the dart package code.

    However I can't find a way to access asset files directly from a dart package. Using the File(path).readAsString() only works for dart console applications and using the rootBundle only works for flutter packages/applications.

    My question is: How can I access this file which is stored in the dart package assets directly from the pure dart package?

    In a flutter package I would simply make the file available via pubspec.yml like this

    flutter:
       assets:
          - lib/assets/b737.json
    

    But I could not find a similar solution for a pure dart package.

    Any help is appreciated.

    Answer

    After long research and nice help from the community this feature simply doesn't seem to exist.

    But there are workarounds:

    Load from Flutter project and pass read string to dart package

    Load the asset file from the flutter project via rootBundle.loadString() and specify the asset file in the flutter pubspec.yaml and pass the string data to the dart package. Check ch271828n's answer for details

    Make it a flutter package

    An easy solution is to convert the pure dart package to a flutter package. Then it's not pure dart anymore, but that doesn't always hurt. Especially, when the package is used inside another flutter project/package.

    Save the raw data in a variable

    Instead of providing asset files and reading the content at runtime, you can also directly safe the asset file content to a static const variable. For bigger assets however this might slow down your IDE if it indexes hundrets of thousands of lines from the assets. Excluding these files from the analyzer might help: analysis_options.dart

    analyzer:
      exclude:
        - '**/assets/data/**'
    

    aspen package

    You can also checkout the aspen package which assists with the previous solution. You specify the paths of the assets and via code generation the contents of these files are then saved to variables which are directly available from the code.

    part 'assets.g.dart';
    
    // @Asset is an annotation from package:aspen that marks the asset to be packed.
    @Asset('asset:my_package/web/my-asset.txt')
    // We create a const (it must be const!) value that holds the generated asset content.
    const myTextAsset = TextAsset(text: _myTextAsset$content);