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!