In this paper, the target
Successfully integrated Flutter into an Android native project
Warning
- Starting with Flutter v1.1.7, the Flutter module only supports AndroidX applications
- In release mode, Flutter only supports the following architectures: X86_64, Armeabi-V7A, ARM64-V8A, MIPS and x86 are not supported, so you need to select the architecture that Flutter supports before introducing Flutter
android{
/ /...
defaultConfig {
// Configure the supported dynamic library types
ndk {
abiFilters 'x86_64'.'armeabi-v7a'.'arm64-v8a'}}}Copy the code
Some applicable scenarios for mixed development
- Add the Flutter page to the existing project
- Embed the Flutter module in native pages
- Embed native modules in the Flutter project
The main steps
- Create a Flutter module
- Add Flutter Module dependencies to existing Android projects
- Early Kotlin/Java calls the Flutter Module
- Writing Dart code
- Run the project
- Hot restart/reload
- Debugging the Dart code
- Release application
Please put all the projects in the same folder
- WorkProject
- AndroidProject
- iOSProject
- flutrter_module
Copy the code
There are native Android module, native iOS module and Flutter module respectively under WorkProject, and these three modules are in parallel structure
Create a Flutter module
Before doing mixed development we need to create a Flutter Module at this time
cd xxx/WorkProject /
Copy the code
Create flutter_module
flutter create -t module flutter_module
Copy the code
To specify a package name
flutter create -t module --org com.example flutter_module
Copy the code
It will then create successfully
- Android-flutter_module Android host project
- Ios-flutter_module ios host project
- Dart code for the lib-Flutter_module
- Pubspec.yaml-flutter_module has project dependency profiles Due to the host project, our Flutter_module can run independently with additional configuration. Open the Flutter_module project with The Flutter and Dart plugin installed in AndroidStudio and run it directly with the run button
Build a Flutter AAR (optional)
You can run the following command to build an AAR
cd .android/
./gradlew flutter:assembleRelease
Copy the code
It in the android/Flutter/build/outputs/generate a Flutter in aar / – the aar archive file
Add Flutter Module dependencies to existing Android intentions
Open our Android project settings.gradle and add the following code
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'flutter_module/.android/include_flutter.groovy'
))
The flutter_module can be displayed under the Project of the current AS to facilitate viewing and writing Dart code
include ':flutter_module'
project(':flutter_module').projectDir = new File('.. /flutter_module')
Copy the code
SetBinding and evaluate allow the Flutter module, including itself, to exist in setting.gradle in a manner similar to that of the Flutter package_info :video_player
Added: Flutter dependencies
dependencies {
implementation project(':flutter')}Copy the code
Add Java8 compilation options
Because The Android Engine for Flutter uses Java8 features, you need to configure the Java8 compilation options for your project when introducing Flutter
Android {compileOptions {sourceCompatibility = 1.8 targetCompatibility = 1.8}}Copy the code
Call the Flutter Module in Kotlin
We have added the necessary dependencies for Flutter for our Android project. Now let’s look at how to call the Flutter module in the Fragment in Kotlin’s way. Here we can optimize the Flutter to increase the loading speed and enable the Flutter module to open in seconds
Native Kotlin side code
/** * The abstract base class of a flutter fragment can be inherited from **/
abstract class FlutterFragment(moduleName: String) : IBaseFragment() {
private val flutterEngine: FlutterEngine?
private lateinit var flutterView: FlutterView
init{ flutterEngine =FlutterCacheManager.instance!! .getCachedFlutterEngine(AppGlobals.get(), moduleName)
}
override fun getLayoutId(a): Int {
return R.layout.fragment_flutter
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?). {
super.onViewCreated(view, savedInstanceState)
(mLayoutView as ViewGroup).addView(createFlutterView(activity!!))
}
private fun createFlutterView(context: Context): FlutterView {
val flutterTextureView = FlutterTextureView(activity!!)
flutterView = FlutterView(context, flutterTextureView)
return flutterView
}
/**
* 设置标题
*/
fun setTitle(titleStr: String){ rl_title.visibility = View.VISIBLE title_line.visibility = View.VISIBLE title.text = titleStr title.setOnClickListener {}}/** * life cycle tells flutter */
override fun onStart(a) {
flutterView.attachToFlutterEngine(flutterEngine!!)
super.onStart()
}
override fun onResume(a) {
super.onResume()
/ / for flutter > = v1.17flutterEngine!! .lifecycleChannel.appIsResumed() }override fun onPause(a) {
super.onPause() flutterEngine!! .lifecycleChannel.appIsInactive() }override fun onStop(a) {
super.onStop() flutterEngine!! .lifecycleChannel.appIsPaused() }override fun onDetach(a) {
super.onDetach() flutterEngine!! .lifecycleChannel.appIsDetached() }override fun onDestroy(a) {
super.onDestroy()
flutterView.detachFromFlutterEngine()
}
}
Copy the code
R.l ayout. Fragment_flutter layout
<? 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">
<RelativeLayout
android:id="@+id/rl_title"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_45"
android:background="@color/color_white"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:gravity="center"
android:textColor="@color/color_000"
android:textSize="16sp" />
</RelativeLayout>
<View
android:id="@+id/title_line"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="2px"
android:background="@color/color_eee" />
</LinearLayout>
Copy the code
/** ** Flutter cache management, mainly to manage multiple FLUTTER engines **/
class FlutterCacheManager private constructor() {
/** * associated object, keep singleton */
companion object {
// The likes page is the main entry for flutter startup by default
const val MODULE_NAME_FAVORITE = "main"
// Recommendation page
const val MODULE_NAME_RECOMMEND = "recommend"
@JvmStatic
@get:Synchronized
var instance: FlutterCacheManager? = null
get() {
if (field == null) {
field = FlutterCacheManager()
}
return field
}
private set
}
/** * Preloads the Flutter */ when idle
fun preLoad(context: Context){
// Perform the preload task when the thread is idle
Looper.myQueue().addIdleHandler {
initFlutterEngine(context, MODULE_NAME_FAVORITE)
initFlutterEngine(context, MODULE_NAME_RECOMMEND)
false}}/** * Initializes Flutter */
private fun initFlutterEngine(context: Context, moduleName: String): FlutterEngine {
/ / flutter engine
val flutterLoader: FlutterLoader = FlutterInjector.instance().flutterLoader()
val flutterEngine = FlutterEngine(context,flutterLoader, FlutterJNI())
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint(
flutterLoader.findAppBundlePath(),
moduleName
)
)
// Save to engine cache
FlutterEngineCache.getInstance().put(moduleName,flutterEngine)
return flutterEngine
}
/**
* 获取缓存的flutterEngine
*/
fun getCachedFlutterEngine(context: Context? , moduleName:String):FlutterEngine{
var flutterEngine = FlutterEngineCache.getInstance()[moduleName]
if(flutterEngine==null&& context! =null){
flutterEngine=initFlutterEngine(context,moduleName)
}
returnflutterEngine!! }}Copy the code
Concrete business class use
// Initialize it in app initialization
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
FlutterCacheManager.getInstance().preLoad(this); }}Copy the code
Collection page
class FavoriteFragment : FlutterFragment(FlutterCacheManager.MODULE_NAME_FAVORITE) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?). {
super.onViewCreated(view, savedInstanceState)
setTitle(getString(R.string.title_favorite))
}
}
Copy the code
Recommended page
class RecommendFragment : FlutterFragment(FlutterCacheManager.MODULE_NAME_RECOMMEND) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?). {
super.onViewCreated(view, savedInstanceState)
setTitle(getString(R.string.title_recommend))
}
}
Copy the code
The Dart end code
import 'package:flutter/material.dart';
import 'package:flutter_module/favorite_page.dart';
import 'package:flutter_module/recommend_page.dart';
// There must be at least one entry, and the following man() and recommend() function names correspond to those defined in FlutterCacheManager
void main() => runApp(MyApp(FavoritePage()));
// Must be annotated
@pragma('vm:entry-point')
void recommend() => runApp(MyApp(RecommendPage()));
class MyApp extends StatelessWidget {
final Widget page;
const MyApp(this.page);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( body: page, ), ); }}Copy the code
Dart side favorites page
import 'package:flutter/material.dart';
class FavoritePage extends StatefulWidget {
@override
_FavoritePageState createState() => _FavoritePageState();
}
class _FavoritePageState extends State<FavoritePage> {
@override
Widget build(BuildContext context) {
return Container(
child: Text("Collection")); }}Copy the code
Dart recommendation page
import 'package:flutter/material.dart';
class RecommendPage extends StatefulWidget {
@override
_RecommendPageState createState() => _RecommendPageState();
}
class _RecommendPageState extends State<RecommendPage> {
@override
Widget build(BuildContext context) {
return Container(
child: Text("Recommended")); }}Copy the code
The final result
At the end
If you study with me, you can pay attention to my public account, ❤️ program ape Development Center ❤️, and we will share technology regularly every week. Join me and learn together!