Flutter 和 Android 混合开发(flutterBoost)

flutter源码依赖简单demo(名字为onlyone):
flutter混合开发中,会有flutter module和flutter plugin

1.分别创建Flutter module和Flutter plugin

2.Flutter module的pubspec.yaml中引入flutter plugin依赖

  only_one_flutter_plugin:
    path: /Users/xufangzhen/FlutterProjects/only_one_flutter_plugin

3.将Flutter Module import进android工程

android工程中修改点如下:
1.settings.gradle文件中创建对flutter module进行评估,并引入

setBinding(new Binding([gradle: this]))
evaluate(new File(settingsDir, './only_one_flutter_module/.android/include_flutter.groovy'))

include ':only_one_flutter_module'
project(':only_one_flutter_module').projectDir = new File('xxx/only_one_flutter_module')

4.在app module中的build.gradle中引入

implementation project(path: ':flutter')
implementation project(path: ':only_one_flutter_plugin')

可能会遇到问题:

  1. 使用flutter v1.12,需要升级android的target sdk 为28及以上
  2. 如果你的工程没有使用androidx,那么你需要将flutter mo,dule中的pubspec.yaml文件里androidX: true去掉。
  3. setting include工程的工程 only_one_flutter_module后,原android工程无法断点调试,只需要将include的名字和路径改成only_one_flutter_module的父目录即可。

引入闲鱼的 flutter_boost

flutter_boost引入主要是解决native跳flutter重复创建flutter engine引题内存等问题,具体可以去闲鱼博客上了解。
到了flutter sdk是1.12.x,flutter engine可以复用了,具体还没看

具体使用如下:

在flutter plugin中pubspec.yarml的,使用引入flutter_boost
查看git上的介绍,不支持android x,flutter sdk是1.12的,使用以下配置

  flutter_boost:
    git:
      url: 'https://github.com/alibaba/flutter_boost.git'
      ref: 'task/task_v1.12.13_support_hotfixes'

flutter plugin 的 android工程的app的build.gradle中添加

    api project(path: ':flutter_boost')

在flutter module的main()方法中,调用plugin的初始化方法

return MaterialApp(
      builder: OnlyOnePlugin.init({
        'one': (pageName, params, _) {
          return OnePage();
        },
        'twoPage': (pageName, params, _) {
          return TwoPage();
        },
      }),
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );

在flutter plugin的lib下创建的OnlyOnePlugin类,
并增加注册、跳转和关闭方法

class OnlyOnePlugin {
  static TransitionBuilder init(Map<String, PageBuilder> builders) {
    FlutterBoost.singleton.registerPageBuilders(builders);
    return FlutterBoost.init();
  }

  static Future<Map<dynamic, dynamic>> openPage(String pageName,
      {Map<dynamic, dynamic> data, Map<dynamic, dynamic> exts}) async {
    return FlutterBoost.singleton
        .open(changeToRouterUrl(pageName), urlParams: data, exts: exts);
  }

  static Future<bool> closePage(BuildContext context,
      {Map<String, dynamic> data, bool animate}) async {
    if (null == context) return Future.value(false);
    String uniqueId = BoostContainer.of(context)?.settings?.uniqueId ?? "";
    return FlutterBoost.singleton.close(uniqueId, result: data, exts: null);
  }

  static const MethodChannel _channel =
      const MethodChannel('only_one_flutter_plugin');

  static Future<String> get platformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }

 ……
}

在flutter plugin的android工程中,进行初始化、容器、bridge等工作开发

初始化:

在application的create方法中调用初始化方法

    public static void initBoost(Application application) {
        FlutterBoost.BoostLifecycleListener boostLifecycleListener = new FlutterBoost.BoostLifecycleListener() {
            @Override
            public void beforeCreateEngine() {
            }

            @Override
            public void onEngineCreated() {
            }

            @Override
            public void onPluginsRegistered() {
            }

            @Override
            public void onEngineDestroy() {
            }
        };


        INativeRouter router = new INativeRouter() {
            @Override
            public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
                openPage(context, url, urlParams, requestCode, exts);
            }
        };

        Platform platform = new FlutterBoost
                .ConfigBuilder(application, router)
                .isDebug(isDebug)
                .whenEngineStart(FlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
                .renderMode(FlutterView.RenderMode.texture)
                .lifecycleListener(boostLifecycleListener)
                .build();
        FlutterBoost.instance().init(platform);
    }
遇到问题:
  1. FlutterBoostPlugin not register yet
    如果出现上面的问题,说明flutter module的android工程里,GeneratedPluginRegistrant
    无法自动生成。com.idlefish.flutterboost.FlutterBoostPlugin.registerWith(shimPluginRegistry.registrarFor("com.idlefish.flutterboost.FlutterBoostPlugin"));
    早期遇到这个问题需要手动注册,现在flutter_boost已经修复

容器:

可以自己写个Flutter容器,加载FlutterBoost里的flutterFragment
再带个启动方法,(用路由的结合下路由,这里略去)

    public static void launch(Activity context, String pageName, JSONObject param, int requestCode) {
        Intent intent = new Intent(context, OnlyFlutterActivity.class);
        intent.putExtra(PAGE_NAME_KEY, pageName);
        intent.putExtra(ROUTER_PARAM_KEY, param);
        context.startActivityForResult(intent, requestCode);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.only_flutter_activity);
        String pageName = getIntent().getStringExtra(PAGE_NAME_KEY);
        HashMap params = (HashMap) getIntent().getSerializableExtra(ROUTER_PARAM_KEY);

        mFragment = new FlutterFragment.NewEngineFragmentBuilder().url(pageName).params(params).build();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_stub, mFragment)
                .commit();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        mFragment.onActivityResult(requestCode, resultCode, data);
    }

其中pageName就是在flutter module里注册进去的页面名。

return MaterialApp(
      builder: OnlyOneFlutterPlugin.init({
        'onePage': (pageName, params, _) {
          print("params = " + params.toString());
          return OnePage(title: "标题1");
        },
        'twoPage': (pageName, params, _) {
          return TwoPage(title: "标题2");
        },
      }),
……

上面看到已经看到了native跳flutter

flutter跳flutter或者flutter跳native只需要调用flutter plugin lib下OnlyOneFlutterPlugin的openPage方法即可

//flutter跳flutter
OnlyOneFlutterPlugin.openPage("twoPage", data: params);
//flutter跳native
OnlyOneFlutterPlugin.openPage("MainActivity", data: params);

flutter端不管跳flutter还是native都调用了
FlutterBoost.singleton.open方法,最终会触发下面这个在初始化时的回调。

  INativeRouter router = new INativeRouter() {
            @Override
            public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
                openPage(context, url, urlParams, requestCode, exts);
            }
        };

我们只需要在openPage的方法中写下时跳native页面还是flutter页面即可。
这里简单的示意下,正确的做法还是要在路由器的拦截器方法里写

    static void openPage(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
        if ("onePage".equals(url) || "twoPage".equals(url)) {
            ……
            OnlyFlutterActivity.launch ……
        } else {
            ……
            AppRouter.launch ……
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容