diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 389d3af06afdb..3d7f197dcfeeb 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -20,7 +20,6 @@ import io.flutter.embedding.engine.plugins.broadcastreceiver.BroadcastReceiverControlSurface; import io.flutter.embedding.engine.plugins.contentprovider.ContentProviderControlSurface; import io.flutter.embedding.engine.plugins.service.ServiceControlSurface; -import io.flutter.embedding.engine.plugins.util.GeneratedPluginRegister; import io.flutter.embedding.engine.renderer.FlutterRenderer; import io.flutter.embedding.engine.renderer.RenderSurface; import io.flutter.embedding.engine.systemchannels.AccessibilityChannel; @@ -37,6 +36,7 @@ import io.flutter.embedding.engine.systemchannels.TextInputChannel; import io.flutter.plugin.localization.LocalizationPlugin; import io.flutter.plugin.platform.PlatformViewsController; +import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; @@ -342,7 +342,7 @@ public FlutterEngine( // Only automatically register plugins if both constructor parameter and // loaded AndroidManifest config turn this feature on. if (automaticallyRegisterPlugins && flutterLoader.automaticallyRegisterPlugins()) { - GeneratedPluginRegister.registerGeneratedPlugins(this); + registerPlugins(); } } @@ -391,6 +391,36 @@ private boolean isAttachedToJni() { newFlutterJNI); // FlutterJNI. } + /** + * 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 void registerPlugins() {
+ try {
+ Class> generatedPluginRegistrant =
+ Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
+ Method registrationMethod =
+ generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
+ registrationMethod.invoke(null, this);
+ } catch (Exception e) {
+ Log.w(
+ TAG,
+ "Tried to automatically register plugins with FlutterEngine ("
+ + this
+ + ") but could not find and invoke the GeneratedPluginRegistrant.");
+ }
+ }
+
/**
* Cleans up all components within this {@code FlutterEngine} and destroys the associated Dart
* Isolate. All state held by the Dart Isolate, such as the Flutter Elements tree, is lost.
diff --git a/shell/platform/android/io/flutter/embedding/engine/plugins/util/GeneratedPluginRegister.java b/shell/platform/android/io/flutter/embedding/engine/plugins/util/GeneratedPluginRegister.java
index fab7eb8c7ee65..5bb0ff5a6f37b 100644
--- a/shell/platform/android/io/flutter/embedding/engine/plugins/util/GeneratedPluginRegister.java
+++ b/shell/platform/android/io/flutter/embedding/engine/plugins/util/GeneratedPluginRegister.java
@@ -33,15 +33,11 @@ public static void registerGeneratedPlugins(@NonNull FlutterEngine flutterEngine
generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
registrationMethod.invoke(null, flutterEngine);
} catch (Exception e) {
- Log.e(
+ Log.w(
TAG,
"Tried to automatically register plugins with FlutterEngine ("
+ flutterEngine
+ ") but could not find and invoke the GeneratedPluginRegistrant.");
- Log.e(
- TAG,
- // getCause here because the first layer of the exception would be from reflect.
- "Received exception while registering: " + e.getCause());
}
}
}
diff --git a/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java b/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java
index 1af79de943259..bcfabf863dafe 100644
--- a/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java
+++ b/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java
@@ -35,7 +35,6 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowLog;
@Config(manifest = Config.NONE)
@RunWith(RobolectricTestRunner.class)
@@ -64,9 +63,6 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
@After
public void tearDown() {
GeneratedPluginRegistrant.clearRegisteredEngines();
- // Make sure to not forget to remove the mock exception in the generated plugin registration
- // mock, or everything subsequent will break.
- GeneratedPluginRegistrant.pluginRegistrationException = null;
}
@Test
@@ -82,38 +78,6 @@ public void itAutomaticallyRegistersPluginsByDefault() {
assertEquals(flutterEngine, registeredEngines.get(0));
}
- // Helps show the root cause of MissingPluginException type errors like
- // https://github.com/flutter/flutter/issues/78625.
- @Test
- public void itCatchesAndDisplaysRegistrationExceptions() {
- assertTrue(GeneratedPluginRegistrant.getRegisteredEngines().isEmpty());
- GeneratedPluginRegistrant.pluginRegistrationException =
- new RuntimeException("I'm a bug in the plugin");
- FlutterLoader mockFlutterLoader = mock(FlutterLoader.class);
- when(mockFlutterLoader.automaticallyRegisterPlugins()).thenReturn(true);
- FlutterEngine flutterEngine =
- new FlutterEngine(RuntimeEnvironment.application, mockFlutterLoader, flutterJNI);
-
- List