Skip to content

assetLoader not invoked for Referenced assets #586

@DeToxer

Description

@DeToxer

Description

When using Rive Flutter runtime 0.14.0-dev.14 with a .riv file that contains an image asset, the assetLoader callback passed to File.asset is only invoked when the image’s export options in the Rive Editor are set to:

  • Type: Embedded + Behavior: Automatic, or
  • Type: Embedded + Behavior: Force Export

For any other combination (in particular when using Type: Referenced), the assetLoader callback is never called for that image asset.

My understanding from the docs is that assetLoader should be invoked for every asset the runtime detects in the .riv file, regardless of whether the asset is embedded or referenced, so that the app can provide bytes when needed (e.g. for referenced assets, where bytes would be null/empty and the app can supply them).

Right now that does not seem to be the case in 0.14.0-dev.14, and it appears tied to the export options used in the Rive Editor.

Steps To Reproduce

  1. In Rive Editor:
  • Create a new file with a single artboard and a simple animation.
  • Import an image asset (e.g. example_image.webp or example_image.png).
  • Place the image on the artboard so that it is clearly in use in the animation.
  • In the image’s Export Options:
    • Set Type: Embedded, Behavior: Automatic.
  • Export the file via Export for Runtimes and place the resulting .riv in a Flutter project (e.g. assets/rive/example.riv).
  1. In Flutter (rive: 0.14.0-dev.14)
  • Add the .riv to pubspec.yaml under assets:
  • Use a minimal widget that loads the file with File.asset and an assetLoader that logs every asset:
class RiveAssetLoaderDemo extends StatefulWidget {
  const RiveAssetLoaderDemo({super.key});

  @override
  State<RiveAssetLoaderDemo> createState() => _RiveAssetLoaderDemoState();
}

class _RiveAssetLoaderDemoState extends State<RiveAssetLoaderDemo> {
  FileLoader? _fileLoader;
  bool _initializing = true;

  @override
  void initState() {
    super.initState();
    _loadFile();
  }

  Future<void> _loadFile() async {
    final file = await File.asset(
      'path/to/animation/',
      riveFactory: Factory.rive,
      assetLoader: (FileAsset asset, Uint8List? bytes) {
        final msg = 'assetLoader: name=${asset.name}, ext=${asset.fileExtension}';
        debugPrint(msg);
        return false;
      },
    );

    if (!mounted || file == null) {
      setState(() => _initializing = false);
      return;
    }

    setState(() {
      _fileLoader = FileLoader.fromFile(
        file,
        riveFactory: Factory.rive,
      );
      _initializing = false;
    });
  }

  @override
  void dispose() {
    _fileLoader?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_initializing || _fileLoader == null) {
      return const Center(child: CircularProgressIndicator());
    }

    return Column(
      children: [
        Expanded(
          child: RiveWidgetBuilder(
            fileLoader: _fileLoader!,
            artboardSelector: ArtboardSelector.byIndex(0),
            stateMachineSelector: StateMachineSelector.byDefault(),
            dataBind: DataBind.auto(),
            builder: (context, state) => switch (state) {
              RiveLoading() => const Center(
                child: CircularProgressIndicator(),
              ),
              RiveFailed() => Center(
                child: Text('Failed: ${state.error}'),
              ),
              RiveLoaded() => RiveWidget(
                controller: state.controller,
                fit: Fit.contain,
              ),
            },
          ),
        ),
      ],
    );
  }
}
  • Run the app and check the console.

Observe that only these two combinations of export options does a console log:
Type: Embedded + Behavior: Automatic
Embedded + Behavior: Force Export

Now re-test with other combinaitons of export options:

  • Type: Referenced + Behavior: Include in Export / Automatic
  • Type: Referenced + Behavior: Force Export
  • Type: Embedded + Behavior: Prevent Export
  • Type: Referenced + Behavior: Prevent Export

For all combinations other than Embedded + Automatic and Embedded + Force Export, assetLoader is never invoked for the image asset (no log lines for that asset).
This is true even in cases where my expectation is that the asset should still exist in the file as a referenced asset and therefore be visible to the runtime (e.g. Type: Referenced + non-“Prevent Export” behavior).

Source .riv/.rev file

I have attached the runtime-exported .riv files that reproduce the issue. I'll also add the corresponding .rev backup file from the Editor.

rev_file.zip
rive_files.zip

Expected behavior

My understanding from the 0.14 runtime docs is that the assetLoader callback passed to File.asset should be called for every asset the runtime detects from the .riv file on load, regardless of how the asset’s Type is configured (Embedded vs Referenced), and regardless of the Behavior as long as the asset is actually present in the exported file.

Screenshots

Not applicable

Device & Versions (please complete the following information)

  • Device: Android Pixel 10 Pro (physical device)
  • OS: Android SDK API Level 36 (Android 16)
  • Flutter Version:
Flutter 3.38.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 19074d12f7 (2 weeks ago) • 2025-11-20 17:53:13 -0500
Engine • hash 8bf2090718fea3655f466049a757f823898f0ad1 (revision 13e658725d) (13 days ago) • 2025-11-20 20:19:23.000Z
Tools • Dart 3.10.1 • DevTools 2.51.1

Additional context

  • The same .riv files display correctly in the Rive Editor.
  • From the app side, the wiring appears correct because assetLoader does fire for embedded assets; it’s specifically other export option combinations that cause it not to be invoked.
  • My goal is to use Referenced image assets and provide the image bytes at runtime from Flutter (via AssetBundle), but this currently seems impossible because the runtime never calls assetLoader for those assets in 0.14.0-dev.14.
  • If there is a misunderstanding of how the new 0.14 runtime is intended to behave with respect to assetLoader and export options, clarification in the docs would also be very helpful.

Cheers!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions