• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package io.flutter.embedding.engine;
6 
7 import android.arch.lifecycle.Lifecycle;
8 import android.arch.lifecycle.LifecycleOwner;
9 import android.content.Context;
10 import android.support.annotation.NonNull;
11 
12 import java.util.HashSet;
13 import java.util.Set;
14 
15 import io.flutter.Log;
16 import io.flutter.embedding.engine.dart.DartExecutor;
17 import io.flutter.embedding.engine.plugins.PluginRegistry;
18 import io.flutter.embedding.engine.plugins.activity.ActivityControlSurface;
19 import io.flutter.embedding.engine.plugins.broadcastreceiver.BroadcastReceiverControlSurface;
20 import io.flutter.embedding.engine.plugins.contentprovider.ContentProviderControlSurface;
21 import io.flutter.embedding.engine.plugins.service.ServiceControlSurface;
22 import io.flutter.embedding.engine.renderer.FlutterRenderer;
23 import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
24 import io.flutter.embedding.engine.systemchannels.KeyEventChannel;
25 import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
26 import io.flutter.embedding.engine.systemchannels.LocalizationChannel;
27 import io.flutter.embedding.engine.systemchannels.NavigationChannel;
28 import io.flutter.embedding.engine.systemchannels.PlatformChannel;
29 import io.flutter.embedding.engine.systemchannels.SettingsChannel;
30 import io.flutter.embedding.engine.systemchannels.SystemChannel;
31 import io.flutter.embedding.engine.systemchannels.TextInputChannel;
32 import io.flutter.plugin.platform.PlatformViewsController;
33 
34 /**
35  * A single Flutter execution environment.
36  *
37  * WARNING: THIS CLASS IS EXPERIMENTAL. DO NOT SHIP A DEPENDENCY ON THIS CODE.
38  * IF YOU USE IT, WE WILL BREAK YOU.
39  *
40  * A {@code FlutterEngine} can execute in the background, or it can be rendered to the screen by
41  * using the accompanying {@link FlutterRenderer}.  Rendering can be started and stopped, thus
42  * allowing a {@code FlutterEngine} to move from UI interaction to data-only processing and then
43  * back to UI interaction.
44  *
45  * Multiple {@code FlutterEngine}s may exist, execute Dart code, and render UIs within a single
46  * Android app.
47  *
48  * To start running Flutter within this {@code FlutterEngine}, get a reference to this engine's
49  * {@link DartExecutor} and then use {@link DartExecutor#executeDartEntrypoint(DartExecutor.DartEntrypoint)}.
50  * The {@link DartExecutor#executeDartEntrypoint(DartExecutor.DartEntrypoint)} method must not be
51  * invoked twice on the same {@code FlutterEngine}.
52  *
53  * To start rendering Flutter content to the screen, use {@link #getRenderer()} to obtain a
54  * {@link FlutterRenderer} and then attach a {@link FlutterRenderer.RenderSurface}.  Consider using
55  * a {@link io.flutter.embedding.android.FlutterView} as a {@link FlutterRenderer.RenderSurface}.
56  */
57 // TODO(mattcarroll): re-evaluate system channel APIs - some are not well named or differentiated
58 public class FlutterEngine implements LifecycleOwner {
59   private static final String TAG = "FlutterEngine";
60 
61   @NonNull
62   private final FlutterJNI flutterJNI;
63   @NonNull
64   private final FlutterRenderer renderer;
65   @NonNull
66   private final DartExecutor dartExecutor;
67   @NonNull
68   private final FlutterEnginePluginRegistry pluginRegistry;
69   @NonNull
70   private final FlutterEngineAndroidLifecycle androidLifecycle;
71 
72   // System channels.
73   @NonNull
74   private final AccessibilityChannel accessibilityChannel;
75   @NonNull
76   private final KeyEventChannel keyEventChannel;
77   @NonNull
78   private final LifecycleChannel lifecycleChannel;
79   @NonNull
80   private final LocalizationChannel localizationChannel;
81   @NonNull
82   private final NavigationChannel navigationChannel;
83   @NonNull
84   private final PlatformChannel platformChannel;
85   @NonNull
86   private final SettingsChannel settingsChannel;
87   @NonNull
88   private final SystemChannel systemChannel;
89   @NonNull
90   private final TextInputChannel textInputChannel;
91 
92   // Platform Views.
93   @NonNull
94   private final PlatformViewsController platformViewsController;
95 
96   // Engine Lifecycle.
97   @NonNull
98   private final Set<EngineLifecycleListener> engineLifecycleListeners = new HashSet<>();
99   @NonNull
100   private final EngineLifecycleListener engineLifecycleListener = new EngineLifecycleListener() {
101     @SuppressWarnings("unused")
102     public void onPreEngineRestart() {
103       Log.v(TAG, "onPreEngineRestart()");
104       for (EngineLifecycleListener lifecycleListener : engineLifecycleListeners) {
105         lifecycleListener.onPreEngineRestart();
106       }
107     }
108   };
109 
110   /**
111    * Constructs a new {@code FlutterEngine}.
112    *
113    * {@code FlutterMain.startInitialization} must be called before constructing a {@code FlutterEngine}
114    * to load the native libraries needed to attach to JNI.
115    *
116    * A new {@code FlutterEngine} does not execute any Dart code automatically. See
117    * {@link #getDartExecutor()} and {@link DartExecutor#executeDartEntrypoint(DartExecutor.DartEntrypoint)}
118    * to begin executing Dart code within this {@code FlutterEngine}.
119    *
120    * A new {@code FlutterEngine} will not display any UI until a
121    * {@link io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface} is registered. See
122    * {@link #getRenderer()} and {@link FlutterRenderer#attachToRenderSurface(FlutterRenderer.RenderSurface)}.
123    *
124    * A new {@code FlutterEngine} does not come with any Flutter plugins attached. To attach plugins,
125    * see {@link #getPlugins()}.
126    *
127    * A new {@code FlutterEngine} does come with all default system channels attached.
128    */
FlutterEngine(@onNull Context context)129   public FlutterEngine(@NonNull Context context) {
130     this.flutterJNI = new FlutterJNI();
131     flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
132     attachToJni();
133 
134     this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
135     this.dartExecutor.onAttachedToJNI();
136 
137     // TODO(mattcarroll): FlutterRenderer is temporally coupled to attach(). Remove that coupling if possible.
138     this.renderer = new FlutterRenderer(flutterJNI);
139 
140     accessibilityChannel = new AccessibilityChannel(dartExecutor, flutterJNI);
141     keyEventChannel = new KeyEventChannel(dartExecutor);
142     lifecycleChannel = new LifecycleChannel(dartExecutor);
143     localizationChannel = new LocalizationChannel(dartExecutor);
144     navigationChannel = new NavigationChannel(dartExecutor);
145     platformChannel = new PlatformChannel(dartExecutor);
146     settingsChannel = new SettingsChannel(dartExecutor);
147     systemChannel = new SystemChannel(dartExecutor);
148     textInputChannel = new TextInputChannel(dartExecutor);
149 
150     platformViewsController = new PlatformViewsController();
151 
152     androidLifecycle = new FlutterEngineAndroidLifecycle(this);
153     this.pluginRegistry = new FlutterEnginePluginRegistry(
154       context.getApplicationContext(),
155       this,
156         androidLifecycle
157     );
158   }
159 
attachToJni()160   private void attachToJni() {
161     Log.v(TAG, "Attaching to JNI.");
162     // TODO(mattcarroll): update native call to not take in "isBackgroundView"
163     flutterJNI.attachToNative(false);
164 
165     if (!isAttachedToJni()) {
166       throw new RuntimeException("FlutterEngine failed to attach to its native Object reference.");
167     }
168   }
169 
170   @SuppressWarnings("BooleanMethodIsAlwaysInverted")
isAttachedToJni()171   private boolean isAttachedToJni() {
172     return flutterJNI.isAttached();
173   }
174 
175   /**
176    * Cleans up all components within this {@code FlutterEngine} and then detaches from Flutter's
177    * native implementation.
178    *
179    * This {@code FlutterEngine} instance should be discarded after invoking this method.
180    */
destroy()181   public void destroy() {
182     Log.d(TAG, "Destroying.");
183     // The order that these things are destroyed is important.
184     pluginRegistry.destroy();
185     dartExecutor.onDetachedFromJNI();
186     flutterJNI.removeEngineLifecycleListener(engineLifecycleListener);
187     flutterJNI.detachFromNativeAndReleaseResources();
188   }
189 
190   /**
191    * Adds a {@code listener} to be notified of Flutter engine lifecycle events, e.g.,
192    * {@code onPreEngineStart()}.
193    */
addEngineLifecycleListener(@onNull EngineLifecycleListener listener)194   public void addEngineLifecycleListener(@NonNull EngineLifecycleListener listener) {
195     engineLifecycleListeners.add(listener);
196   }
197 
198   /**
199    * Removes a {@code listener} that was previously added with
200    * {@link #addEngineLifecycleListener(EngineLifecycleListener)}.
201    */
removeEngineLifecycleListener(@onNull EngineLifecycleListener listener)202   public void removeEngineLifecycleListener(@NonNull EngineLifecycleListener listener) {
203     engineLifecycleListeners.remove(listener);
204   }
205 
206   /**
207    * The Dart execution context associated with this {@code FlutterEngine}.
208    *
209    * The {@link DartExecutor} can be used to start executing Dart code from a given entrypoint.
210    * See {@link DartExecutor#executeDartEntrypoint(DartExecutor.DartEntrypoint)}.
211    *
212    * Use the {@link DartExecutor} to connect any desired message channels and method channels
213    * to facilitate communication between Android and Dart/Flutter.
214    */
215   @NonNull
getDartExecutor()216   public DartExecutor getDartExecutor() {
217     return dartExecutor;
218   }
219 
220   /**
221    * The rendering system associated with this {@code FlutterEngine}.
222    *
223    * To render a Flutter UI that is produced by this {@code FlutterEngine}'s Dart code, attach
224    * a {@link io.flutter.embedding.engine.renderer.FlutterRenderer.RenderSurface} to this
225    * {@link FlutterRenderer}.
226    */
227   @NonNull
getRenderer()228   public FlutterRenderer getRenderer() {
229     return renderer;
230   }
231 
232   /**
233    * System channel that sends accessibility requests and events from Flutter to Android.
234    */
235   @NonNull
getAccessibilityChannel()236   public AccessibilityChannel getAccessibilityChannel() {
237     return accessibilityChannel;
238   }
239 
240   /**
241    * System channel that sends key events from Android to Flutter.
242    */
243   @NonNull
getKeyEventChannel()244   public KeyEventChannel getKeyEventChannel() {
245     return keyEventChannel;
246   }
247 
248   /**
249    * System channel that sends Android lifecycle events to Flutter.
250    */
251   @NonNull
getLifecycleChannel()252   public LifecycleChannel getLifecycleChannel() {
253     return lifecycleChannel;
254   }
255 
256   /**
257    * System channel that sends locale data from Android to Flutter.
258    */
259   @NonNull
getLocalizationChannel()260   public LocalizationChannel getLocalizationChannel() {
261     return localizationChannel;
262   }
263 
264   /**
265    * System channel that sends Flutter navigation commands from Android to Flutter.
266    */
267   @NonNull
getNavigationChannel()268   public NavigationChannel getNavigationChannel() {
269     return navigationChannel;
270   }
271 
272   /**
273    * System channel that sends platform-oriented requests and information to Flutter,
274    * e.g., requests to play sounds, requests for haptics, system chrome settings, etc.
275    */
276   @NonNull
getPlatformChannel()277   public PlatformChannel getPlatformChannel() {
278     return platformChannel;
279   }
280 
281   /**
282    * System channel that sends platform/user settings from Android to Flutter, e.g.,
283    * time format, scale factor, etc.
284    */
285   @NonNull
getSettingsChannel()286   public SettingsChannel getSettingsChannel() {
287     return settingsChannel;
288   }
289 
290   /**
291    * System channel that sends memory pressure warnings from Android to Flutter.
292    */
293   @NonNull
getSystemChannel()294   public SystemChannel getSystemChannel() {
295     return systemChannel;
296   }
297 
298   /**
299    * System channel that sends and receives text input requests and state.
300    */
301   @NonNull
getTextInputChannel()302   public TextInputChannel getTextInputChannel() {
303     return textInputChannel;
304   }
305 
306   /**
307    * Plugin registry, which registers plugins that want to be applied to this {@code FlutterEngine}.
308    */
309   @NonNull
getPlugins()310   public PluginRegistry getPlugins() {
311     return pluginRegistry;
312   }
313 
314   /**
315    * {@code PlatformViewsController}, which controls all platform views running within
316    * this {@code FlutterEngine}.
317    */
318   @NonNull
getPlatformViewsController()319   public PlatformViewsController getPlatformViewsController() {
320     return platformViewsController;
321   }
322 
323   @NonNull
getActivityControlSurface()324   public ActivityControlSurface getActivityControlSurface() {
325     return pluginRegistry;
326   }
327 
328   @NonNull
getServiceControlSurface()329   public ServiceControlSurface getServiceControlSurface() {
330     return pluginRegistry;
331   }
332 
333   @NonNull
getBroadcastReceiverControlSurface()334   public BroadcastReceiverControlSurface getBroadcastReceiverControlSurface() {
335     return pluginRegistry;
336   }
337 
338   @NonNull
getContentProviderControlSurface()339   public ContentProviderControlSurface getContentProviderControlSurface() {
340     return pluginRegistry;
341   }
342 
343   // TODO(mattcarroll): determine if we really need to expose this from FlutterEngine vs making PluginBinding a LifecycleOwner
344   @NonNull
345   @Override
getLifecycle()346   public Lifecycle getLifecycle() {
347     return androidLifecycle;
348   }
349 
350   /**
351    * Lifecycle callbacks for Flutter engine lifecycle events.
352    */
353   public interface EngineLifecycleListener {
354     /**
355      * Lifecycle callback invoked before a hot restart of the Flutter engine.
356      */
onPreEngineRestart()357     void onPreEngineRestart();
358   }
359 }
360