Search code examples
javaandroidflutterassetsflutter-plugin

How *Exactly* to Access Flutter Assets From Within Android Java *Plugin* Platform Code?


We want to define a Flutter asset that can be accessed from the Android platform code within the same plugin. The documentation for this is purported to be here.

Please note we are NOT talking about custom platform code within a flutter app -- we are talking about flutter plugin code from the perspective of the plugin author.

So, following the docs, we start with the pubspec.yaml file for our plugin which exists at [your_plugin_root_dir]\pubspec.yaml, and we add the asset definition:

  assets:
    - assets/sound.wav

This points to an existing file at [your_plugin_root_dir]\assets\sound.wav

All good so far, but then we have a problem:

When you create a new Flutter Plugin project in Android studio, the Android Java file for the plugin looks like this:

public class PluginTestPlugin implements FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "plugin_test");
    channel.setMethodCallHandler(this);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }
}

And in order to access your asset from within that code, the docs suggest adding this code:

AssetManager assetManager = registrar.context().getAssets();
String key = registrar.lookupKeyForAsset("assets/sound.wav");
AssetFileDescriptor fd = assetManager.openFd(key);

But since there is no "registrar" instance that exists in that code, and the documentation doesn't describe how it was created or how to access it, I'm lost.

What am I missing here????


Solution

  • Add another field next to the method channel, to keep hold of the binding;

    private MethodChannel channel;
    
    private FlutterPluginBinding binding;
    

    In onAttachedToEngine set it:

    channel.setMethodCallHandler(this);
    binding = flutterPluginBinding;
    

    And clear it in onDetached

    channel.setMethodCallHandler(null);
    binding = null;
    

    Then use it like this (for the purposes of this I added an asset to the plugin (not the example app) called assets/foo.bin, and my plugin name is plugin1)

            String assetPath = binding
                    .getFlutterAssets()
                    .getAssetFilePathBySubpath("assets/foo.bin", "plugin1");
            try {
                InputStream is = binding.getApplicationContext().getAssets().open(assetPath);
                // todo - read the asset into memory or whatever
                is.close();
            } catch (IOException e) {
                Log.e("plugin1", e.getMessage());
            }
    

    The pubspec.yaml of the plugin project needs extra lines to package the asset as follows, after the plugin section:

      plugin:
        platforms:
          android:
            package: io.swhh.plugin1
            pluginClass: Plugin1Plugin
          ios:
            pluginClass: Plugin1Plugin
    
      assets:
        - assets/foo.bin
    

    You may be interested in the equivalent in iOS (excuse the lack of error handling)

      let key = FlutterDartProject.lookupKey(forAsset: "assets/foo.bin", fromPackage: "plugin1")
      let path = Bundle.main.path(forResource: key, ofType: nil, inDirectory: nil)
      let url = URL(fileURLWithPath: path!)
      // use url to load the resource