[Flutter Mixed Development] How to start Flutter in an Android project

insert image description here

foreword

Flutter can complete projects independently, but in the case of existing projects, the best way is mixed development and gradual transition. In this way, native and flutter codes will coexist, and the most important thing is how native starts the flutter page, and how flutter interacts with native.

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

Introduce Flutter into existing projects

In the existing Android project, create a new flutter module. After creating the module, you will find that it is automatically dependent on the main module. Of course, if we use this flutter module in other projects, this step will not be performed automatically, so we must first register it in setting.gradle, as follows:

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

Then depend on the main module:

implementation project(path: ':flutter')

This enables hybrid development.

Start the flutter page

After creating a new flutter module, a main page will be created automatically, so how does native open this page?

First add in 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"
           />

Then use the code to open the flutter main page

startActivity(FlutterActivity.createDefaultIntent(this))

So how to 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() {
    
    
    return _SecondPage();
  }
 
}
 
class _SecondPage extends State<SecondPage>{
    
    
  @override
  Widget build(BuildContext context) {
    
    
    return Scaffold(
        appBar: AppBar(
          title: Text("test"),
        ),
        body:Text("test")
    );
  }
}

Then register this page under the App of main.dart:

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(),  //也可以用其他方式注册
      },
    );
  }
}

In this way, the following code can be used to open this page in flutter:

Navigator.of(context).pushNamed("second");

In Android, you can use the following code to open the page:

startActivity(FlutterActivity.withNewEngine().initialRoute("second").build(this))

Accelerate start

When the flutter page is opened through the above code, a black screen will appear, and the time is not short, which greatly affects the experience. Because every time a new flutter engine is created (the inside of the createDefaultIntent function is actually withNewEngine().build(launchContext)).

The official solution is to use engine cache, such as adding cache to Appliation:

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

Then change the startup to:

startActivity(FlutterActivity.withCachedEngine("main").build(this))

But the above is only to start the main page. If you want to start other pages, such as second, you need to continue to add cache:

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

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

startActivity(FlutterActivity.withCachedEngine("second").build(this))

By caching the engine, the black screen time at startup is shortened a lot, and it is almost imperceptible (note that the screen may be slightly black for the first time).

Start parameter passing

Above we opened the main and second pages without passing parameters, so if we want to pass in some parameters necessary for initialization, how to deal with it?

At present, the flutter framework does not encapsulate the api with parameters, that is to say, the native jump to flutter officially has no parameters. But our actual scene has such a demand, how to deal with it?

The official did not give the corresponding api, so we can only find a way from the route. First, change the way of registering routes in the app. The above directly uses the map form of routes, and we replace it with the RouteFactory form of onGenerateRoute, 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"),
              ),
            );
          });
        }
      },

The settings.name here is the route, because we want to add parameters after the route, so we can judge which page is from the beginning.

Note: In the example, the route url is directly passed to the page. In fact, it should be parsed here and passed to the page in the form of a map.

Then modify the Second page:

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

There is no parsing here, and 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))

You can pass parameters.

But this leads to another problem, because the above startup method does not use the engine cache. If the engine cache is used, the route must be set in advance so that it can be placed in the cache in Appllication. But since we want to pass parameters, it means that the route is dynamically changed, so these two are in conflict, so that the startup cannot be accelerated when the parameters are passed?

Because our parameter passing itself is not an official API behavior, the official engine cache does not have corresponding support. But this problem is not unsolvable. For example, the flutter hybrid framework opened by Xianyu——flutter-boost, can easily realize native porting parameters to open flutter pages. However, there are many things involved here, the most important thing is the way of interaction between Flutter and native, this can be seen in my other blog "[ Flutter Advanced] Three Ways to Interact with Native "

Summarize

The above briefly understands how to introduce the Flutter module and start the page in the existing Android project. The advantage of this is that you can use Flutter to develop new pages without large-scale reconstruction of existing projects, and gradually transition to Flutter.

This article is about the Android project, so what about the Ios project? Please see
[Flutter Mixed Development] Introducing Flutter into Existing iOS Projects

Guess you like

Origin blog.csdn.net/chzphoenix/article/details/130750902