diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java index 92d7586a32a70..82b64d696f13e 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java @@ -41,6 +41,7 @@ import io.flutter.embedding.engine.FlutterShellArgs; import io.flutter.plugin.platform.PlatformPlugin; import io.flutter.view.FlutterMain; +import java.lang.reflect.Method; /** * A Flutter {@code Activity} that is based upon {@link FragmentActivity}. @@ -555,13 +556,18 @@ public FlutterEngine provideFlutterEngine(@NonNull Context context) { } /** - * Hook for subclasses to easily configure a {@code FlutterEngine}, e.g., register plugins. + * Hook for subclasses to easily configure a {@code FlutterEngine}. * *

This method is called after {@link #provideFlutterEngine(Context)}. + * + *

All plugins listed in the app's pubspec are registered in the base implementation of this + * method. To avoid automatic plugin registration, override this method without invoking super(). + * To keep automatic plugin registration and further configure the flutterEngine, override this + * method, invoke super(), and then configure the flutterEngine as desired. */ @Override public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { - // No-op. Hook for subclasses. + registerPlugins(flutterEngine); } /** @@ -698,4 +704,34 @@ protected BackgroundMode getBackgroundMode() { private boolean isDebuggable() { return (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; } + + /** + * Registers all plugins that an app lists in its pubspec.yaml. + * + *

The Flutter tool generates a class called GeneratedPluginRegistrant, which includes the code + * necessary to register every plugin in the pubspec.yaml with a given {@code FlutterEngine}. The + * GeneratedPluginRegistrant must be generated per app, because each app uses different sets of + * plugins. Therefore, the Android embedding cannot place a compile-time dependency on this + * generated class. This method uses reflection to attempt to locate the generated file and then + * use it at runtime. + * + *

This method fizzles if the GeneratedPluginRegistrant cannot be found or invoked. This + * situation should never occur, but if any eventuality comes up that prevents an app from using + * this behavior, that app can still write code that explicitly registers plugins. + */ + private static void registerPlugins(@NonNull FlutterEngine flutterEngine) { + try { + Class generatedPluginRegistrant = + Class.forName("io.flutter.plugins.GeneratedPluginRegistrant"); + Method registrationMethod = + generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class); + registrationMethod.invoke(null, flutterEngine); + } catch (Exception e) { + Log.w( + TAG, + "Tried to automatically register plugins with FlutterEngine (" + + flutterEngine + + ") but could not find and invoke the GeneratedPluginRegistrant."); + } + } }