Flutter Hybrid Development: Android Project Integration Flutter Module Detailed Guide

This article was first published under the WeChat Public Number "Android Development Tour". Welcome to your attention and get more technical dry goods

Hybrid Development Application Scenarios

At present, the development of pure Flutter applications in China is still relatively small, and most companies using Flutter also use mixed development.So what are the main scenarios for hybrid development?

  • Join as a separate page, jumping from a native page to a Flutter page, or from a Flutter page to a native page.

  • Embedded as part of the page.

Create Flutter module

Since we're doing mixed development, we're certainly working on Android native projects.If the path to the native project is this: flutter/flutter_hybrid/native, then we need to create the Flutter module in the flutter_hybrids directory above native.

cd flutter/flutter_hybrid/
//Create a flutter_module that supports AndroidX
flutter create --androidx -t module flutter_module 
//Create flutter_module that does not support AndroidX
flutter create -t module flutter_module

So the first thing we need to do when we create a module is to determine if the native project already supports AndroidX, and if it does, we need to add the--androidx parameter.

The input background console prints as follows:

$ flutter create -t module flutter_module
Creating project flutter_module...
  flutter_module/test/widget_test.dart (created)
  flutter_module/flutter_module.iml (created)
  flutter_module/.gitignore (created)
  flutter_module/.metadata (created)
  flutter_module/pubspec.yaml (created)
  flutter_module/README.md (created)
  flutter_module/lib/main.dart (created)
  flutter_module/flutter_module_android.iml (created)
  flutter_module/.idea/libraries/Flutter_for_Android.xml (created)
  flutter_module/.idea/libraries/Dart_SDK.xml (created)
  flutter_module/.idea/modules.xml (created)
  flutter_module/.idea/workspace.xml (created)
Running "flutter pub get" in flutter_module...                      1.2s
Wrote 12 files.

All done!
Your module code is in flutter_module/lib/main.dart.

Seeing All done means that our project has been created.The entire module directory is basically the same as the native Flutter, mainly the Android, iOS host project and lib directories, and the pubspec.yaml file.

Add Flutter module Dependency

Once the module project is created, it needs to be added to the Android project.Let's open the settings.gradle file for the Android project and add the following code:

setBinding(new Binding([gradle: this]))
evaluate(new File(
        //flutter_module is the name of the module created

setBinding and evaluate allow any Flutter plug-in for the Flutter module, including itself, to exist in settings.gradle in a similar manner: flutter, package_info, video_player.

Then open app/build.gradle to add dependencies in the dependencies tag:

implementation project(':flutter')

This completes the addition of dependencies in two steps. Why add "flutter" instead of "flutter_module"?Because a directory called Flutter is generated in the directory of an Android project when the project is compiled, that's what we rely on.It is also important to note that minSdkVersion in gradle must be greater than or equal to 16, since the minimum version supported by this flutter.Also add compile using java8.Add in the Android tag in app/build.gradle:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8

Call Flutter module

Once the dependency is complete, we can call the flutter module to create the UI.Flutter gives us two ways to call it, createView, which is loaded as a view.The other is createFragment, which is loaded as a fragment in Android.

createView method:

public class MainActivity extends AppCompatActivity {

    protected void onCreate(@Nullable Bundle savedInstanceState) {
//        setContentView(R.layout.activity_main);

        FlutterView flutterView = Flutter.createView(this, getLifecycle(), "initialRoute");


createFragment method:

public class MainActivity extends AppCompatActivity {

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        //container is the placeholder FrameLayout in the activity_main layout
        transaction.replace(R.id.container, Flutter.createFragment("initialRoute"));


This loads the Flutter default home page into the application.

As you can see from the above two sections of code, there is an "initialRoute" parameter that tells the Dart code which widget to display in the Flutter view.Let's modify the main.dart code in the module to load our own page.

We set up two routes to show route1Widget and route2Widget, respectively, and display reminder text when there is no match.

import 'package:flutter/material.dart';
import 'dart:ui';

void main() => runApp(MyApp(
      //Getting the parameters passed from native through window.defaultRouteName requires importing the dart:ui package
      initParams: window.defaultRouteName,

class MyApp extends StatelessWidget {
  final String initParams;

  MyApp({Key key, this.initParams}) : super(key: key);

  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter_Android Mixed Development',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      home: HomePage(initParams: initParams),

class HomePage extends StatefulWidget {
  final String initParams;

  const HomePage({Key key, this.initParams}) : super(key: key);

  _HomePageState createState() => _HomePageState();

class _HomePageState extends State<HomePage> {
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _widgetRoute(widget.initParams),

///Routing Forwarding
Widget _widgetRoute(String route) {
  switch (route) {
    case "route1":
      return route1Widget();
    case "route2":
      return route2Widget();
      return notFoundWidget();

Widget route1Widget() {
  return Center(
    child: Text(
      "this is route1Widget",
      style: TextStyle(color: Colors.red, fontSize: 20),

Widget route2Widget() {
  return Center(
    child: Text(
      "this is route2Widget",
      style: TextStyle(color: Colors.blue, fontSize: 20),

Widget notFoundWidget() {
  return Center(
    child: Text(
      "Unmatched to route 111",
      style: TextStyle(fontSize: 40),

We will now replace the initial Route parameter when loading Flutter with "route1", which will load the route1Widget, replace it with "route2", and load the route2Widget.Otherwise, the notFoundWidget will be displayed.Of course, we can pass a routing parameter directly, but because it's a string itself, we can do something about it.For example, if you pass a json string, can you do a lot?I won't post demo here because, like the logic above, you can try it.

Hot restart/reload

When you write a pure Flutter application, you know it has a hot restart/reload function, but when you do mixed development, you will find that the hot restart/reload function is not working.So how do I turn on hot restart/reload in hybrid development?

  • First connect to our device or simulator
  • Close our App, exit the background, run the flutter attach command in terminal
$ flutter attach
Waiting for a connection from Flutter on Android SDK built for x86...

Waiting for the device to connect.It is important to note that if a computer is connected to more than one device, you need to use the -d command to specify a device with the device id as the parameter.

 flutter attach -d 'Your device id'
  • Then start our application and you will see console output:
Syncing files to device Android SDK built for x86...             1,393ms

🔥  To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on Android SDK built for x86 is available at:
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".

That means we connected successfully.The output log also tells us how to use the hot restart/reload function.

Enter the following command in Terminal:

r: Hot load;
R: Hot restart;
h: Get help;
d: Disconnect;
q: quit;

The commands d and q here both exit debugging, except that the d command is simply a disconnect and the q command will back the application to the background.

Debugging Dart code

How do we debug dart code during mixed development as well?

  • Close our apps
  • Click the Flutter Attach button on the Android Studio toolbar (Flutter and Dart plugins need to be installed)

  • Start our app

Now you can debug the DT code in mixed development mode just as you would debug a regular Flutter project.


These are the basic instructions on how to access the Flutter module in Android native projects, including module creation, dependency, invocation and debugging.Other communications, such as iOS access to the Flutter module, between Android and Flutter projects, and between iOS and Flutter, will be explained in subsequent articles.Friends are tired of reading because it's too long to write in one piece.So there will be at least three related articles to meet you in the future.Start by focusing on the public number to get instant feeds of relevant articles.

All Demo sources have been uploaded to the background, follow the public number reply "Android hybrid development" to get a download link.

If you think the article is good, please share it with us. You are certainly my greatest encouragement and support.

Recommended reading

Essential Dart Foundation for Flutter Development: Quick Start for Dart

Scan the QR code below to focus on the public number for more technical dry goods.

Tags: Android Gradle xml iOS

Posted on Thu, 07 Nov 2019 08:11:29 -0500 by joshberm