Flutter can be a standalone project, but in the case of existing projects the best approach is to mix and transition. This allows both the Native and the flutter code to coexist. The key is how the flutter starts the page and how the flutter interacts with the native.

This article uses Android as an example to show how to introduce Flutter in an existing project, start flutter, speed up flutter startup, and pass parameters.

Flutter was introduced into existing projects

Create a Flutter Module in your existing Android project. After you create a module, you will find that it is automatically dependent on the main module. Of course, this step will not be automatically implemented if other projects use the Flutter module. Therefore, register the Flutter module with setting.gradle as follows:

setBinding(new Binding([gradle: this]))
evaluate(new File(
  settingsDir,
  'flutter_module/.android/include_flutter.groovy'
))
 
include ':flutter_module'
Copy the code

Then rely on the main Module:

implementation project(path: ':flutter')
Copy the code

This allows for mixed development.

Start flutter page

A new Flutter Module automatically creates a main page. How does Native open this page?

First add to the manifest of the main Module:

       <activity
           android:name="io.flutter.embedding.android.FlutterActivity"
           android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
           android:hardwareAccelerated="true"
           android:windowSoftInputMode="adjustResize"
           />
Copy the code

Then use the code to open the Flutter home page

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

So how do I open other pages?

For example, we create a new Flutter page second:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
 
class SecondPage extends StatefulWidget{
  @override
  State<StatefulWidget> createState(a) {
    return_SecondPage(); }}class _SecondPage extends State<SecondPage>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("test"),
        ),
        body:Text("test")); }}Copy the code

Dart then registers the page in the main.dart App:

class MyApp extends StatelessWidget {
 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
      routes: {
        "second" : (BuildContext context) => SecondPage(),  // You can also register in other ways}); }}Copy the code

This opens the page in Flutter with the following code:

Navigator.of(context).pushNamed("second");
Copy the code

On Android, you can open the page with the following code:

startActivity(FlutterActivity.withNewEngine().initialRoute("second").build(this))
Copy the code

accelerating

When opening the flutter page through the above code, a black screen will appear, which is not short and will affect the experience. This is because every time a new flutter engine is created (createDefaultIntent withNewEngine().build(launchContext)).

The official solution is to use Engine Cache, such as adding a cache to Appliation:

        var flutterEngine = FlutterEngine(this)
        flutterEngine.dartExecutor.executeDartEntrypoint(
                DartExecutor.DartEntrypoint.createDefault()
        )
        FlutterEngineCache.getInstance().put("main", flutterEngine)
Copy the code

Then change the startup to:

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

If you want to start other pages, such as Second, you need to continue adding the cache:

        var flutterEngine2 = FlutterEngine(this)
        flutterEngine2.navigationChannel.setInitialRoute("second")
        flutterEngine2.dartExecutor.executeDartEntrypoint(
                DartExecutor.DartEntrypoint.createDefault()
        )
        FlutterEngineCache.getInstance().put("second", flutterEngine2)
Copy the code

Note that the route is set by setInitialRoute. Then start:

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

With the cache Engine, the black screen time at startup is reduced to almost imperceptible (note that it may be slightly black the first time around).

Start the participation

We have opened the main and second pages without passing in parameters. What if we want to pass in some parameters necessary for initialization?

Currently, the Flutter framework does not encapsulate an API that carries parameters, which means that native jump flutter has no parameters. But our actual scene has such requirements, how to deal with?

There is no official API, so we have to find a way from route. First of all, change the way of registering route in app. Above, the form of routes map is directly used, and we change it to the form of onGenerateRoute RouteFactory, as follows:

      onGenerateRoute: (RouteSettings settings) {
        if(settings.name.startsWith("second")) {return MaterialPageRoute(builder: (BuildContext context) {
            return SecondPage(settings.name);
          });
        }
        else {
          return MaterialPageRoute(builder: (BuildContext context) {
            return Scaffold(
              body: Center(
                child: Text("page not found"),),); }); }},Copy the code

Settings. name is route, and since we want to add parameters after route, we can use the beginning to determine which page it is.

Note: In the example, the route URL was passed directly to the page. Instead, it should be resolved and passed to the page as a map.

Then modify the Second page:

class SecondPage extends StatefulWidget{
  String url;
 
  SecondPage(String url){
    this.url = url;
  }
 
  @override
  State<StatefulWidget> createState(a) {
    return_SecondPage(); }}class _SecondPage extends State<SecondPage>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("test"),
        ),
        body:Text("test:${widget.url}")); }}Copy the code

There is no parsing here, the URL is displayed directly, the purpose is to pass the parameters in place.

Finally, use the following code in Native:

startActivity(FlutterActivity.withNewEngine().initialRoute("second? text=second test").build(this))
Copy the code

You can pass parameters.

This introduces another problem, because engine cache is not used in this startup. If engine cache is used, the route must be specified in advance to be cached in Appllication. The route is dynamically changed, so the two are in conflict, so we can’t speed up the startup in the case of parameter passing.

Since passing the parameter itself is not the behavior of the official API, the official Engine Cache does not support it. However, this problem is not impossible to solve. For example, the open flutter hybrid framework of The Idle fish, the flutter-boost, can easily implement the native to open the flutter page. However, there are a lot of things involved in flutter. I will use a separate article to explain how flutter-boost realizes parameter transfer and fast start.