tmaihoff
tmaihoff

Reputation: 3550

How to access asset file in pure dart package?

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.

Upvotes: 8

Views: 1862

Answers (5)

tmaihoff
tmaihoff

Reputation: 3550

Summary of solutions

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);

Upvotes: 2

jamesdlin
jamesdlin

Reputation: 89975

As an unintended alternative to the aspen package, I wrote a resource_importer package that also uses code generation to store data as literals. (I perhaps wouldn't have written it if I were aware of aspen at the time. Alas.)

Usage is a bit different; assets are specified via pubspec.yaml. For example:

resource_importer:
  resources:
    myImage: 'assets/image.png'
    myLicense:
      path: 'LICENSE'
      type: String

Upvotes: 0

ch271828n
ch271828n

Reputation: 17587

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.

Upvotes: 3

Marius Atasiei
Marius Atasiei

Reputation: 305

Try this:

final stringData = await File('data.json').readAsString();
final data = json.decode(stringData);

Upvotes: 0

Fabio Campos
Fabio Campos

Reputation: 86

Acounding the documentation you should use the rootBundle to load your json:

String   jsonString =  await rootBundle.loadString('assets/b737.json');
  

If you are using it inside an Widget its recomended to user DefaultAssetBundle.of(context)

String jsonString = await DefaultAssetBundle
      .of(context)
      .loadString("assets/b737.json");

Upvotes: 0

Related Questions