美文网首页Flutter
Flutter(六)Android与Flutter混合开发(Hy

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

作者: Geekholt | 来源:发表于2020-08-14 14:41 被阅读0次

    因为笔者本身主要从事是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

    <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" />
    
    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组件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@color/colorAccent"
            android:gravity="center"
            android:text="Hello World!" />
    
        <FrameLayout
            android:id="@+id/container"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1">
    
        </FrameLayout>
    
    </LinearLayout>
    

    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混合开发(Hy

        本文链接:https://www.haomeiwen.com/subject/phvgdktx.html