Android PR 7: Introduce structure of FlutterActivity and FlutterFragment (flutter/engine#7912)
This commit is contained in:
@@ -471,7 +471,10 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterFragmentActi
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/app/FlutterPluginRegistry.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/FlutterShellArgs.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/android/AndroidKeyProcessor.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/android/FlutterActivity.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/android/FlutterFragment.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/android/FlutterSurfaceView.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/android/FlutterTextureView.java
|
||||
FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/engine/android/FlutterView.java
|
||||
|
||||
@@ -108,7 +108,10 @@ java_library("flutter_shell_java") {
|
||||
"io/flutter/app/FlutterPluginRegistry.java",
|
||||
"io/flutter/embedding/engine/FlutterEngine.java",
|
||||
"io/flutter/embedding/engine/FlutterJNI.java",
|
||||
"io/flutter/embedding/engine/FlutterShellArgs.java",
|
||||
"io/flutter/embedding/engine/android/AndroidKeyProcessor.java",
|
||||
"io/flutter/embedding/engine/android/FlutterActivity.java",
|
||||
"io/flutter/embedding/engine/android/FlutterFragment.java",
|
||||
"io/flutter/embedding/engine/android/FlutterSurfaceView.java",
|
||||
"io/flutter/embedding/engine/android/FlutterTextureView.java",
|
||||
"io/flutter/embedding/engine/android/FlutterView.java",
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
// 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.embedding.engine;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Arguments that can be delivered to the Flutter shell when it is created.
|
||||
* <p>
|
||||
* WARNING: THIS CLASS IS EXPERIMENTAL. DO NOT SHIP A DEPENDENCY ON THIS CODE.
|
||||
* IF YOU USE IT, WE WILL BREAK YOU.
|
||||
* <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.
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public class FlutterShellArgs {
|
||||
public static final String ARG_KEY_TRACE_STARTUP = "trace-startup";
|
||||
public static final String ARG_TRACE_STARTUP = "--trace-startup";
|
||||
public static final String ARG_KEY_START_PAUSED = "start-paused";
|
||||
public static final String ARG_START_PAUSED = "--start-paused";
|
||||
public static final String ARG_KEY_USE_TEST_FONTS = "use-test-fonts";
|
||||
public static final String ARG_USE_TEST_FONTS = "--use-test-fonts";
|
||||
public static final String ARG_KEY_ENABLE_DART_PROFILING = "enable-dart-profiling";
|
||||
public static final String ARG_ENABLE_DART_PROFILING = "--enable-dart-profiling";
|
||||
public static final String ARG_KEY_ENABLE_SOFTWARE_RENDERING = "enable-software-rendering";
|
||||
public static final String ARG_ENABLE_SOFTWARE_RENDERING = "--enable-software-rendering";
|
||||
public static final String ARG_KEY_SKIA_DETERMINISTIC_RENDERING = "skia-deterministic-rendering";
|
||||
public static final String ARG_SKIA_DETERMINISTIC_RENDERING = "--skia-deterministic-rendering";
|
||||
public static final String ARG_KEY_TRACE_SKIA = "trace-skia";
|
||||
public static final String ARG_TRACE_SKIA = "--trace-skia";
|
||||
public static final String ARG_KEY_VERBOSE_LOGGING = "verbose-logging";
|
||||
public static final String ARG_VERBOSE_LOGGING = "--verbose-logging";
|
||||
|
||||
@NonNull
|
||||
public static FlutterShellArgs fromIntent(@NonNull Intent intent) {
|
||||
// Before adding more entries to this list, consider that arbitrary
|
||||
// Android applications can generate intents with extra data and that
|
||||
// there are many security-sensitive args in the binary.
|
||||
// TODO(mattcarroll): I left this warning as-is, but we should clarify what exactly this warning is warning against.
|
||||
ArrayList<String> args = new ArrayList<>();
|
||||
|
||||
if (intent.getBooleanExtra(ARG_KEY_TRACE_STARTUP, false)) {
|
||||
args.add(ARG_TRACE_STARTUP);
|
||||
}
|
||||
if (intent.getBooleanExtra(ARG_KEY_START_PAUSED, false)) {
|
||||
args.add(ARG_START_PAUSED);
|
||||
}
|
||||
if (intent.getBooleanExtra(ARG_KEY_USE_TEST_FONTS, false)) {
|
||||
args.add(ARG_USE_TEST_FONTS);
|
||||
}
|
||||
if (intent.getBooleanExtra(ARG_KEY_ENABLE_DART_PROFILING, false)) {
|
||||
args.add(ARG_ENABLE_DART_PROFILING);
|
||||
}
|
||||
if (intent.getBooleanExtra(ARG_KEY_ENABLE_SOFTWARE_RENDERING, false)) {
|
||||
args.add(ARG_ENABLE_SOFTWARE_RENDERING);
|
||||
}
|
||||
if (intent.getBooleanExtra(ARG_KEY_SKIA_DETERMINISTIC_RENDERING, false)) {
|
||||
args.add(ARG_SKIA_DETERMINISTIC_RENDERING);
|
||||
}
|
||||
if (intent.getBooleanExtra(ARG_KEY_TRACE_SKIA, false)) {
|
||||
args.add(ARG_TRACE_SKIA);
|
||||
}
|
||||
if (intent.getBooleanExtra(ARG_KEY_VERBOSE_LOGGING, false)) {
|
||||
args.add(ARG_VERBOSE_LOGGING);
|
||||
}
|
||||
|
||||
return new FlutterShellArgs(args);
|
||||
}
|
||||
|
||||
private Set<String> args;
|
||||
|
||||
/**
|
||||
* Creates a set of Flutter shell arguments from a given {@code String[]} array.
|
||||
* The given arguments are automatically de-duplicated.
|
||||
*/
|
||||
public FlutterShellArgs(@NonNull String[] args) {
|
||||
this.args = new HashSet<>(Arrays.asList(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a set of Flutter shell arguments from a given {@code List<String>}.
|
||||
* The given arguments are automatically de-duplicated.
|
||||
*/
|
||||
public FlutterShellArgs(@NonNull List<String> args) {
|
||||
this.args = new HashSet<>(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a set of Flutter shell arguments from a given {@code Set<String>}.
|
||||
*/
|
||||
public FlutterShellArgs(@NonNull Set<String> args) {
|
||||
this.args = new HashSet<>(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@code arg} to this set of arguments.
|
||||
* @param arg argument to add
|
||||
*/
|
||||
public void add(@NonNull String arg) {
|
||||
args.add(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@code arg} from this set of arguments.
|
||||
* @param arg argument to remove
|
||||
*/
|
||||
public void remove(@NonNull String arg) {
|
||||
args.remove(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code String[]} array which contains each of the arguments
|
||||
* within this {@code FlutterShellArgs}.
|
||||
*
|
||||
* @return array of arguments
|
||||
*/
|
||||
@NonNull
|
||||
public String[] toArray() {
|
||||
String[] argsArray = new String[args.size()];
|
||||
return args.toArray(argsArray);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
// 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.embedding.engine.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import io.flutter.embedding.engine.FlutterShellArgs;
|
||||
import io.flutter.view.FlutterMain;
|
||||
|
||||
/**
|
||||
* {@code Activity} which displays a fullscreen Flutter UI.
|
||||
* <p>
|
||||
* WARNING: THIS CLASS IS EXPERIMENTAL. DO NOT SHIP A DEPENDENCY ON THIS CODE.
|
||||
* IF YOU USE IT, WE WILL BREAK YOU.
|
||||
* <p>
|
||||
* {@code FlutterActivity} is the simplest and most direct way to integrate Flutter within an
|
||||
* Android app.
|
||||
* <p>
|
||||
* The Dart entrypoint executed within this {@code Activity} is "main()" by default. The entrypoint
|
||||
* may be specified explicitly by passing the name of the entrypoint method as a {@code String} in
|
||||
* {@link #EXTRA_DART_ENTRYPOINT}, e.g., "myEntrypoint".
|
||||
* <p>
|
||||
* The Flutter route that is initially loaded within this {@code Activity} is "/". The initial
|
||||
* route may be specified explicitly by passing the name of the route as a {@code String} in
|
||||
* {@link #EXTRA_INITIAL_ROUTE}, e.g., "my/deep/link".
|
||||
* <p>
|
||||
* The app bundle path, Dart entrypoint, and initial route can each be controlled in a subclass of
|
||||
* {@code FlutterActivity} by overriding their respective methods:
|
||||
* <ul>
|
||||
* <li>{@link #getAppBundlePath()}</li>
|
||||
* <li>{@link #getDartEntrypoint()}</li>
|
||||
* <li>{@link #getInitialRoute()}</li>
|
||||
* </ul>
|
||||
* If Flutter is needed in a location that cannot use an {@code Activity}, consider using
|
||||
* a {@link FlutterFragment}. Using a {@link FlutterFragment} requires forwarding some calls from
|
||||
* an {@code Activity} to the {@link FlutterFragment}.
|
||||
* <p>
|
||||
* If Flutter is needed in a location that can only use a {@code View}, consider using a
|
||||
* {@link FlutterView}. Using a {@link FlutterView} requires forwarding some calls from an
|
||||
* {@code Activity}, as well as forwarding lifecycle calls from an {@code Activity} or a
|
||||
* {@code Fragment}.
|
||||
*/
|
||||
// TODO(mattcarroll): explain each call forwarded to Fragment (first requires resolution of PluginRegistry API).
|
||||
public class FlutterActivity extends FragmentActivity {
|
||||
private static final String TAG = "FlutterActivity";
|
||||
|
||||
// Meta-data arguments, processed from manifest XML.
|
||||
private static final String DART_ENTRYPOINT_META_DATA_KEY = "io.flutter.Entrypoint";
|
||||
private static final String INITIAL_ROUTE_META_DATA_KEY = "io.flutter.InitialRoute";
|
||||
|
||||
// Intent extra arguments.
|
||||
public static final String EXTRA_DART_ENTRYPOINT = "dart_entrypoint";
|
||||
public static final String EXTRA_INITIAL_ROUTE = "initial_route";
|
||||
|
||||
// FlutterFragment management.
|
||||
private static final String TAG_FLUTTER_FRAGMENT = "flutter_fragment";
|
||||
// TODO(mattcarroll): replace ID with R.id when build system supports R.java
|
||||
private static final int FRAGMENT_CONTAINER_ID = 609893468; // random number
|
||||
private FlutterFragment flutterFragment;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(createFragmentContainer());
|
||||
ensureFlutterFragmentCreated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FrameLayout} with an ID of {@code #FRAGMENT_CONTAINER_ID} that will contain
|
||||
* the {@link FlutterFragment} displayed by this {@code FlutterActivity}.
|
||||
* <p>
|
||||
* @return the FrameLayout container
|
||||
*/
|
||||
@NonNull
|
||||
private View createFragmentContainer() {
|
||||
FrameLayout container = new FrameLayout(this);
|
||||
container.setId(FRAGMENT_CONTAINER_ID);
|
||||
container.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
));
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a {@link FlutterFragment} is attached to this {@code FlutterActivity}.
|
||||
* <p>
|
||||
* If no {@link FlutterFragment} exists in this {@code FlutterActivity}, then a {@link FlutterFragment}
|
||||
* is created and added. If a {@link FlutterFragment} does exist in this {@code FlutterActivity}, then
|
||||
* a reference to that {@link FlutterFragment} is retained in {@code #flutterFragment}.
|
||||
*/
|
||||
private void ensureFlutterFragmentCreated() {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
flutterFragment = (FlutterFragment) fragmentManager.findFragmentByTag(TAG_FLUTTER_FRAGMENT);
|
||||
if (flutterFragment == null) {
|
||||
// No FlutterFragment exists yet. This must be the initial Activity creation. We will create
|
||||
// and add a new FlutterFragment to this Activity.
|
||||
flutterFragment = createFlutterFragment();
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.add(FRAGMENT_CONTAINER_ID, flutterFragment, TAG_FLUTTER_FRAGMENT)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the instance of the {@link FlutterFragment} that this {@code FlutterActivity} displays.
|
||||
* <p>
|
||||
* Subclasses may override this method to return a specialization of {@link FlutterFragment}.
|
||||
*/
|
||||
@NonNull
|
||||
protected FlutterFragment createFlutterFragment() {
|
||||
return FlutterFragment.newInstance(
|
||||
getDartEntrypoint(),
|
||||
getInitialRoute(),
|
||||
getAppBundlePath(),
|
||||
FlutterShellArgs.fromIntent(getIntent())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to the bundle that contains this Flutter app's resources, e.g., Dart code snapshots.
|
||||
* <p>
|
||||
* When this {@code FlutterActivity} is run by Flutter tooling and a data String is included
|
||||
* in the launching {@code Intent}, that data String is interpreted as an app bundle path.
|
||||
* <p>
|
||||
* By default, the app bundle path is obtained from {@link FlutterMain#findAppBundlePath(Context)}.
|
||||
* <p>
|
||||
* Subclasses may override this method to return a custom app bundle path.
|
||||
*/
|
||||
@NonNull
|
||||
protected String getAppBundlePath() {
|
||||
// If this Activity was launched from tooling, and the incoming Intent contains
|
||||
// a custom app bundle path, return that path.
|
||||
// TODO(mattcarroll): determine if we should have an explicit FlutterTestActivity instead of conflating.
|
||||
if (isDebuggable() && Intent.ACTION_RUN.equals(getIntent().getAction())) {
|
||||
String appBundlePath = getIntent().getDataString();
|
||||
if (appBundlePath != null) {
|
||||
return appBundlePath;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the default app bundle path.
|
||||
// TODO(mattcarroll): move app bundle resolution into an appropriately named class.
|
||||
return FlutterMain.findAppBundlePath(getApplicationContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* The Dart entrypoint that will be executed as soon as the Dart snapshot is loaded.
|
||||
* <p>
|
||||
* This preference can be controlled with 2 methods:
|
||||
* <ol>
|
||||
* <li>Pass a {@code String} as {@link #EXTRA_DART_ENTRYPOINT} with the launching {@code Intent}, or</li>
|
||||
* <li>Set a {@code <meta-data>} called {@link #DART_ENTRYPOINT_META_DATA_KEY} for this
|
||||
* {@code Activity} in the Android manifest.</li>
|
||||
* </ol>
|
||||
* If both preferences are set, the {@code Intent} preference takes priority.
|
||||
* <p>
|
||||
* The reason that a {@code <meta-data>} preference is supported is because this {@code Activity}
|
||||
* might be the very first {@code Activity} launched, which means the developer won't have
|
||||
* control over the incoming {@code Intent}.
|
||||
* <p>
|
||||
* Subclasses may override this method to directly control the Dart entrypoint.
|
||||
*/
|
||||
@Nullable
|
||||
protected String getDartEntrypoint() {
|
||||
if (getIntent().hasExtra(EXTRA_DART_ENTRYPOINT)) {
|
||||
return getIntent().getStringExtra(EXTRA_DART_ENTRYPOINT);
|
||||
}
|
||||
|
||||
try {
|
||||
ActivityInfo activityInfo = getPackageManager().getActivityInfo(
|
||||
getComponentName(),
|
||||
PackageManager.GET_META_DATA|PackageManager.GET_ACTIVITIES
|
||||
);
|
||||
Bundle metadata = activityInfo.metaData;
|
||||
return metadata != null ? metadata.getString(DART_ENTRYPOINT_META_DATA_KEY) : null;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial route that a Flutter app will render upon loading and executing its Dart code.
|
||||
* <p>
|
||||
* This preference can be controlled with 2 methods:
|
||||
* <ol>
|
||||
* <li>Pass a boolean as {@link #EXTRA_INITIAL_ROUTE} with the launching {@code Intent}, or</li>
|
||||
* <li>Set a {@code <meta-data>} called {@link #INITIAL_ROUTE_META_DATA_KEY} for this
|
||||
* {@code Activity} in the Android manifest.</li>
|
||||
* </ol>
|
||||
* If both preferences are set, the {@code Intent} preference takes priority.
|
||||
* <p>
|
||||
* The reason that a {@code <meta-data>} preference is supported is because this {@code Activity}
|
||||
* might be the very first {@code Activity} launched, which means the developer won't have
|
||||
* control over the incoming {@code Intent}.
|
||||
* <p>
|
||||
* Subclasses may override this method to directly control the initial route.
|
||||
*/
|
||||
@Nullable
|
||||
protected String getInitialRoute() {
|
||||
if (getIntent().hasExtra(EXTRA_INITIAL_ROUTE)) {
|
||||
return getIntent().getStringExtra(EXTRA_INITIAL_ROUTE);
|
||||
}
|
||||
|
||||
try {
|
||||
ActivityInfo activityInfo = getPackageManager().getActivityInfo(
|
||||
getComponentName(),
|
||||
PackageManager.GET_META_DATA|PackageManager.GET_ACTIVITIES
|
||||
);
|
||||
Bundle metadata = activityInfo.metaData;
|
||||
return metadata != null ? metadata.getString(INITIAL_ROUTE_META_DATA_KEY) : null;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Flutter is running in "debug mode", and false otherwise.
|
||||
* <p>
|
||||
* Debug mode allows Flutter to operate with hot reload and hot restart. Release mode does not.
|
||||
*/
|
||||
private boolean isDebuggable() {
|
||||
return (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
// 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.embedding.engine.android;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
||||
import io.flutter.embedding.engine.FlutterShellArgs;
|
||||
|
||||
/**
|
||||
* {@code Fragment} which displays a Flutter UI that takes up all available {@code Fragment} space.
|
||||
* <p>
|
||||
* WARNING: THIS CLASS IS EXPERIMENTAL. DO NOT SHIP A DEPENDENCY ON THIS CODE.
|
||||
* IF YOU USE IT, WE WILL BREAK YOU.
|
||||
* <p>
|
||||
* Using a {@code FlutterFragment} requires forwarding a number of calls from an {@code Activity} to
|
||||
* ensure that the internal Flutter app behaves as expected:
|
||||
* <ol>
|
||||
* <li>{@link Activity#onPostResume()}</li>
|
||||
* <li>{@link Activity#onBackPressed()}</li>
|
||||
* <li>{@link Activity#onRequestPermissionsResult(int, String[], int[])} ()}</li>
|
||||
* <li>{@link Activity#onNewIntent(Intent)} ()}</li>
|
||||
* <li>{@link Activity#onUserLeaveHint()}</li>
|
||||
* <li>{@link Activity#onTrimMemory(int)}</li>
|
||||
* </ol>
|
||||
* Additionally, when starting an {@code Activity} for a result from this {@code Fragment}, be sure
|
||||
* to invoke {@link Fragment#startActivityForResult(Intent, int)} rather than
|
||||
* {@link Activity#startActivityForResult(Intent, int)}. If the {@code Activity} version of the
|
||||
* method is invoked then this {@code Fragment} will never receive its
|
||||
* {@link Fragment#onActivityResult(int, int, Intent)} callback.
|
||||
* <p>
|
||||
* If convenient, consider using a {@link FlutterActivity} instead of a {@code FlutterFragment} to
|
||||
* avoid the work of forwarding calls.
|
||||
* <p>
|
||||
* If Flutter is needed in a location that can only use a {@code View}, consider using a
|
||||
* {@link FlutterView}. Using a {@link FlutterView} requires forwarding some calls from an
|
||||
* {@code Activity}, as well as forwarding lifecycle calls from an {@code Activity} or a
|
||||
* {@code Fragment}.
|
||||
*/
|
||||
public class FlutterFragment extends Fragment {
|
||||
private static final String TAG = "FlutterFragment";
|
||||
|
||||
private static final String ARG_DART_ENTRYPOINT = "dart_entrypoint";
|
||||
private static final String ARG_INITIAL_ROUTE = "initial_route";
|
||||
private static final String ARG_APP_BUNDLE_PATH = "app_bundle_path";
|
||||
private static final String ARG_FLUTTER_INITIALIZATION_ARGS = "initialization_args";
|
||||
|
||||
/**
|
||||
* Factory method that creates a new {@link FlutterFragment} with a default configuration.
|
||||
* <ul>
|
||||
* <li>default Dart entrypoint of "main"</li>
|
||||
* <li>initial route of "/"</li>
|
||||
* <li>default app bundle location</li>
|
||||
* <li>no special engine arguments</li>
|
||||
* </ul>
|
||||
* @return new {@link FlutterFragment}
|
||||
*/
|
||||
public static FlutterFragment newInstance() {
|
||||
return newInstance(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that creates a new {@link FlutterFragment} with the given configuration.
|
||||
* <p>
|
||||
* @param dartEntrypoint the name of the initial Dart method to invoke, defaults to "main"
|
||||
* @param initialRoute the first route that a Flutter app will render in this {@link FlutterFragment},
|
||||
* defaults to "/"
|
||||
* @param appBundlePath the path to the app bundle which contains the Dart app to execute, defaults
|
||||
* to {@link FlutterMain#findAppBundlePath(Context)}
|
||||
* @param flutterShellArgs any special configuration arguments for the Flutter engine
|
||||
*
|
||||
* @return a new {@link FlutterFragment}
|
||||
*/
|
||||
public static FlutterFragment newInstance(@Nullable String dartEntrypoint,
|
||||
@Nullable String initialRoute,
|
||||
@Nullable String appBundlePath,
|
||||
@Nullable FlutterShellArgs flutterShellArgs) {
|
||||
FlutterFragment frag = new FlutterFragment();
|
||||
|
||||
Bundle args = createArgsBundle(
|
||||
dartEntrypoint,
|
||||
initialRoute,
|
||||
appBundlePath,
|
||||
flutterShellArgs
|
||||
);
|
||||
frag.setArguments(args);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Bundle} of arguments that can be used to configure a {@link FlutterFragment}.
|
||||
* This method is exposed so that developers can create subclasses of {@link FlutterFragment}.
|
||||
* Subclasses should declare static factories that use this method to create arguments that will
|
||||
* be understood by the base class, and then the subclass can add any additional arguments it
|
||||
* wants to this {@link Bundle}. Example:
|
||||
* <pre>{@code
|
||||
* public static MyFlutterFragment newInstance(String myNewArg) {
|
||||
* // Create an instance of our subclass Fragment.
|
||||
* MyFlutterFragment myFrag = new MyFlutterFragment();
|
||||
*
|
||||
* // Create the Bundle or args that FlutterFragment understands.
|
||||
* Bundle args = FlutterFragment.createArgsBundle(...);
|
||||
*
|
||||
* // Add our new args to the bundle.
|
||||
* args.putString(ARG_MY_NEW_ARG, myNewArg);
|
||||
*
|
||||
* // Give the args to our subclass Fragment.
|
||||
* myFrag.setArguments(args);
|
||||
*
|
||||
* // Return the newly created subclass Fragment.
|
||||
* return myFrag;
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param dartEntrypoint the name of the initial Dart method to invoke, defaults to "main"
|
||||
* @param initialRoute the first route that a Flutter app will render in this {@link FlutterFragment}, defaults to "/"
|
||||
* @param appBundlePath the path to the app bundle which contains the Dart app to execute
|
||||
* @param flutterShellArgs any special configuration arguments for the Flutter engine
|
||||
*
|
||||
* @return Bundle of arguments that configure a {@link FlutterFragment}
|
||||
*/
|
||||
protected static Bundle createArgsBundle(@Nullable String dartEntrypoint,
|
||||
@Nullable String initialRoute,
|
||||
@Nullable String appBundlePath,
|
||||
@Nullable FlutterShellArgs flutterShellArgs) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ARG_INITIAL_ROUTE, initialRoute);
|
||||
args.putString(ARG_APP_BUNDLE_PATH, appBundlePath);
|
||||
args.putString(ARG_DART_ENTRYPOINT, dartEntrypoint);
|
||||
// TODO(mattcarroll): determine if we should have an explicit FlutterTestFragment instead of conflating.
|
||||
if (null != flutterShellArgs) {
|
||||
args.putStringArray(ARG_FLUTTER_INITIALIZATION_ARGS, flutterShellArgs.toArray());
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
public FlutterFragment() {
|
||||
// Ensure that we at least have an empty Bundle of arguments so that we don't
|
||||
// need to continually check for null arguments before grabbing one.
|
||||
setArguments(new Bundle());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user