Flutter as a module for Android Developers

Based in India.
Search for a command to run...

Based in India.
No comments yet. Be the first to comment.
I recently had to deploy a Ktor project to Railway for my hobby project. I'll share the how-to through this article. Introduction Ktor is a framework that allows us to build web applications in Kotlin, built and backed by Jetbrains. It's open-source,...

Understanding Coroutines and Flow Kotlin Coroutines and Flows are a powerful tool for managing asynchronous programming in your Android apps. This article is a beginner's guide to understanding Kotlin Flow. First, let's understand what coroutines are...

The problem When working with JVM (Java Virtual Machine), the Garbage Collector will take care of allocating and deallocating memory for us - Most of the time. In some cases, it fails to release the memory for some objects which are no longer in use,...

What are quick actions? Quick actions under the hood are App Shortcuts(in Android) and Home Screen Actions(in iOS) which allow users to perform certain app actions without having to open the app. Where have I seen this? You might have already seen an...

What are app shortcuts? App shortcuts (introduced in Android Nougat 7.1) allow users to perform certain app actions without having to open the app. Developers can allow users to pin certain app actions to home screen. Let's see how. Where have I seen...

Flutter has become quite popular among app developers because -
Ease of development,
Cross-platform,
Declarative UI,
Hot reload,
and Native-like performance.
While we can build a fully functional application using Flutter, it's also possible to add Flutter to a fully functional native android application(and iOS application). In this article, we'll look into exactly that -
We can add Flutter into our existing apps as -
Activity
Fragment
View
In this article, I'll be covering FlutterActivity and FlutterFragment. I'll make another article covering FlutterView using RecyclerView adapter.
In the example code snippets, I'll be using Kotlin.
We'll need to add a new module to our existing project by doing-
First, add the Flutter plugin to Android Studio.
Then in your existing project - File > New > New Module > Flutter Module and then complete the module setup wizard.

In flutter, we inflate a widget (everything in Flutter is a widget) using the runApp function by doing this -
void main() => runApp(const MyApp());
Let's say we want to do the same from our existing app as an activity we can do this -
fun navigateToFlutterActivity() {
startActivity(
FlutterActivity
.createDefaultIntent(this)
)
}
Make sure FlutterActivity is imported.
import io.flutter.embedding.android.FlutterActivity
**Result - **

We'll notice some delay in inflating the widget ๐. This is because flutter runs on Flutter Engine which has a non-trivial warm-up time, what we can do is pre-cache the engine and use that to inflate the widget.
For this, we'll use a cached FlutterEngine.
First, declare the FlutterEngine in the application class as follows -
class AndroidAndFlutterApplication : Application() {
private lateinit var flutterEngine: FlutterEngine
override fun onCreate() {
super.onCreate()
flutterEngine = FlutterEngine(this)
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
FlutterEngineCache
.getInstance()
.put("engineID", flutterEngine)
}
}
Engine id parameter can we whatever we want, we'll need it later to uniquely identify the FlutterEngine.
Now we can use this FlutterEngine by simply using .withCachedEngine() builder as -
startActivity(
FlutterActivity
.withCachedEngine("engineID")
.build(this)
)
**Result - **

Now there is no delay. ๐
Similarly, we can add a Flutter screen as a fragment in our existing application with/without a pre-cached engine. Here I'll be using the same FlutterEngine as in FlutterActivity example.
class FlutterFragmentContainerActivity : AppCompatActivity() {
companion object {
// Define a tag String to represent the FlutterFragment within
// this Activity's FragmentManager.
private const val TAG_FLUTTER_FRAGMENT = "flutter_fragment"
}
private var flutterFragment: FlutterFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_flutter_fragment_container)
// Attempt to find an existing FlutterFragment,
// in case this is not the first time that onCreate() was run.
flutterFragment = supportFragmentManager
.findFragmentByTag(TAG_FLUTTER_FRAGMENT) as FlutterFragment?
if (flutterFragment == null) {
val newFlutterFragment =
FlutterFragment.withCachedEngine("engineID")
.build<FlutterFragment>()
flutterFragment = newFlutterFragment
supportFragmentManager
.beginTransaction()
.add(
R.id.fragmentContainer,
newFlutterFragment
)
.commit()
}
}
Make sure FlutterFragment is imported.
import io.flutter.embedding.android.FlutterFragment
Let's see we don't want to open the default Fluttermain() => runApp(), instead we want to specify some entry point to inflate.
We can do that too. First, we need to define a pragma that indicates the Dart compiler that our function will be used in native code. Inmain.dart define -
@pragma('vm:forSpecificRoute')
void specificRoute() => runApp(const AppWithSpecificRoute());
Now we'll define a FlutterEngine and pass the
// Instantiate a FlutterEngine.
flutterEngine = FlutterEngine(this)
// Start executing Dart code to pre-warm the FlutterEngine.
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint(
FlutterMain.findAppBundlePath(), "specificRoute"
)
)
// Cache the FlutterEngine to be used by FlutterActivity.
FlutterEngineCache
.getInstance()
.put("engineID", flutterEngine)
Now we can use this FlutterEngine to inflate a specific widget.
I hope you found this article useful, you can find the source code here.
Follow me for more articles like this. Have a great day! ๐