使用Flutter_Boost进行混合开发 Android

2,253 阅读5分钟

使用Flutter_Boost进行混合开发-Android

  1. 创建Flutter项目,用 flutter create -t module fluttr_test 命令来创建,flutter_test为我们的Flutter的工程名

用Android studio打开刚才创建的功能,我们刚创建好的时候不会有.android与.ios这两个目录的,用Android studio打开构建一下就出来了(也可以用flutter make-host-app-editable命令来创建出来),.android与.ios中都存在一个Flutter目录,这个很重要,我试过只有通过flutter create -t module XXX命令生成出来的才有这个Flutter的文件夹,直接创建出来的没有,Flutter这个是我们flutter的库项目,Android用来生成aar,iOS用来生成framework

image-20190708152623127.png

2.接下来就是依赖了,添加flutter的依赖

这里要注意层级关系,要和flutter:一个层级

flutter_boost: ^0.0.415

image-20190711141333017.png

添加完依赖后,在flutter中初始化flutter_boost,配置路由

import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:fluttr_test/firstpage.dart';
import 'package:fluttr_test/second.dart';

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

class MyApp extends StatefulWidget {

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyApp> {


  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    FlutterBoost.singleton.registerPageBuilders({
      'first':(pageName,params,_){//格式为路由名称:(pageName,params,_)pageName是路由名称,params为原生传递过来的参数
        return FirstPage();//返回一个widget
      },
      'second':(pageNmae,params,_){
        return Second();
      },

    });

    FlutterBoost.handleOnStartPage();//查询当前的顶层页面,并加载它
  }

  @override
  Widget build(BuildContext context) {
      return MaterialApp(
        title: 'oa',
        builder: FlutterBoost.init(),
        home: Container(),
      );
  }
}
  1. flutter配置完了,接下来就是配置Android
  • settings.gradle中添加,这里我是把flutter_test工程放在和Android工程同一级目录下的(是与project同一级,不是与module同一级),这里如果报文件找不到那就是你的路径写错了,重新检查一下路径

这里切记flutter一定要生成出.android与.ios两个文件

setBinding(new Binding(gradle:this))
evaluate(new File('../flutter_test/.android/include_flutter.groovy'))
  • app.gradle中配置flutter与flutter_boost
implementation project(path:':flutter')
implementation project(":flutter_boost")
  • Application中进行初始化
FlutterMain.startInitialization(this);

FlutterBoostPlugin.init(new IPlatform() {
    @Override
    public Application getApplication() {
        return FunnyApplication.this;
    }

    /**
     * 获取应用入口的Activity,这个Activity在应用交互期间应该是一直在栈底的
     * @return
     */
    @Override
    public Activity getMainActivity() {
        if (MainActivity.sRef != null) {
            return MainActivity.sRef.get();
        }

        return null;
    }

    @Override
    public boolean isDebug() {
        return true;
    }

    /**
     * 如果flutter想打开一个本地页面,将会回调这个方法,页面参数将会拼接在url中
     *
     * 例如:sample://nativePage?aaa=bbb
     *
     * 参数就是类似 aaa=bbb 这样的键值对
     *
     * @param context
     * @param url
     * @param requestCode
     * @return
     */
    @Override
    public boolean startActivity(Context context, String url, int requestCode) {
        Debuger.log("startActivity url="+url);

        return PageRouter.openPageByUrl(context,url,requestCode);
    }

    @Override
    public Map getSettings() {
        return null;
    }
});
  1. flutter与Android的初始化都完成了,接下来就是完成我们的混合需求,我们考虑五种情况:Android跳转到flutter页面,flutter跳转到Android页面,Android中嵌入Flutter界面、Flutter中嵌入Android界面、一个原生界面中同时有flutter界面与原生界面
  • Android跳转到flutter页面:
    • 创建一个activity,继承BoostFlutterActivity,我们主要关注的主要有两个方法,getContainerName(),getContainerParams();
      getContainerName()配置对应key,就是我们在flutter中配置路由的key;
      getContainerParams()配置我们要传递给flutter页面的数据;
      然后直接跳转到这个activity就行了startActivity(new Intent(getActivity(), FlutterPageActivity.class));
package com.example.funny.flutter;

import com.taobao.idlefish.flutterboost.containers.BoostFlutterActivity;

import java.util.HashMap;
import java.util.Map;

import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class FlutterPageActivity extends BoostFlutterActivity {

    @Override
    public void onRegisterPlugins(PluginRegistry registry) {
        GeneratedPluginRegistrant.registerWith(registry);
    }

    /**
     * 该方法返回当前Activity在Flutter层对应的name,
     * 混合栈将会在flutter层根据这个名字,在注册的Route表中查找对应的Widget
     *
     * 在flutter层有注册函数:
     *     FlutterBoost.singleton.registerPageBuilders({
     *       'first': (pageName, params, _) => FirstRouteWidget(),
     *       'second': (pageName, params, _) => SecondRouteWidget(),
     *       ...
     *     });
     *
     * 该方法中返回的就是注册的key:first , second
     *
     * @return
     */
    @Override
    public String getContainerName() {
        return "first";
    }

    /**
     * 该方法返回的参数将会传递给上层的flutter对应的Widget
     *
     * 在flutter层有注册函数:
     *    FlutterBoost.singleton.registerPageBuilders({
     *       'first': (pageName, params, _) => FirstRouteWidget(),
     *       'second': (pageName, params, _) => SecondRouteWidget(),
     *        ...
     *     });
     *
     * 该方法返回的参数就会封装成上面的params
     *
     * @return
     */
    @Override
    public Map getContainerParams() {
        Map<String,String> params = new HashMap<>();
        params.put("aaa","bbb");
        return params;
    }
}
  • flutter跳转到android:
    • flutter中直接调用openPage
      第一个参数是路由url,我们在Android中要对应上的,第二个是我们要传给Android的参数,query不是必须的,名字自己定,然后他会拼接到url后面的
FlutterBoost.singleton.openPage("oa://createNew", {
  "query": {"userid":"123"}
});
  • android中:我们在application中进行了初始化,初始化的时候我们实现了一个startActivty的方法,我们就是通过这个方法来进行调整Activity的,在这里去判断应该调整哪个activity,我上面是按照官网来搬了一个统一路由跳转的类
public class PageRouter {

    public static final String CREATE_NEW = "oa://createNew";

    public static boolean openPageByUrl(Context context, String url) {
        return openPageByUrl(context, url, 0);
    }

    public static boolean openPageByUrl(Context context, String url, int requestCode) {
        try {
            if(url.startsWith(CREATE_NEW)){
                context.startActivity(new Intent(context,CreateFunnyActivity.class));
                return true;
            } else {
                return false;
            }
        } catch (Throwable t) {
            return false;
        }
    }
}
  • Android中嵌入Flutter界面,这里我们继承的就不是Activity而是BoostFlutterFragment了,使用方法和activity没什么区别,说到这里就顺带说一下一个原生界面中附带flutter和原生两种界面的问题了,我们就是直接把fragment弄成一个小区域就成了
public class FlutterPageFragment extends BoostFlutterFragment 
  • Flutter中嵌入Android的View
    • 首先定义一个类实现PlatformView
package com.example.funny.flutter;

import android.content.Context;
import android.view.View;
import android.widget.TextView;

import java.util.Map;

import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;

public class MyFlutterView implements PlatformView {

    private TextView view;

    public MyFlutterView(Context context, BinaryMessenger messenger, int id, Map<String, Object> map) {
        TextView textView = new TextView(context);
        textView.setText("这是AndroidView");
        this.view = textView;//我们返回一个text
    }

    @Override
    public View getView() {
        return view;
    }

    @Override
    public void dispose() {

    }
}
  • 建立一个工厂
public class MyFlutterFactory extends PlatformViewFactory {


    private BinaryMessenger message;

    public MyFlutterFactory(BinaryMessenger messenger) {
        super(StandardMessageCodec.INSTANCE);
        this.message = messenger;
    }

    @Override
    public PlatformView create(Context context, int i, Object o) {
        Map<String, Object> map = (Map<String, Object>) o;

        return new MyFlutterView(context, message, i, map);
    }
}
  • 在我们的BoostFlutterActivity中注册一下这个View(以下截取了部分代码,就是我上面那个类)
public class FlutterPageActivity extends BoostFlutterActivity {

    @Override
    public void onRegisterPlugins(PluginRegistry registry) {
        GeneratedPluginRegistrant.registerWith(registry);

        final String key = FlutterPageActivity.class.getCanonicalName();

        if (registry.hasPlugin(key)) return;

        PluginRegistry.Registrar registrar = registry.registrarFor(key);
        registrar.platformViewRegistry().registerViewFactory("plugins.nightfarmer.top/myTestView", new MyFlutterFactory(registrar.messenger()));
    }
  • Flutter中我们直接引用(这里我判断了设备是Android还是ios,如果是Android,我就加载Android的view,用AndroidView()这个方法,如果不是Android设备我就走flutter的)
child:Platform.isAndroid?AndroidView(viewType: 'plugins.nightfarmer.top/myTestView'):Text("这还是Flutter 的文字",style: TextStyle(color: Colors.white),)