|
4 | 4 |
|
5 | 5 | package io.flutter.embedding.engine; |
6 | 6 |
|
| 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 | + |
7 | 15 | /** |
8 | 16 | * A single Flutter execution environment. |
9 | 17 | * |
|
19 | 27 | * Android app. |
20 | 28 | * |
21 | 29 | * 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}. |
25 | 33 | * |
26 | 34 | * To start rendering Flutter content to the screen, use {@link #getRenderer()} to obtain a |
27 | 35 | * {@link FlutterRenderer} and then attach a {@link FlutterRenderer.RenderSurface}. Consider using |
28 | 36 | * a {@link io.flutter.embedding.android.FlutterView} as a {@link FlutterRenderer.RenderSurface}. |
29 | 37 | */ |
30 | 38 | 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 | + } |
32 | 160 |
|
33 | 161 | /** |
34 | 162 | * Lifecycle callbacks for Flutter engine lifecycle events. |
|
0 commit comments