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

Commit e11d0e9

Browse files
Android embedding refactor pr5 add flutterengine impl (#7878)
1 parent 2f4a38d commit e11d0e9

File tree

2 files changed

+140
-4
lines changed

2 files changed

+140
-4
lines changed

shell/platform/android/io/flutter/app/FlutterPluginRegistry.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import android.app.Activity;
88
import android.content.Context;
99
import android.content.Intent;
10+
11+
import io.flutter.embedding.engine.FlutterEngine;
1012
import io.flutter.plugin.common.BinaryMessenger;
1113
import io.flutter.plugin.common.PluginRegistry;
1214
import io.flutter.plugin.platform.PlatformViewRegistry;
@@ -49,6 +51,12 @@ public FlutterPluginRegistry(FlutterNativeView nativeView, Context context) {
4951
mPlatformViewsController = new PlatformViewsController();
5052
}
5153

54+
public FlutterPluginRegistry(FlutterEngine engine, Context context) {
55+
// TODO(mattcarroll): implement use of engine instead of nativeView.
56+
mAppContext = context;
57+
mPlatformViewsController = new PlatformViewsController();
58+
}
59+
5260
@Override
5361
public boolean hasPlugin(String key) {
5462
return mPluginMap.containsKey(key);

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

Lines changed: 132 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
package io.flutter.embedding.engine;
66

7+
import android.content.Context;
8+
import android.support.annotation.NonNull;
9+
import android.support.annotation.Nullable;
10+
11+
import io.flutter.app.FlutterPluginRegistry;
12+
import io.flutter.embedding.engine.dart.DartExecutor;
13+
import io.flutter.embedding.engine.renderer.FlutterRenderer;
14+
715
/**
816
* A single Flutter execution environment.
917
*
@@ -19,16 +27,136 @@
1927
* Android app.
2028
*
2129
* To start running Flutter within this {@code FlutterEngine}, get a reference to this engine's
22-
* {@link DartExecutor} and then use {@link DartExecutor#runFromBundle(FlutterRunArguments)}.
23-
* The {@link DartExecutor#runFromBundle(FlutterRunArguments)} method must not be invoked twice on the same
24-
* {@code FlutterEngine}.
30+
* {@link DartExecutor} and then use {@link DartExecutor#executeDartEntrypoint(DartExecutor.DartEntrypoint)}.
31+
* The {@link DartExecutor#executeDartEntrypoint(DartExecutor.DartEntrypoint)} method must not be
32+
* invoked twice on the same {@code FlutterEngine}.
2533
*
2634
* To start rendering Flutter content to the screen, use {@link #getRenderer()} to obtain a
2735
* {@link FlutterRenderer} and then attach a {@link FlutterRenderer.RenderSurface}. Consider using
2836
* a {@link io.flutter.embedding.android.FlutterView} as a {@link FlutterRenderer.RenderSurface}.
2937
*/
3038
public class FlutterEngine {
31-
// TODO(mattcarroll): bring in FlutterEngine implementation in future PR
39+
private static final String TAG = "FlutterEngine";
40+
41+
@NonNull
42+
private final FlutterJNI flutterJNI;
43+
@NonNull
44+
private final FlutterRenderer renderer;
45+
@NonNull
46+
private final DartExecutor dartExecutor;
47+
// TODO(mattcarroll): integrate system channels with FlutterEngine
48+
@NonNull
49+
private final FlutterPluginRegistry pluginRegistry;
50+
51+
private final EngineLifecycleListener engineLifecycleListener = new EngineLifecycleListener() {
52+
@SuppressWarnings("unused")
53+
public void onPreEngineRestart() {
54+
pluginRegistry.onPreEngineRestart();
55+
}
56+
};
57+
58+
/**
59+
* Constructs a new {@code FlutterEngine}.
60+
*
61+
* A new {@code FlutterEngine} does not execute any Dart code automatically. See
62+
* {@link #getDartExecutor()} and {@link DartExecutor#executeDartEntrypoint(DartExecutor.DartEntrypoint)}
63+
* to begin executing Dart code within this {@code FlutterEngine}.
64+
*
65+
* A new {@code FlutterEngine} will not display any UI until a
66+
* {@link io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface} is registered. See
67+
* {@link #getRenderer()} and {@link FlutterRenderer#attachToRenderSurface(FlutterRenderer.RenderSurface)}.
68+
*
69+
* A new {@code FlutterEngine} does not come with any Flutter plugins attached. To attach plugins,
70+
* see {@link #getPluginRegistry()}.
71+
*
72+
* A new {@code FlutterEngine} does come with all default system channels attached.
73+
*/
74+
public FlutterEngine(@NonNull Context context) {
75+
this.flutterJNI = new FlutterJNI();
76+
flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
77+
attachToJni();
78+
79+
this.dartExecutor = new DartExecutor(flutterJNI);
80+
this.dartExecutor.onAttachedToJNI();
81+
82+
// TODO(mattcarroll): FlutterRenderer is temporally coupled to attach(). Remove that coupling if possible.
83+
this.renderer = new FlutterRenderer(flutterJNI);
84+
85+
this.pluginRegistry = new FlutterPluginRegistry(this, context);
86+
}
87+
88+
private void attachToJni() {
89+
// TODO(mattcarroll): update native call to not take in "isBackgroundView"
90+
flutterJNI.attachToNative(false);
91+
92+
if (!isAttachedToJni()) {
93+
throw new RuntimeException("FlutterEngine failed to attach to its native Object reference.");
94+
}
95+
}
96+
97+
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
98+
private boolean isAttachedToJni() {
99+
return flutterJNI.isAttached();
100+
}
101+
102+
/**
103+
* Detaches this {@code FlutterEngine} from Flutter's native implementation, but allows
104+
* reattachment later.
105+
*
106+
* // TODO(mattcarroll): document use-cases for this behavior.
107+
*/
108+
public void detachFromJni() {
109+
pluginRegistry.detach();
110+
dartExecutor.onDetachedFromJNI();
111+
flutterJNI.removeEngineLifecycleListener(engineLifecycleListener);
112+
// TODO(mattcarroll): investigate detach vs destroy. document user-cases. update code if needed.
113+
flutterJNI.detachFromNativeButKeepNativeResources();
114+
}
115+
116+
/**
117+
* Cleans up all components within this {@code FlutterEngine} and then detaches from Flutter's
118+
* native implementation.
119+
*
120+
* This {@code FlutterEngine} instance should be discarded after invoking this method.
121+
*/
122+
public void destroy() {
123+
pluginRegistry.destroy();
124+
dartExecutor.onDetachedFromJNI();
125+
flutterJNI.removeEngineLifecycleListener(engineLifecycleListener);
126+
flutterJNI.detachFromNativeAndReleaseResources();
127+
}
128+
129+
/**
130+
* The Dart execution context associated with this {@code FlutterEngine}.
131+
*
132+
* The {@link DartExecutor} can be used to start executing Dart code from a given entrypoint.
133+
* See {@link DartExecutor#executeDartEntrypoint(DartExecutor.DartEntrypoint)}.
134+
*
135+
* Use the {@link DartExecutor} to connect any desired message channels and method channels
136+
* to facilitate communication between Android and Dart/Flutter.
137+
*/
138+
@NonNull
139+
public DartExecutor getDartExecutor() {
140+
return dartExecutor;
141+
}
142+
143+
/**
144+
* The rendering system associated with this {@code FlutterEngine}.
145+
*
146+
* To render a Flutter UI that is produced by this {@code FlutterEngine}'s Dart code, attach
147+
* a {@link io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface} to this
148+
* {@link FlutterRenderer}.
149+
*/
150+
@NonNull
151+
public FlutterRenderer getRenderer() {
152+
return renderer;
153+
}
154+
155+
// TODO(mattcarroll): propose a robust story for plugin backward compability and future facing API.
156+
@NonNull
157+
public FlutterPluginRegistry getPluginRegistry() {
158+
return pluginRegistry;
159+
}
32160

33161
/**
34162
* Lifecycle callbacks for Flutter engine lifecycle events.

0 commit comments

Comments
 (0)