Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit fec9573

Browse files
Prevent duplicate plugin registration in FlutterEnginePluginRegistry. (#49365) (#15956)
1 parent 9ee917c commit fec9573

File tree

4 files changed

+89
-0
lines changed

4 files changed

+89
-0
lines changed

shell/platform/android/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ action("robolectric_tests") {
421421
"test/io/flutter/embedding/android/FlutterViewTest.java",
422422
"test/io/flutter/embedding/android/RobolectricFlutterActivity.java",
423423
"test/io/flutter/embedding/engine/FlutterEngineCacheTest.java",
424+
"test/io/flutter/embedding/engine/FlutterEnginePluginRegistryTest.java",
424425
"test/io/flutter/embedding/engine/FlutterEngineTest.java",
425426
"test/io/flutter/embedding/engine/FlutterJNITest.java",
426427
"test/io/flutter/embedding/engine/FlutterShellArgsTest.java",

shell/platform/android/io/flutter/embedding/engine/FlutterEnginePluginRegistry.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ public void destroy() {
117117

118118
@Override
119119
public void add(@NonNull FlutterPlugin plugin) {
120+
if (has(plugin.getClass())) {
121+
Log.w(TAG, "Attempted to register plugin (" + plugin +") but it was "
122+
+ "already registered with this FlutterEngine (" + flutterEngine + ").");
123+
return;
124+
}
125+
120126
Log.v(TAG, "Adding plugin: " + plugin);
121127
// Add the plugin to our generic set of plugins and notify the plugin
122128
// that is has been attached to an engine.

shell/platform/android/test/io/flutter/FlutterTestSuite.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import io.flutter.embedding.android.FlutterFragmentTest;
1414
import io.flutter.embedding.android.FlutterViewTest;
1515
import io.flutter.embedding.engine.FlutterEngineCacheTest;
16+
import io.flutter.embedding.engine.FlutterEnginePluginRegistryTest;
1617
import io.flutter.embedding.engine.FlutterJNITest;
1718
import io.flutter.embedding.engine.RenderingComponentTest;
1819
import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistryTest;
@@ -35,6 +36,7 @@
3536
FlutterActivityTest.class,
3637
FlutterAndroidComponentTest.class,
3738
FlutterEngineCacheTest.class,
39+
FlutterEnginePluginRegistryTest.class,
3840
FlutterEngineTest.class,
3941
FlutterFragmentTest.class,
4042
FlutterJNITest.class,
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package io.flutter.embedding.engine;
2+
3+
import android.content.Context;
4+
import android.support.annotation.NonNull;
5+
6+
import org.junit.Test;
7+
import org.junit.runner.RunWith;
8+
import org.robolectric.RobolectricTestRunner;
9+
import org.robolectric.annotation.Config;
10+
11+
import io.flutter.embedding.engine.loader.FlutterLoader;
12+
import io.flutter.embedding.engine.plugins.FlutterPlugin;
13+
import io.flutter.plugin.platform.PlatformViewsController;
14+
15+
import static junit.framework.TestCase.assertTrue;
16+
import static org.junit.Assert.assertEquals;
17+
import static org.junit.Assert.assertFalse;
18+
import static org.mockito.Mockito.mock;
19+
import static org.mockito.Mockito.when;
20+
21+
// Run with Robolectric so that Log calls don't crash.
22+
@Config(manifest=Config.NONE)
23+
@RunWith(RobolectricTestRunner.class)
24+
public class FlutterEnginePluginRegistryTest {
25+
@Test
26+
public void itDoesNotRegisterTheSamePluginTwice() {
27+
Context context = mock(Context.class);
28+
29+
FlutterEngine flutterEngine = mock(FlutterEngine.class);
30+
PlatformViewsController platformViewsController = mock(PlatformViewsController.class);
31+
when(flutterEngine.getPlatformViewsController()).thenReturn(platformViewsController);
32+
33+
FlutterLoader flutterLoader = mock(FlutterLoader.class);
34+
35+
FakeFlutterPlugin fakePlugin1 = new FakeFlutterPlugin();
36+
FakeFlutterPlugin fakePlugin2 = new FakeFlutterPlugin();
37+
38+
FlutterEnginePluginRegistry registry = new FlutterEnginePluginRegistry(
39+
context,
40+
flutterEngine,
41+
flutterLoader
42+
);
43+
44+
// Verify that the registry doesn't think it contains our plugin yet.
45+
assertFalse(registry.has(fakePlugin1.getClass()));
46+
47+
// Add our plugin to the registry.
48+
registry.add(fakePlugin1);
49+
50+
// Verify that the registry now thinks it contains our plugin.
51+
assertTrue(registry.has(fakePlugin1.getClass()));
52+
assertEquals(1, fakePlugin1.attachmentCallCount);
53+
54+
// Add a different instance of the same plugin class.
55+
registry.add(fakePlugin2);
56+
57+
// Verify that the registry did not detach the 1st plugin, and
58+
// it did not attach the 2nd plugin.
59+
assertEquals(1, fakePlugin1.attachmentCallCount);
60+
assertEquals(0, fakePlugin1.detachmentCallCount);
61+
62+
assertEquals(0, fakePlugin2.attachmentCallCount);
63+
assertEquals(0, fakePlugin2.detachmentCallCount);
64+
}
65+
66+
private static class FakeFlutterPlugin implements FlutterPlugin {
67+
public int attachmentCallCount = 0;
68+
public int detachmentCallCount = 0;
69+
70+
@Override
71+
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
72+
attachmentCallCount += 1;
73+
}
74+
75+
@Override
76+
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
77+
detachmentCallCount += 1;
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)