Updated: Add a flutter screen to your Android app
Has Flutter become your new favourite tool for building mobile apps? But migrating your huge native CodeBase to Flutter in one go is impractical.
To solve this, flutter provides a feature called add-to-app. It allows you to build parts of your app in Flutter and integrate them incrementally in your native app.
In this article, I will show how to integrate a flutter screen into the Android codebase.
Prerequisite
Set ABI filters to supported architectures
Flutter does not support mips
and x86
architectures for AOT.
So, We are explicitly specifying the three AOT-supported architectures, armabi-v7a
, arm64-v8a
and x86_64
.
// file: my_project/app/build.gradle
android {
//…
defaultConfig {
ndk {
// Filter for architectures supported by Flutter.
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
}
}
}
Java 11 requirement
Declare Java 11 source compatibility in app/build.gradle
android {
// ...
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
// ...
}
Create a new flutter module
Create a flutter module in the same folder where the android project lives
cd some_path/all_my_projects
flutter create -t module --org com.example my_flutter_module
Integrate the Flutter module into the Android app
There are 3 ways in which we can integrate a flutter module our android app.
- Automatic: using Android studio
- Manual: using AAR method
- [Does not work] Manual: Depend on the module’s source code
1. Automatic: Using Android Studio
Before Android Studio 4.0, It was possible to create a new module and have it integrated using Android studio’s graphical interface.
Starting Android Studio 4.0, this method no longer works and we are not going to talk about it
2. Manual: using AAR method
This option packages your Flutter library as a generic local Maven repository composed of AARs and POMs artifacts. This option allows your team to build the host app without installing the Flutter SDK. You can then distribute the artifact from a local or remote repository.
cd some_path/all_my_projects/my_flutter_module
flutter build aar
After the command completes, the console shows the exact steps that we need to follow to integrate this aar into Android native app
# Sample output
➜ my_flutter flutter build aar
💪 Building with sound null safety 💪
Running Gradle task 'assembleAarDebug'... 36.8s
✓ Built build/host/outputs/repo.
Running Gradle task 'assembleAarProfile'... 19.4s
✓ Built build/host/outputs/repo.
Running Gradle task 'assembleAarRelease'... 20.4s
✓ Built build/host/outputs/repo.
Consuming the Module
1. Open <host>/app/build.gradle
2. Ensure you have the repositories configured, otherwise add them:
String storageUrl = System.env.FLUTTER_STORAGE_BASE_URL ?: "https://storage.googleapis.com"
repositories {
maven {
url '/Users/sanniprasad/Documents/PROJECTS/my_flutter/build/host/outputs/repo'
}
maven {
url "$storageUrl/download.flutter.io"
}
}
3. Make the host app depend on the Flutter module:
dependencies {
debugImplementation 'com.my_flutter.my_flutter:flutter_debug:1.0'
profileImplementation 'com.my_flutter.my_flutter:flutter_profile:1.0'
releaseImplementation 'com.my_flutter.my_flutter:flutter_release:1.0'
}
4. Add the `profile` build type:
android {
buildTypes {
profile {
initWith debug
}
}
}
To learn more, visit https://flutter.dev/go/build-aar
Note: If you created your Android project after Gradle 6.8 was released, You may need to paste the repositories {…} piece into settings.gradle under dependencyResolutionManagement
. Because you won’t find the place where we are used to put the gradle repository references.
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
# this section start
String storageUrl = System.env.FLUTTER_STORAGE_BASE_URL ?: "https://storage.googleapis.com"
maven {
url '/Users/sanniprasad/Documents/PROJECTS/my_flutter/build/host/outputs/repo'
}
maven {
url "$storageUrl/download.flutter.io"
}
# this section end
}
}
3. [No longer works] Depend on the module’s source code
This technique is broken on the stable flutter SDK as of 16 Apr ‘23
Include the Flutter module as a subproject in the host app’s settings.gradle
:
Advantages of this technique:
- No need to build AAR files after making changes in the Flutter code base
- Faster development cycle
// Assuming my_flutter_module is a sibling to my_android_app.
include ':app' // assumed existing content
setBinding(new Binding([gradle: this])) // new
evaluate(new File( // new
settingsDir.parentFile, // new
'my_flutter_module/.android/include_flutter.groovy' // new
))
The binding and script evaluation allows the Flutter module to include
itself (as :flutter
) and any Flutter plugins used by the module ( in the evaluation context of your settings.gradle
.
In short, the Flutter project includes itself along with all Flutter plugins in the build process of the Android app
And the last step is, Add the flutter dependency in app/build.gradle
// android/build.gradke file
dependencies {
implementation project(':flutter')
}
Integration Done…. Now we can try to open the Flutter module from Android.
Trigger Flutter module from Android native codebase
Step 1: Add FlutterActivity to AndroidManifest.xml
Add this to your manifest under <application> tag
<activity
android:name="io.flutter.embedding.android.FlutterActivity"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
/>
Please note that it may fail to understand LaunchThme in newer projects.
The solution is to use any theme that works
Step 2: Start the flutter activity
myButton.setOnClickListener {
// start a flutter activity
startActivity(
FlutterActivity.createDefaultIntent(this)
)
}
You must see your Flutter app loaded… Congratulations… 🎉
Please post your questions below, or feel free to reach out to me if you need help fixing issues related to the add-to app.
Here is a Demo app that I built.