-
Notifications
You must be signed in to change notification settings - Fork 1
Experimental: Add Flutter Fragment
Everything in this doc and linked from this doc is experimental. These details WILL change. Do not use these instructions or APIs in production code because we will break you.
Many Android apps achieve navigation by switching out different Fragment
s as "screens" within a single Activity
. A FlutterActivity
cannot be used in such apps because Activity
s cannot be embedded within other Activity
s. To deal with this use-case, Flutter offers a FlutterFragment
that can be used wherever any other Fragment
can be used.
One way to use a FlutterFragment
is to declare it in an XML layout file.
<fragment
android:id="@+id/flutterfragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="io.flutter.embedding.android.FlutterFragment"
/>
Reminder, declaring a FlutterFragment
, or any other Fragment
, within an XML layout file prevents the Fragment
from being programmatically removed at runtime.
TODO(mattcarroll): Add support for XML attributes for splash screen, initial route, and possibly app bundle path. This work is currently blocked by the fact that the engine buildroot does not support AAR production, which prevents including any XML resources of any kind.
Another way to use a FlutterFragment
is to instantiate one within an Activity
.
private void createFlutterFragment() {
FragmentManager fragmentManager = getFragmentManager();
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.
//
// This example uses defaults of "main" for the Dart entrypoint, and "/" as the initial route.
flutterFragment = new FlutterFragment.createDefault();
// This method assumes that there is a FrameLayout in the view hierarchy with an ID of CONTAINER_ID.
// TAG_FLUTTER_FRAGMENT is a String of your choice to reference the added FlutterFragment.
fragmentManager
.beginTransaction()
.add(CONTAINER_ID, flutterFragment, TAG_FLUTTER_FRAGMENT)
.commit();
}
}
A FlutterEngine
object is responsible for executing the Dart code in your Flutter app. By default, every FlutterFragment
creates a new FlutterEngine
internally to run the desired Flutter UI.
One downside to having a FlutterFragment
internally create a new FlutterEngine
is that there is a warm-up period before the FlutterEngine
is able to render a UI. This results in a temporary blank screen. One way to solve this is to create and start a FlutterEngine
before the FlutterFragment
appears, and then instruct the FlutterFragment
to use the warmed up FlutterEngine
. There are 3 ways to accomplish this, which are outlined below.
Regardless of which option you use to provide a FlutterEngine
to a FlutterFragment
, you must first instantiate and pre-warm a FlutterEngine
before the user navigates to your FlutterFragment
.
// Instantiate your FlutterEngine.
FlutterEngine flutterEngine = new FlutterEngine(context);
// Pre-warm your FlutterEngine by starting Dart execution.
flutterEngine
.getDartExecutor()
.executeDartEntrypoint(
DartEntrypoint.createDefault()
);
After pre-warming a FlutterEngine
, place it in the FlutterEngineCache
:
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine);
The engine ID in the previous example can be any value you choose, so long as it does not collide with other cached engines that you previously placed in the FlutterEngineCache
.
Then, configure your FlutterFragment
to use your cached FlutterEngine
:
FlutterFragment flutterFragment = FlutterFragment
.withCachedEngine("my_engine_id")
.build();
Now, when your FlutterFragment
is displayed, it will use your pre-warmed FlutterEngine
, greatly reducing the time it takes to display the first frame.
Another way to use a pre-existing FlutterEngine
within a FlutterFragment
is to subclass FlutterFragment
:
public class MyFlutterFragment extends FlutterFragment {
@Override
@Nullable
protected FlutterEngine provideFlutterEngine(@NonNull Context context) {
// Maybe you chose to store your FlutterEngine in a static reference.
return MyFlutterEngine.getFlutterEngine();
// or maybe you chose to store your FlutterEngine in your Application class.
return ((MyApp) context.getApplication).getFlutterEngine();
}
}
A third way to use a pre-warmed FlutterEngine
is to implement the FlutterEngineProvider
in the Activity
that owns your FlutterFragment
:
public class MyActivity extends Activity implements FlutterEngineProvider {
@Override
@Nullable
FlutterEngine provideFlutterEngine(@NonNull Context context) {
// Maybe you chose to store your FlutterEngine in a static reference.
return MyFlutterEngine.getFlutterEngine();
// or maybe you chose to store your FlutterEngine in your Application class.
return ((MyApp) context.getApplication).getFlutterEngine();
}
}
- Home of the Wiki
- Roadmap
- API Reference (stable)
- API Reference (master)
- Glossary
- Contributor Guide
- Chat on Discord
- Code of Conduct
- Issue triage reports
- Our Values
- Tree hygiene
- Issue hygiene and Triage
- Style guide for Flutter repo
- Project teams
- Contributor access
- What should I work on?
- Running and writing tests
- Release process
- Rolling Dart
- Manual Engine Roll with Breaking Commits
- Updating Material Design Fonts & Icons
- Postmortems
- Setting up the Framework development environment
- The Framework architecture
- The flutter tool
- API Docs code block generation
- Running examples
- Using the Dart analyzer
- The flutter run variants
- Test coverage for package:flutter
- Writing a golden-file test for package:flutter
- Setting up the Engine development environment
- Compiling the engine
- Debugging the engine
- Using Sanitizers with the Flutter Engine
- Testing the engine
- The Engine architecture
- Flutter's modes
- Engine disk footprint
- Comparing AOT Snapshot Sizes
- Custom Flutter engine embedders
- Custom Flutter Engine Embedding in AOT Mode
- Flutter engine operation in AOT Mode
- Engine-specific Service Protocol extensions
- Crashes
- Supporting legacy platforms
- Metal on iOS FAQ
- Engine Clang Tidy Linter
- Why we have a separate engine repo
- Reduce Flutter engine size with MLGO
- Setting up the Plugins development environment
- Setting up the Packages development environment
- Plugins and Packages repository structure
- Plugin Tests
- Contributing to Plugins and Packages
- Releasing a Plugin or Package
- Unexpected Plugins and Packages failures