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