Flutter mixing: mixing Flutter in Android native

At present, the "Xianyu" client has been written in pure Flutter on the product detail page. It is no problem to write pure Flutter on a single page. By the way, I would like to mention how to easily identify whether a page is Flutter or native (not rigorous, when you know it In the case of Flutter, because RN will also be like this):

  1. Turn on the "Developer Mode" of the phone
  2. Turn on "Show layout boundaries"
  3. Switch back to APP

Take the product list page and product detail page of "Xianyu" as an example:

Product list page and product detail page

Product list page and product detail page

Next, we open the layout border display, you can see that Xianyu’s product list page (left) is natively written, so you can see the layout layer. The darker the color, the more layout layers, while the product details page (right) is Written by Flutter, there is only one layer of layout:

Layout boundary

Layout boundary

Ok, after the digression, let's start mixing Flutter in Android, using the previous "Daily" example.

The plan is like this:

  • Transfer the outer UI framework, including toolbar, to the native for processing
  • Flutter handles ListView, daily report data request logic, etc.

This can basically be a sub-simple mixed compilation example.

the simplest. . . Also count the official Flutter example (raw meat warning): https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps

New Flutter Module

If you want to mix Flutter in Native code, you need to create a Module in Flutter, which is officially created through the command line, but Android Studio's Flutter plugin also provides this function and is more intuitive, so here is Android Studio as an example:

New Flutter Module

New Flutter Module

Next project path, name, etc.:

Flutter Module path configuration

Flutter Module path configuration

Then set the package name and click Finish again.

New Android project

Create a new Android project in the same parent directory of the Flutter Module, if the existing project is fine, the same is true.

New Android project

New Android project

Then go all the way next.

Introduce Flutter in Android project

Add the following code to the settings.gradle of the created Android project:

1
2
3
4
5
setBinding(new Binding([gradle: this]))                                 
evaluate(new File(                                                      
  settingsDir.parentFile,                                               
  'flutter_daily_module/.android/include_flutter.groovy'                          
))

Which settingsDir.parentFilerepresents the parent directory of the current directory, which flutter_daily_moduleis the Flutter Module directory created earlier.

You can see one Fluttermore library module by clicking Sync

Flutter Module

Flutter Module

Then rely on the library just introduced in the Build.gradle of the Application Module:

1
implementation project(':flutter')

Android native code calls Flutter

Let's start with a simple Demo.

We changed the code in Flutter to the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import 'dart:ui';
import 'package:flutter/material.dart';

void main() => runApp(_widgetForRoute(window.defaultRouteName));

Widget _widgetForRoute(String route) {
  switch (route) {
    case 'route1':
      return Center(
        child: Text('route: $route', textDirection: TextDirection.ltr),
      );
    case 'route2':
      return Center(
        child: Text('route: $route', textDirection: TextDirection.ltr),
      );
    default:
      return Center(
        child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
      );
  }
}

The above code will return a Widget, if the input parameter is, route1it will be displayed in the center of the widget route: router1.

In the MainActivity generated by the Android project by default, let's show a route1.

1
2
3
4
5
6
7
8
9
View flutterView = Flutter.createView(
        MainActivity.this,
        getLifecycle(),
        "route1"
);
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(600, 800);
layout.leftMargin = 100;
layout.topMargin = 400;
addContentView(flutterView, layout);

Run the native Android project, you can see the following effects:

FlutterView running effect

FlutterView running effect

FlutterView is not the only way to use it. There is also a way of calling Flutter through FlutterFragment, as shown in the following code:

1
2
3
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fl_flutter_view, Flutter.createFragment("route1"));
fragmentTransaction.commit();

Which fl_flutter_viewcorresponds to a FrameLayout defined in xml in Android:

1
2
3
4
<FrameLayout
    android:id="@+id/fl_flutter_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

The running effect chart is as follows:

FlutterFragment running effect

FlutterFragment running effect

Flutter daily report list embedded in Android native outer framework

After completing the above steps, we have already understood how to call Flutter in Android. Below, we will embed the "Daily" list page of the actual combat series of articles in this "outer frame".

"Daily" pure Flutter project source code:
https://github.com/KevinWu1993/DailyFlutter

Let's first synchronize the main code of the list page in Flutter to flutter_daily_module.

The original "Daily" main.dartcode is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import 'package:flutter/material.dart';
import 'package:zhihudaily/daily/daily_page.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '日报',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: DailyPage(title: '日报'),
    );
  }
}

We changed main.dart in Flutter Module to the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_daily_module/daily/daily_page.dart';

void main() => runApp(_widgetForRoute(window.defaultRouteName));

Widget _widgetForRoute(String route) {
  switch (route) {
    case 'dailyInNative':
      return MaterialApp(
        title: '日报',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: DailyPage(title: '日报', isShowToolbar: false,),
      );
    default:
      return MaterialApp(
        title: '日报',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: DailyPage(title: '日报'),
      );
  }
}

要注意的是default选项,因为Flutter Module也是可以独立运行的,所以留着这个case。

同样的在DailyPage这一个Widget的构造方法里面,增加一个可选“是否显示Toolbar”的参数,目的是在独立运行flutter项目的时候显示状态栏,而在作为library module混编进Android的时候隐藏Toolbar,使用Android原生的Toolbar。

1
DailyPage({Key key, this.title, this.isShowToolbar = true}) : super(key: key);

对于Flutter Toolbar,在DailyPage中构建的方法如下:

1
2
3
4
5
6
7
8
Widget _buildAppBar(BuildContext buildContext) {
  if (widget.isShowToolbar)
    return new AppBar(
      title: Text(widget.title),
    );
  else
    return null;
}

完成上述步骤后,在Android原生代码中调用如下:

1
2
3
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fl_flutter_view, Flutter.createFragment("dailyInNative"));
fragmentTransaction.commit();

Now that the embedding of the daily report list is completed, let's run it:

Native running effect

Native running effect

When running in Flutter standalone mode, it looks like this:

Flutter independent operation effect

Flutter independent operation effect

There is no picture and no truth. Let’s end this article with a layout boundary comparison diagram. Pay attention to the Toolbar. One is native and the other is Flutter:

Layout boundary comparison

Layout boundary comparison

The authors: Kevin Wu

Article link: https://kevinwu.cn/p/964c6c3/

 

Guess you like

Origin blog.csdn.net/MYBOYER/article/details/90737342