How can I embed a Flutter layout in my Android App using FlutterFragment with a custom entry point?

1,332

What went wrong?

As of the moment, if you are using AndroidX, the only way you can use FlutterFragment in embedding your Flutter layout is when it is added as an Android Archive (AAR) in your dependencies.

I've previously opened an issue in Github regarding this concern, and it is still open at the time of writing.

Adding Flutter as an AAR dependency has both pros and cons. With AAR, your team does not need to have Flutter SDK installed in their local machine nor required to install Dart SDK. However, since AAR files are compiled artifacts, your team may not be able to edit the project's Flutter source code during development.

Here's the documentation on how you can setup your Android project with your Flutter source code added as an AAR module.

But why really use AAR?

Under the hood, FlutterFragment and some (if not all) of the classes under io.flutter.embedding are still using the support libraries and not AndroidX, there is a mismatch in the dependencies. With AAR and with your jetifier enabled during compilation, the AAR output of your Flutter will now use equivalent AndroidX libraries, something you don't expect to happen during runtime .

But, I need my team to work on some Flutter app features simultaneously with some Android app project changes.

Well, since you can't use FlutterFragment in that particular type of setup, you can still use FlutterView, especially if you are only showing a portion of your Flutter layout in your Android app.

feature_fragment.kt

portfolioEngine?.let { flutterEngine ->
    // Start executing Dart code to pre-warm the FlutterEngine.
    // https://github.com/flutter/flutter/wiki/Experimental:-Launch-Flutter-with-non-main-entrypoint
    flutterEngine.dartExecutor.executeDartEntrypoint(
        DartExecutor.DartEntrypoint(
            FlutterMain.findAppBundlePath(),
            "customEntryPoint"
        )
    )

    // Cache the FlutterEngine to be used by FlutterActivity.
    FlutterEngineCache
        .getInstance()
        .put("SOME_FLUTTER_ENGINE_NAME", flutterEngine)

    // Add the Flutter layout
    flutterView = FlutterView(context)
    flutterView.attachToFlutterEngine(flutterEngine)
    flutterContainerView?.removeAllViews() // Only if deemed necessary
    flutterContainerView?.addView(flutterView)
}

feature_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/flutterContainerView"
        android:layout_width="match_parent"
        android:layout_height="300dp" />
</LinearLayout>

But, there's a small catch...

One of the benefits using FlutterActivity or FlutterFragment over FlutterView is the ease of managing the lifecycle of your Android and Flutter code simultaneously. Don't worry, you can still handle how your Flutter code will behave by managing its lifecycle using the attached FlutterEngine.

Further reading

Share:
1,332
Joshua de Guzman
Author by

Joshua de Guzman

Hello, I am Joshua de Guzman, a software engineer with a passion for learning and teaching, based in the Philippines. A Google Developer Expert for Flutter. I work at Freelancer.com (ASX:FLN), a services marketplace with over 40M users where you can hire and work for freelancers and projects respectively. Previously I worked at Xurpas (PSE:X), the largest publicly listed consumer technology company in Southeast Asia, where I developed Android and iOS apps as part of the company’s product line and worked with some of the country’s well-known companies. Life outside work, I enjoy exploring and contributing to open-source projects, asking and answering questions here in StackOverflow, and sharing my experiences and knowledge with the community. In 2019, I founded Flutter Philippines where I am continuously learning how to build and grow an awesome community. You may know me as @joshuamdeguzman on Twitter, @joshuadeguzman on Github, LinkedIn, and Keybase. Most recent blog: Complete Guide: Design, Build and Deploy Your First Flutter Website!

Updated on December 16, 2022

Comments

  • Joshua de Guzman
    Joshua de Guzman over 1 year

    This feature I'm trying out in Flutter is called Add-to-App.

    I read the instructions included in their documentation on how I can add FlutterFragment as a section in my app.

    As seen in the document example, I should be able to add my newFlutterFragment just like how I add normal Fragment classes in Android.

    // Create and attach a FlutterFragment if one does not exist.
    if (flutterFragment == null) {
      var newFlutterFragment = FlutterFragment.createDefault()
      flutterFragment = newFlutterFragment
      fragmentManager
        .beginTransaction()
        .add(
          R.id.fragment_container,
          newFlutterFragment,
          TAG_FLUTTER_FRAGMENT
        )
        .commit()
    }
    

    The examples we're pretty much straightforward, however, as per checking (Github and SO), it only works when you are warming up a FlutterEngine using the main or default entry point.

    image-1

    Unfortunately, whenever I try adding my own FlutterFragment using a custom entry point, it doesn't seem to accept the type of object I'm passing in the .add(<INVALID_TYPE>,...,...) method of the FragmentTransaction.

    image-1

    Is there by any chance that I could still use FlutterFragment as the container for the Flutter section view I have?

    Setup

    • Android depend on Flutter module's source code (Option B)
    • Android project with AndroidX

    Environment

    • Flutter: v1.12.13+hotfix.5 (stable)
    • Dart: v2.4.0
    • OS: macOS Catalina v1.14.5