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

Commit 36a8dc3

Browse files
committed
Started using FlutterEngineGroups by default on Android and making
them accessible to plugins.
1 parent 1fcbb9c commit 36a8dc3

11 files changed

+116
-16
lines changed

shell/platform/android/io/flutter/embedding/android/FlutterActivity.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@
149149
*
150150
* <pre>{@code
151151
* // Create and pre-warm a FlutterEngine.
152-
* FlutterEngine flutterEngine = new FlutterEngine(context);
152+
* FlutterEngineGroup group = new FlutterEngineGroup(context);
153+
* FlutterEngine flutterEngine = group.createAndRunDefaultEngine(context);
153154
* flutterEngine.getDartExecutor().executeDartEntrypoint(DartEntrypoint.createDefault());
154155
*
155156
* // Cache the pre-warmed FlutterEngine in the FlutterEngineCache.

shell/platform/android/io/flutter/embedding/android/FlutterActivityAndFragmentDelegate.java

+17-5
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public interface DelegateFactory {
9090
private boolean isFirstFrameRendered;
9191
private boolean isAttached;
9292
private Integer previousVisibility;
93+
@Nullable private FlutterEngineGroup engineGroup;
9394

9495
@NonNull
9596
private final FlutterUiDisplayListener flutterUiDisplayListener =
@@ -109,8 +110,15 @@ public void onFlutterUiNoLongerDisplayed() {
109110
};
110111

111112
FlutterActivityAndFragmentDelegate(@NonNull Host host) {
113+
this(host, null);
114+
}
115+
116+
FlutterActivityAndFragmentDelegate(@NonNull Host host, @Nullable FlutterEngineGroup engineGroup) {
112117
this.host = host;
113118
this.isFirstFrameRendered = false;
119+
if (engineGroup != null) {
120+
this.engineGroup = engineGroup;
121+
}
114122
}
115123

116124
/**
@@ -298,12 +306,16 @@ void onAttach(@NonNull Context context) {
298306
TAG,
299307
"No preferred FlutterEngine was provided. Creating a new FlutterEngine for"
300308
+ " this FlutterFragment.");
309+
310+
FlutterEngineGroup group =
311+
engineGroup == null
312+
? new FlutterEngineGroup(host.getContext(), host.getFlutterShellArgs().toArray())
313+
: engineGroup;
301314
flutterEngine =
302-
new FlutterEngine(
303-
host.getContext(),
304-
host.getFlutterShellArgs().toArray(),
305-
/*automaticallyRegisterPlugins=*/ false,
306-
/*willProvideRestorationData=*/ host.shouldRestoreAndSaveState());
315+
group.createAndRunEngine(
316+
new FlutterEngineGroup.Options(host.getContext())
317+
.setAutomaticallyRegisterPlugins(false)
318+
.setWaitForRestorationData(host.shouldRestoreAndSaveState()));
307319
isFlutterEngineFromHost = false;
308320
}
309321

shell/platform/android/io/flutter/embedding/android/FlutterFragment.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
*
8080
* <pre>{@code
8181
* // Create and pre-warm a FlutterEngine.
82-
* FlutterEngine flutterEngine = new FlutterEngine(context);
82+
* FlutterEngineGroup group = new FlutterEngineGroup(context);
83+
* FlutterEngine flutterEngine = group.createAndRunDefaultEngine(context);
8384
* flutterEngine
8485
* .getDartExecutor()
8586
* .executeDartEntrypoint(DartEntrypoint.createDefault());

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

+24-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import android.content.res.AssetManager;
1010
import androidx.annotation.NonNull;
1111
import androidx.annotation.Nullable;
12+
import androidx.annotation.VisibleForTesting;
1213
import io.flutter.FlutterInjector;
1314
import io.flutter.Log;
1415
import io.flutter.embedding.engine.dart.DartExecutor;
@@ -279,6 +280,27 @@ public FlutterEngine(
279280
@Nullable String[] dartVmArgs,
280281
boolean automaticallyRegisterPlugins,
281282
boolean waitForRestorationData) {
283+
this(
284+
context,
285+
flutterLoader,
286+
flutterJNI,
287+
platformViewsController,
288+
dartVmArgs,
289+
automaticallyRegisterPlugins,
290+
waitForRestorationData,
291+
null);
292+
}
293+
294+
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
295+
public FlutterEngine(
296+
@NonNull Context context,
297+
@Nullable FlutterLoader flutterLoader,
298+
@NonNull FlutterJNI flutterJNI,
299+
@NonNull PlatformViewsController platformViewsController,
300+
@Nullable String[] dartVmArgs,
301+
boolean automaticallyRegisterPlugins,
302+
boolean waitForRestorationData,
303+
@Nullable FlutterEngineGroup group) {
282304
AssetManager assetManager;
283305
try {
284306
assetManager = context.createPackageContext(context.getPackageName(), 0).getAssets();
@@ -347,7 +369,8 @@ public FlutterEngine(
347369
this.platformViewsController.onAttachedToJNI();
348370

349371
this.pluginRegistry =
350-
new FlutterEngineConnectionRegistry(context.getApplicationContext(), this, flutterLoader);
372+
new FlutterEngineConnectionRegistry(
373+
context.getApplicationContext(), this, flutterLoader, group);
351374

352375
localizationPlugin.sendLocalesToFlutter(context.getResources().getConfiguration());
353376

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@
9797
FlutterEngineConnectionRegistry(
9898
@NonNull Context appContext,
9999
@NonNull FlutterEngine flutterEngine,
100-
@NonNull FlutterLoader flutterLoader) {
100+
@NonNull FlutterLoader flutterLoader,
101+
@Nullable FlutterEngineGroup group) {
101102
this.flutterEngine = flutterEngine;
102103
pluginBinding =
103104
new FlutterPlugin.FlutterPluginBinding(
@@ -106,7 +107,8 @@
106107
flutterEngine.getDartExecutor(),
107108
flutterEngine.getRenderer(),
108109
flutterEngine.getPlatformViewsController().getRegistry(),
109-
new DefaultFlutterAssets(flutterLoader));
110+
new DefaultFlutterAssets(flutterLoader),
111+
group);
110112
}
111113

112114
public void destroy() {

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ public void onEngineWillDestroy() {
210210
platformViewsController, // PlatformViewsController.
211211
null, // String[]. The Dart VM has already started, this arguments will have no effect.
212212
automaticallyRegisterPlugins, // boolean.
213-
waitForRestorationData); // boolean.
213+
waitForRestorationData, // boolean.
214+
this);
214215
}
215216

216217
/** Options that control how a FlutterEngine should be created. */

shell/platform/android/io/flutter/embedding/engine/plugins/FlutterPlugin.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
import android.content.Context;
88
import androidx.annotation.NonNull;
9+
import androidx.annotation.Nullable;
910
import androidx.lifecycle.Lifecycle;
1011
import io.flutter.embedding.engine.FlutterEngine;
12+
import io.flutter.embedding.engine.FlutterEngineGroup;
1113
import io.flutter.plugin.common.BinaryMessenger;
1214
import io.flutter.plugin.platform.PlatformViewRegistry;
1315
import io.flutter.view.TextureRegistry;
@@ -107,20 +109,23 @@ class FlutterPluginBinding {
107109
private final TextureRegistry textureRegistry;
108110
private final PlatformViewRegistry platformViewRegistry;
109111
private final FlutterAssets flutterAssets;
112+
private final FlutterEngineGroup group;
110113

111114
public FlutterPluginBinding(
112115
@NonNull Context applicationContext,
113116
@NonNull FlutterEngine flutterEngine,
114117
@NonNull BinaryMessenger binaryMessenger,
115118
@NonNull TextureRegistry textureRegistry,
116119
@NonNull PlatformViewRegistry platformViewRegistry,
117-
@NonNull FlutterAssets flutterAssets) {
120+
@NonNull FlutterAssets flutterAssets,
121+
@Nullable FlutterEngineGroup group) {
118122
this.applicationContext = applicationContext;
119123
this.flutterEngine = flutterEngine;
120124
this.binaryMessenger = binaryMessenger;
121125
this.textureRegistry = textureRegistry;
122126
this.platformViewRegistry = platformViewRegistry;
123127
this.flutterAssets = flutterAssets;
128+
this.group = group;
124129
}
125130

126131
@NonNull
@@ -157,6 +162,11 @@ public PlatformViewRegistry getPlatformViewRegistry() {
157162
public FlutterAssets getFlutterAssets() {
158163
return flutterAssets;
159164
}
165+
166+
@Nullable
167+
public FlutterEngineGroup getEngineGroup() {
168+
return group;
169+
}
160170
}
161171

162172
/** Provides Flutter plugins with access to Flutter asset information. */

shell/platform/android/io/flutter/embedding/engine/plugins/shim/ShimPluginRegistry.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
*
2626
* <pre>
2727
* // Create the FlutterEngine that will back the Flutter UI.
28-
* FlutterEngine flutterEngine = new FlutterEngine(context);
28+
* FlutterEngineGroup group = new FlutterEngineGroup(context);
29+
* FlutterEngine flutterEngine = group.createAndRunDefaultEngine(context);
2930
*
3031
* // Create a ShimPluginRegistry and wrap the FlutterEngine with the shim.
3132
* ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry(flutterEngine, platformViewsController);

shell/platform/android/test/io/flutter/embedding/android/FlutterActivityAndFragmentDelegateTest.java

+16
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,22 @@ public void itDoesNotDelayTheFirstDrawWhenRequestedAndWithAProvidedSplashScreen(
11591159
assertNull(delegate.activePreDrawListener);
11601160
}
11611161

1162+
@Test
1163+
public void usesFlutterEngineGroup() {
1164+
FlutterEngineGroup mockEngineGroup = mock(FlutterEngineGroup.class);
1165+
when(mockEngineGroup.createAndRunEngine(any(FlutterEngineGroup.Options.class)))
1166+
.thenReturn(mockFlutterEngine);
1167+
FlutterActivityAndFragmentDelegate.Host host =
1168+
mock(FlutterActivityAndFragmentDelegate.Host.class);
1169+
when(mockHost.getContext()).thenReturn(ctx);
1170+
1171+
FlutterActivityAndFragmentDelegate delegate =
1172+
new FlutterActivityAndFragmentDelegate(mockHost, mockEngineGroup);
1173+
delegate.onAttach(ctx);
1174+
FlutterEngine engineUnderTest = delegate.getFlutterEngine();
1175+
assertEquals(engineUnderTest, mockFlutterEngine);
1176+
}
1177+
11621178
/**
11631179
* Creates a mock {@link io.flutter.embedding.engine.FlutterEngine}.
11641180
*

shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineConnectionRegistryTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void itDoesNotRegisterTheSamePluginTwice() {
4040
FakeFlutterPlugin fakePlugin2 = new FakeFlutterPlugin();
4141

4242
FlutterEngineConnectionRegistry registry =
43-
new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader);
43+
new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader, null);
4444

4545
// Verify that the registry doesn't think it contains our plugin yet.
4646
assertFalse(registry.has(fakePlugin1.getClass()));
@@ -86,7 +86,7 @@ public void activityResultListenerCanBeRemovedFromListener() {
8686

8787
// Set up the environment to get the required internal data
8888
FlutterEngineConnectionRegistry registry =
89-
new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader);
89+
new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader, null);
9090
FakeActivityAwareFlutterPlugin fakePlugin = new FakeActivityAwareFlutterPlugin();
9191
registry.add(fakePlugin);
9292
registry.attachToActivity(appComponent, lifecycle);
@@ -129,7 +129,7 @@ public void softwareRendering() {
129129

130130
// Test attachToActivity with an Activity that has no Intent.
131131
FlutterEngineConnectionRegistry registry =
132-
new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader);
132+
new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader, null);
133133
registry.attachToActivity(appComponent, mock(Lifecycle.class));
134134
verify(platformViewsController).setSoftwareRendering(false);
135135

shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineTest.java

+33
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525
import io.flutter.FlutterInjector;
2626
import io.flutter.embedding.engine.FlutterEngine;
2727
import io.flutter.embedding.engine.FlutterEngine.EngineLifecycleListener;
28+
import io.flutter.embedding.engine.FlutterEngineGroup;
2829
import io.flutter.embedding.engine.FlutterJNI;
2930
import io.flutter.embedding.engine.loader.FlutterLoader;
31+
import io.flutter.embedding.engine.plugins.FlutterPlugin;
32+
import io.flutter.embedding.engine.plugins.PluginRegistry;
3033
import io.flutter.plugin.platform.PlatformViewsController;
3134
import io.flutter.plugins.GeneratedPluginRegistrant;
3235
import java.util.List;
@@ -323,4 +326,34 @@ public void itComesWithARunningDartExecutorIfJNIIsAlreadyAttached() throws NameN
323326

324327
assertTrue(engineUnderTest.getDartExecutor().isExecutingDart());
325328
}
329+
330+
@Test
331+
public void passesEngineGroupToPlugins() throws NameNotFoundException {
332+
Context packageContext = mock(Context.class);
333+
334+
when(mockContext.createPackageContext(any(), anyInt())).thenReturn(packageContext);
335+
when(flutterJNI.isAttached()).thenReturn(true);
336+
337+
FlutterEngineGroup mockGroup = mock(FlutterEngineGroup.class);
338+
339+
FlutterEngine engineUnderTest =
340+
new FlutterEngine(
341+
mockContext,
342+
mock(FlutterLoader.class),
343+
flutterJNI,
344+
new PlatformViewsController(),
345+
/*dartVmArgs=*/ new String[] {},
346+
/*automaticallyRegisterPlugins=*/ false,
347+
/*waitForRestorationData=*/ false,
348+
mockGroup);
349+
350+
PluginRegistry registry = engineUnderTest.getPlugins();
351+
FlutterPlugin mockPlugin = mock(FlutterPlugin.class);
352+
ArgumentCaptor<FlutterPlugin.FlutterPluginBinding> pluginBindingCaptor =
353+
ArgumentCaptor.forClass(FlutterPlugin.FlutterPluginBinding.class);
354+
registry.add(mockPlugin);
355+
verify(mockPlugin).onAttachedToEngine(pluginBindingCaptor.capture());
356+
assertNotNull(pluginBindingCaptor.getValue());
357+
assertEquals(mockGroup, pluginBindingCaptor.getValue().getEngineGroup());
358+
}
326359
}

0 commit comments

Comments
 (0)