Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_poo
FILE: ../../../flutter/shell/platform/android/external_view_embedder/surface_pool_unittests.cc
FILE: ../../../flutter/shell/platform/android/flutter_main.cc
FILE: ../../../flutter/shell/platform/android/flutter_main.h
FILE: ../../../flutter/shell/platform/android/io/flutter/FlutterInjector.java
FILE: ../../../flutter/shell/platform/android/io/flutter/Log.java
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivity.java
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ embedding_sources_jar_filename = "$embedding_artifact_id-sources.jar"
embedding_source_jar_path = "$root_out_dir/$embedding_sources_jar_filename"

android_java_sources = [
"io/flutter/FlutterInjector.java",
"io/flutter/Log.java",
"io/flutter/app/FlutterActivity.java",
"io/flutter/app/FlutterActivityDelegate.java",
Expand Down Expand Up @@ -415,6 +416,7 @@ action("robolectric_tests") {
jar_path = "$root_out_dir/robolectric_tests.jar"

sources = [
"test/io/flutter/FlutterInjectorTest.java",
"test/io/flutter/FlutterTestSuite.java",
"test/io/flutter/SmokeTest.java",
"test/io/flutter/embedding/android/AndroidKeyProcessorTest.java",
Expand All @@ -434,6 +436,7 @@ action("robolectric_tests") {
"test/io/flutter/embedding/engine/RenderingComponentTest.java",
"test/io/flutter/embedding/engine/dart/DartExecutorTest.java",
"test/io/flutter/embedding/engine/loader/ApplicationInfoLoaderTest.java",
"test/io/flutter/embedding/engine/loader/FlutterLoaderTest.java",
"test/io/flutter/embedding/engine/plugins/shim/ShimPluginRegistryTest.java",
"test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java",
"test/io/flutter/embedding/engine/systemchannels/KeyEventChannelTest.java",
Expand Down
136 changes: 136 additions & 0 deletions shell/platform/android/io/flutter/FlutterInjector.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter;

import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import io.flutter.embedding.engine.loader.FlutterLoader;

/**
* This class is a simple dependency injector for the relatively thin Android part of the Flutter
* engine.
*
* <p>This simple solution is used facilitate testability without bringing in heavier
* app-development centric dependency injection frameworks such as Guice or Dagger2 or spreading
* construction injection everywhere.
*/
public final class FlutterInjector {

private static FlutterInjector instance;
private static boolean accessed;

/**
* Use {@link FlutterInjector.Builder} to specify members to be injected via the static {@code
* FlutterInjector}.
*
* <p>This can only be called at the beginning of the program before the {@link #instance()} is
* accessed.
*/
public static void setInstance(@NonNull FlutterInjector injector) {
if (accessed) {
throw new IllegalStateException(
"Cannot change the FlutterInjector instance once it's been "
+ "read. If you're trying to dependency inject, be sure to do so at the beginning of "
+ "the program");
}
instance = injector;
}

/**
* Retrieve the static instance of the {@code FlutterInjector} to use in your program.
*
* <p>Once you access it, you can no longer change the values injected.
*
* <p>If no override is provided for the injector, reasonable defaults are provided.
*/
public static FlutterInjector instance() {
accessed = true;
if (instance == null) {
instance = new Builder().build();
}
return instance;
}

// This whole class is here to enable testing so to test the thing that lets you test, some degree
// of hack is needed.
@VisibleForTesting
public static void reset() {
accessed = false;
instance = null;
}

private FlutterInjector(boolean shouldLoadNative, @NonNull FlutterLoader flutterLoader) {
this.shouldLoadNative = shouldLoadNative;
this.flutterLoader = flutterLoader;
}

private boolean shouldLoadNative;
private FlutterLoader flutterLoader;

/**
* Returns whether the Flutter Android engine embedding should load the native C++ engine.
*
* <p>Useful for testing since JVM tests via Robolectric can't load native libraries.
*/
public boolean shouldLoadNative() {
return shouldLoadNative;
}

/** Returns the {@link FlutterLoader} instance to use for the Flutter Android engine embedding. */
@NonNull
public FlutterLoader flutterLoader() {
return flutterLoader;
}

/**
* Builder used to supply a custom FlutterInjector instance to {@link
* FlutterInjector#setInstance(FlutterInjector)}.
*
* <p>Non-overriden values have reasonable defaults.
*/
public static final class Builder {

private boolean shouldLoadNative = true;
/**
* Sets whether the Flutter Android engine embedding should load the native C++ engine.
*
* <p>Useful for testing since JVM tests via Robolectric can't load native libraries.
*
* <p>Defaults to true.
*/
public Builder setShouldLoadNative(boolean shouldLoadNative) {
this.shouldLoadNative = shouldLoadNative;
return this;
}

private FlutterLoader flutterLoader;
/**
* Sets a {@link FlutterLoader} override.
*
* <p>A reasonable default will be used if unspecified.
*/
public Builder setFlutterLoader(@NonNull FlutterLoader flutterLoader) {
this.flutterLoader = flutterLoader;
return this;
}

private void fillDefaults() {
if (flutterLoader == null) {
flutterLoader = new FlutterLoader();
}
}

/**
* Builds a {@link FlutterInjector} from the builder. Unspecified properties will have
* reasonable defaults.
*/
public FlutterInjector build() {
fillDefaults();

System.out.println("should load native is " + shouldLoadNative);
return new FlutterInjector(shouldLoadNative, flutterLoader);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
import java.util.ArrayList;

/**
* Class that performs the actual work of tying Android {@link Activity} instances to Flutter.
* Deprecated class that performs the actual work of tying Android {@link Activity} instances to
* Flutter.
*
* <p>This exists as a dedicated class (as opposed to being integrated directly into {@link
* FlutterActivity}) to facilitate applications that don't wish to subclass {@code FlutterActivity}.
Expand All @@ -48,6 +49,10 @@
* FlutterActivityEvents} from your activity to an instance of this class. Optionally, you can make
* your activity implement {@link PluginRegistry} and/or {@link
* io.flutter.view.FlutterView.Provider} and forward those methods to this class as well.
*
* <p>Deprecation: {@link io.flutter.embedding.android.FlutterActivity} is the new API that now
* replaces this class and {@link io.flutter.app.FlutterActivity}. See
* https://flutter.dev/go/android-project-migration for more migration details.
*/
public final class FlutterActivityDelegate
implements FlutterActivityEvents, FlutterView.Provider, PluginRegistry {
Expand Down
4 changes: 2 additions & 2 deletions shell/platform/android/io/flutter/app/FlutterApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import android.app.Activity;
import android.app.Application;
import androidx.annotation.CallSuper;
import io.flutter.view.FlutterMain;
import io.flutter.FlutterInjector;

/**
* Flutter implementation of {@link android.app.Application}, managing application-level global
Expand All @@ -21,7 +21,7 @@ public class FlutterApplication extends Application {
@CallSuper
public void onCreate() {
super.onCreate();
FlutterMain.startInitialization(this);
FlutterInjector.instance().flutterLoader().startInitialization(this);
}

private Activity mCurrentActivity = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.FlutterInjector;
import io.flutter.Log;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.loader.FlutterLoader;
Expand Down Expand Up @@ -131,7 +132,8 @@ public void onPreEngineRestart() {
* <p>In order to pass Dart VM initialization arguments (see {@link
* io.flutter.embedding.engine.FlutterShellArgs}) when creating the VM, manually set the
* initialization arguments by calling {@link FlutterLoader#startInitialization(Context)} and
* {@link FlutterLoader#ensureInitializationComplete(Context, String[])}.
* {@link FlutterLoader#ensureInitializationComplete(Context, String[])} before constructing the
* engine.
*/
public FlutterEngine(@NonNull Context context) {
this(context, null);
Expand All @@ -143,7 +145,7 @@ public FlutterEngine(@NonNull Context context) {
* <p>If the Dart VM has already started, the given arguments will have no effect.
*/
public FlutterEngine(@NonNull Context context, @Nullable String[] dartVmArgs) {
this(context, FlutterLoader.getInstance(), new FlutterJNI(), dartVmArgs, true);
this(context, /* flutterLoader */ null, new FlutterJNI(), dartVmArgs, true);
}

/**
Expand All @@ -158,7 +160,7 @@ public FlutterEngine(
boolean automaticallyRegisterPlugins) {
this(
context,
FlutterLoader.getInstance(),
/* flutterLoader */ null,
new FlutterJNI(),
dartVmArgs,
automaticallyRegisterPlugins);
Expand Down Expand Up @@ -189,7 +191,7 @@ public FlutterEngine(
boolean waitForRestorationData) {
this(
context,
FlutterLoader.getInstance(),
/* flutterLoader */ null,
new FlutterJNI(),
new PlatformViewsController(),
dartVmArgs,
Expand All @@ -206,7 +208,7 @@ public FlutterEngine(
*/
public FlutterEngine(
@NonNull Context context,
@NonNull FlutterLoader flutterLoader,
@Nullable FlutterLoader flutterLoader,
@NonNull FlutterJNI flutterJNI) {
this(context, flutterLoader, flutterJNI, null, true);
}
Expand All @@ -219,7 +221,7 @@ public FlutterEngine(
*/
public FlutterEngine(
@NonNull Context context,
@NonNull FlutterLoader flutterLoader,
@Nullable FlutterLoader flutterLoader,
@NonNull FlutterJNI flutterJNI,
@Nullable String[] dartVmArgs,
boolean automaticallyRegisterPlugins) {
Expand All @@ -238,7 +240,7 @@ public FlutterEngine(
*/
public FlutterEngine(
@NonNull Context context,
@NonNull FlutterLoader flutterLoader,
@Nullable FlutterLoader flutterLoader,
@NonNull FlutterJNI flutterJNI,
@NonNull PlatformViewsController platformViewsController,
@Nullable String[] dartVmArgs,
Expand All @@ -256,7 +258,7 @@ public FlutterEngine(
/** Fully configurable {@code FlutterEngine} constructor. */
public FlutterEngine(
@NonNull Context context,
@NonNull FlutterLoader flutterLoader,
@Nullable FlutterLoader flutterLoader,
@NonNull FlutterJNI flutterJNI,
@NonNull PlatformViewsController platformViewsController,
@Nullable String[] dartVmArgs,
Expand All @@ -280,6 +282,9 @@ public FlutterEngine(
this.localizationPlugin = new LocalizationPlugin(context, localizationChannel);

this.flutterJNI = flutterJNI;
if (flutterLoader == null) {
flutterLoader = FlutterInjector.instance().flutterLoader();
}
flutterLoader.startInitialization(context.getApplicationContext());
flutterLoader.ensureInitializationComplete(context, dartVmArgs);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
* <p>The term "shell" refers to the native code that adapts Flutter to different platforms.
* Flutter's Android Java code initializes a native "shell" and passes these arguments to that
* native shell when it is initialized. See {@link
* io.flutter.view.FlutterMain#ensureInitializationComplete(Context, String[])} for more
* information.
* io.flutter.embedding.engine.loader.FlutterLoader#ensureInitializationComplete(Context, String[])}
* for more information.
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public class FlutterShellArgs {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import io.flutter.FlutterInjector;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.StringCodec;
import io.flutter.view.FlutterCallbackInformation;
import io.flutter.view.FlutterMain;
import java.nio.ByteBuffer;

/**
Expand Down Expand Up @@ -250,9 +251,19 @@ public void notifyLowMemoryWarning() {
* that entrypoint and other assets required for Dart execution.
*/
public static class DartEntrypoint {
/**
* Create a DartEntrypoint pointing to the default Flutter assets location with a default Dart
* entrypoint.
*/
@NonNull
public static DartEntrypoint createDefault() {
return new DartEntrypoint(FlutterMain.findAppBundlePath(), "main");
FlutterLoader flutterLoader = FlutterInjector.instance().flutterLoader();

if (!flutterLoader.initialized()) {
throw new AssertionError(
"DartEntrypoints can only be created once a FlutterEngine is created.");
}
return new DartEntrypoint(flutterLoader.findAppBundlePath(), "main");
}

/** The path within the AssetManager where the app will look for assets. */
Expand Down
Loading