The Flutter hybrid development family includes the following:

  • Embed native View-Android
  • Embed native View-ios
  • Communicate with native -MethodChannel
  • Communicate with native -BasicMessageChannel
  • Communicate with native -EventChannel
  • Add Flutter to Android Activity
  • Add Flutter to Android Fragment
  • Add Flutter to iOS

Share one article every weekday, welcome to follow, like and forward.

Create a Flutter Module

Flutter can be embedded into Android native projects either as source code or as an AAR. The integration process can be done using Android Studio or manually. Android Studio is highly recommended.

First create an Android project and create an empty Activity:

After the Android project is created, add the Flutter Module using Android Studio. In the Android native project, go to File > New > New Module… Create Flutter Module

Note: Android Studio version 3.5 and later, the Flutter IntelliJ Plugin version 42 and later.

Select Flutter Module in the dialog box that pops up to select the Module type and click Next.

To set the Project name of the Flutter Module, the Flutter SDK, and so on, click Next:

Set the package name for the Flutter Module and click Finish:

After compilation, the code for the Flutter module will be generated in the current App directory with the following structure:

Start page to load the Flutter

Load the Flutter page into MainActivity (the default startup page) and modify the MainActivity:

package com.flutter.androidflutter

import io.flutter.embedding.android.FlutterActivity

class MainActivity : FlutterActivity(a)Copy the code

You read that right, just make MainActivity inherit from FlutterActivity.

Note: the package name of FlutterActivity is IO flutter. Embedding. Android. FlutterActivity

Jump to the Flutter page

MainActivity (default startup page) add a button to redirect to a new page that loads the Flutter. The MainActivity code is as follows:

package com.flutter.androidflutter

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import io.flutter.embedding.android.FlutterActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.setOnClickListener {
            startActivity(Intent(this,SecondFlutterActivity::class.java))
        }
    }
}
Copy the code

The SecondFlutterActivity code looks like this:

package com.flutter.androidflutter

import io.flutter.embedding.android.FlutterActivity

class SecondFlutterActivity:FlutterActivity(a)Copy the code

Register this Activity in androidmanifest.xml:

<? The XML version = "1.0" encoding = "utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.flutter.androidflutter"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> ... <activity android:name=".SecondFlutterActivity"/> </application> </manifest>Copy the code

SecondFlutterActivity simply inherits FlutterActivity, in which case you can also use FlutterActivity directly:

startActivity(Intent(this, FlutterActivity::class.java))
Copy the code

Or:

startActivity(FlutterActivity.createDefaultIntent(this))
Copy the code

Register FlutterActivity in Androidmanifest.xml:

<activity android:name="io.flutter.embedding.android.FlutterActivity"/>
Copy the code

The effect is the same as above.

FlutterActivity loads the main method of lib/main.dart in the Flutter Module. If there are multiple Flutter pages, how can I specify the jump? The OnePage code is as follows:

class OnePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Text('This is the One page'),),); }}Copy the code

FlutterActivity specifies that the loading page needs to use named routes. MyApp is modified as follows:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(

        primarySwatch: Colors.blue,
      ),
      routes: {
        'one_page':(context){
          return OnePage();
        },
        'two_page':(context){
          return TwoPage();
        }
      },
      home: MyHomePage(title: 'Flutter Demo Home Page')); }}Copy the code

Click on the Flutter page to load the OnePage page:

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.setOnClickListener {
            startActivity(
                FlutterActivity
                    .withNewEngine()
                    .initialRoute("one_page")
                    .build(this)}}}Copy the code

Engine cache

When loading the FlutterActivity page, there was obviously a black screen for a period of time, during which the FlutterEngine was started. The startup time of the Flutter engine was different on different mobile phones, and the better the performance of the Flutter engine was, the shorter it was. Each FlutterActivity page also starts an engine, so it is strongly recommended not to create multiple FlutterActivity (or start multiple instances of FlutterActivity) in a single project, otherwise memory will get bigger and bigger. Here is the memory variation diagram for creating an instance of FlutterActivity every 3 seconds:

To reduce the latency of FlutterActivity pages and the memory growth of multiple FlutterActivity instances, we can use the Flutter engine cache. Start the Flutter engine before starting FlutterActivity, and then load the page using the cached engine, usually in Application:

class MyApplication : Application() {
    lateinit var flutterEngine: FlutterEngine

    override fun onCreate(a) {
        super.onCreate()
        flutterEngine = FlutterEngine(this)
        flutterEngine.dartExecutor.executeDartEntrypoint(
            DartExecutor.DartEntrypoint.createDefault()
        )
        FlutterEngineCache
            .getInstance()
            .put("engine_id", flutterEngine)
    }

}
Copy the code

Engines that use caching:

startActivity(
    FlutterActivity
        .withCachedEngine("engine_id")
        .build(this))Copy the code

On the same phone, the effect is very clear, with the black screen time greatly reduced, but there is still a brief black screen.

Note that when using the cache engine, it is not the life cycle of the FlutterActivity (or FlutterFragment), but the life cycle of the entire App (created and destroyed in the Application). Of course, it can also be destroyed in advance:

flutterEngine.destroy()
Copy the code

In addition, the debug and release versions of the project have a great impact on performance. If you want to test its performance, you must test it under release.

Using the new engine above, you can specify FlutterActivity (or FlutterFragment) to configure the initial route, but you cannot configure the initial route in FlutterActivity (or FlutterFragment) with the cache engine. Since the cache engine is already up and running, you can specify its initial route when you start the cache engine:

flutterEngine = FlutterEngine(this)

flutterEngine.navigationChannel.setInitialRoute("one_page")

flutterEngine.dartExecutor.executeDartEntrypoint(
    DartExecutor.DartEntrypoint.createDefault()
)
FlutterEngineCache
    .getInstance()
    .put("engine_id", flutterEngine)
Copy the code

What if a cache engine is used to specify different routes in FlutterActivity (or FlutterFragment)? A method channel needs to be created, and the flutter receives specific messages to switch between different routes.

communication

Lao Meng Flutter blog (330 controls usage + practical primer series) : laomengit.com