Flutter(六)Android与Flutter混合开发(Hybird)

因为笔者本身主要从事是Android开发,所以很多角度都是作为一个Android开发者学习Flutter的角度出发,IOS或者H5的开发同学可以选择性阅读

目录

前言

如果我们目前的项目是Android的,但是接下来我们希望部分页面可以使用Flutter进行开发,甚至我们希望在Native页面中嵌入FlutterUI组件,那么我们该如何实现呢?

创建Flutter Module

假设你现在Android项目的目录的结构是这样的

xxx/flutter_hybrid/FlutterHybridAndroid 

这时候如果你想创建一个Flutter模块,使得Android模块和Flutter模块之间可以进行交互,我们可以通过Android Studio新建一个Flutter Module,具体过程是:File —> New —> New Module ,之后选择Flutter Module,指定Project Location的路径为

xxx/flutter_hybrid

也就是说,最终你的项目结构会是这样的

- flutter_hybrid  
  - flutter_module  
  - FlutterHybridAndroid 

接下来在Android Module的build.gradle文件中添加flutter依赖

//FlutterHybridAndroid/app/build.gradle
...
dependencies {
   implementation project(':flutter')
...
}

Android启动Flutter页面的两种方式

先创建一个Flutter页面

这里比较重要的是window.defaultRouteName这个字段,这个字段可以接收从Native传递过来的参数(下文我们会介绍原生传递参数的方法),也就是说通过这个字段我们就可以进行Flutter页面的路由的分发

import 'dart:ui';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FlutterHybird',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      //window.defaultRouteName可以接收从Native传过来的参数
      home: _widgetForRoute(window.defaultRouteName),
    );
  }
}

Widget _widgetForRoute(String route) {
  switch (route) {
    case 'route1':
      return Center(
        child: Text("route1"),
      );
    case 'route2':
      return Center(
        child: Text("route2"),
      );
    default:
      return Center(
        child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
      );
  }
}
  1. 直接启动一个FlutterActivity

我们可以直接在Android的MainActivity中启动一个FlutterActivity,这里的initialRoute方法中传递的参数就对应Flutter层的window.defaultRouteName

findViewById(R.id.jump).setOnClickListener(v -> {
        startActivity(FlutterActivity.withNewEngine()
              .initialRoute("route2")
              .build(MainActivity.this));
});

注意:需要在AndroidManifest.xml注册FlutterActivity


  1. 启动复写后的FlutterActivity(推荐)

自己创建一个FlutterAppActivity继承自FlutterActivity

public class FlutterAppActivity extends FlutterActivity {
    public final static String INIT_PARAMS = "initParams";
    private String initParams;

    public static void start(Context context, String initParams) {
        Intent intent = new Intent(context, FlutterAppActivity.class);
        intent.putExtra(INIT_PARAMS, initParams);
        context.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initParams = getIntent().getStringExtra(INIT_PARAMS);
    }

    /**
     * 重载该方法来传递初始化参数
     *
     * @return
     */
    @NonNull
    @Override
    public String getInitialRoute() {
        return initParams == null ? super.getInitialRoute() : initParams;
    }
}

MainActivity中启动FlutterAppActivity(另外别忘了在AndroidManifest.xml中注册FlutterAppActivity

findViewById(R.id.jump).setOnClickListener(v -> {
    FlutterAppActivity.start(MainActivity.this,"route2");
});

两种启动方式的区别

如果单纯只是想打开一个Flutter页面,两种方式实际上基本没有太大区别,第一种方式也许还会更简单一点。但是,在Flutter开发中,我们往往还需要开发一些Native插件供Flutter调用,如果使用复写FlutterActivity的方式更有利于我们在FlutterActivity中注册我们的Native插件,所以实际开发中一般推荐使用第二种方式

扩展思考

initialRoute从名称上看起来是Flutter提供给我们进行Native与Flutter交互的路由跳转的,但是实际上他就是一个字符串,我们不仅仅可以传递一个路由名称,有时候我们也可以通过这个参数传递一串JSON数据,然后在Flutter端进行解析,这样我们就可以通过这个参数做更多的事情

在Android原生页面中嵌入FlutterUI组件

activity_main.xml

FrameLayout用于承载Flutter组件




    

    

    


MainActivity.java

使用FragmentManagerFlutterFragment添加到FrameLayout容器中

FlutterFragment fragment = FlutterFragment.withNewEngine().initialRoute("route1").build();
getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.container, fragment)
        .commit();

运行结果

上半部分是原生的TextView,下半部分是Flutter的Text组件

总结

本节主要介绍了Native和Flutter之间的页面跳转,以及同一个页面中Native与Flutter组件的组合。接下来会介绍如何编写Android插件与Flutter进行数据交互

你可能感兴趣的:(Flutter(六)Android与Flutter混合开发(Hybird))