JaminZhou
首发于JaminZhou
Flutter开发干货!关于Flutter和已有App混合开发的一些个人思考和探索

Flutter开发干货!关于Flutter和已有App混合开发的一些个人思考和探索

2个多月前,我开始探索flutter的使用方法,并用flutter对已有app进行集成,遇到了一些困惑,也摸索出一些解决问题的方法,希望可以帮助到大家。

注意

作为Google推出的移动跨平台框架,flutter跟随开发者的脚步不断迭代更新,这篇文章具有时效性,我从flutter稳定版本v1.2.1开始接触,目前最新的版本是v1.5.4-hotfix.2。


flutter module更新时间线

2018年2月22日

issue 14821中出现了关于“如何在已有app上进行混合开发并减少摩擦”的讨论,因为有很多开发者并不想直接把现有app直接替换成flutter,而是想在现有应用程序上添加一个或多个flutter屏幕进行使用。

https://github.com/flutter/flutter/issues/14821

2018年4月6日

flutter wiki上出现了第一篇关于《如何在已有app添加flutter并持续更新》的文章。

https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps

2018年6月22日

发起了第一个关于flutter module的pull request,只能用于Android上,并在flutter v0.5.6加入stable。

https://github.com/flutter/flutter/pull/18697

更多

flutter团队一直在对已有app集成做持续跟进,你可以在 github.com/flutter/flut 看到最新进展。


flutter和native混合开发解决方案

现在flutter可以用module的方式对现有app进行集成,你可以参照上面的wiki,这非常容易做到。github.com/flutter/flut

如果你是独立开发者,那么直接用官方wiki上的接入方式不会有太大问题。但如果在一个团队协作中,这样的做法有可能就不那么友好了,因为这不仅会侵入native工程,还有可能产生一些问题。我们该怎么解决呢?

iOS以cocoapods通过ruby的eval binding方式接入,并需要加入run script,因为podhelper.rb中存在post_install,如果原工程也有post_install,就会出现如下错误

[!] Invalid `Podfile` file: [!] Specifying multiple `post_install` hooks is unsupported..

需要如何解决,详见

https://github.com/flutter/flutter/issues/26212#issuecomment-477487234

Android的处理方法和iOS有所不同。它以子module方式接入,需要settings.gradle和build.gradle添加依赖,在以子module接入时,会产生一些问题。如果原工程有添加自定义buildTypes和flavor等功能选项,就需要在相应的module中补上自定义buildTypes和flavor。以module方式创建的flutter项目,.android是被gitignore的,每次通过flutter packages get自动生成,就不太好做版本控制,当然你可以选择使用“git add -f.”,flutter module中每引入一个plugin就会在原生Android项目中产生一个module,如果依赖多个那就会产生多个module,这需要补上非常多的buildType和falavor,管理起来也不是特别方便。

一个好的flutter混合项目的需要具备哪些

  • flutter可以不依赖native独立开发,debug快速便捷
  • native可以非常简单的集成并不破坏原项目,也不需要添加flutter环境,当然能以其他SDK,framework的通用接入方式是最好
  • flutter开发完成能release bundle供native端进行使用,也就是第二点需要达到的目的

改造flutter module

我们需要对flutter module进行改造来满足更多工作上的需求,flutter module本身可以不依赖native进行独立开发,并且能快速便捷的debug。所以第一点目的达到了。

这里推荐使用Android Studio进行flutter开发,因为Android Studio的Flutter插件功能更强大(虽然我更喜欢VSCode),比如flutter inspector, flutter outline等等。

iOS目前集成外部framework的方式有Cocoapods, Carthage等,Android使用Maven是最方便的。很多开发者都关心这个问题:能不能把flutter module在iOS中导出.framework .a,在Android中导出.aar 然后使用cococapods和meaven进行接入?答案是肯定的,后面会有详细的说明。

写到这里上述两点都能得到解决,但还遗留了一些问题。因为flutter目前还不支持单个flutter engine进行多个窗口绘制,参考wiki,如果需要接入多个窗口(iOS:FlutterViewController, Android: FltterActivity, FlutterFragment),就需要初始化多个flutter engine,随之带来的就是内存消耗不断增加。

该如何实现单个flutter engine支持多窗口绘制呢?阿里开源了解决上述问题的flutter plugin:flutter_boost (github.com/alibaba/flut)

这里我们需要给module添加flutter_boost依赖。引入flutter_boost也随之带来了一些需要优化问题:比如在flutter侧进行独立开发不是特别友好,破坏了原本入口结构。要如何解决会在后面细说。

如何构建一个混合项目

github.com/JaminZhou/fl

为了看起来更直观,我把flutter和native项目融合到了一起,实际开发中,两者应使用不同的仓库来管理。

示例分为三部分1. flutter 2. native 3. release脚本+repo。

flutter里包含1. module 2. plugin 3. example(module方式接入flutter,实际可有可无,因为会产生重复)

首先继续解决“如何对引入flutter_boost进行优化”的问题,我是这样处理的:添加了开发环境,对flutter_boost和其他一些需要用到native的plugin进行隔离,不受native限制直接进行flutter的开发。

因此,我加入了`main_dev.dart`,用于区分隔离开发和生产环境,在Android Studio添加一个新的Flutter Configuation,Dart enrtypoint指向main_dev.dart

接下来需要解决“如何和native进行交互”的问题。

首先请把FlutterView想象成WebView,我们是如何和前端进行协作开发的?客户端和前端将各自独立开发互不干扰,客户端和前端约定好JSBridge用于数据交互,然后在客户端的WebView容器中指定url就可以展示相应内容,并可以进行Remote Debug。回到Flutter,我们已经有了flutter_boost用于展示FlutterView,还欠缺类似于JSBridge用于数据交互的桥梁,所以我们需要自定一个自己的plugin用户数据交互。

我在plugins里创建了一个flutter_bridge,它的功能和JSBridge一样。

想知道plugin和底层是如何交互的可以看这篇文章

flutter.dev/docs/develo

flutter.dev/docs/develo

在flutter_bridge中,我用protocol(iOS), abstract class(Android)定义好类似于JSBridge的协议,然后运用runtime调用实现方法(runtime会增加开发效率,但性能上又还是直接用if else或者switch case更好,见仁见智,诸君可以自行选择)。

我在iOS中还添加了`FLBFlutterViewContainer`的Category,用于隐藏导航栏。当FLBFlutterViewContainer消失,就会回到之前导航栏的状态,目的是想让flutter自行控制导航栏的事件,UI等等。

flutter团队也提供了很多plugin, package(纯dart),如果没有满足你的需求,你也可以开发自己的plugin和package

github.com/flutter/plug

pub.dev/

负责flutter的同学开发完项目,如何把成果输出给native端呢?

回想一下,当写Web端同学开发完,他可以部署到服务器,只需要把最后的url移动端的人接入即可;写ReactNative的同学开发完也可以导出JSBundle让移动端的同学接入。

那flutter可以导出哪些东西呢?

flutter提供了对iOS,Android的导出命令 `flutter build ios --release`和`flutter build android --release`,,一般都在module目录下的build文件夹,在.ios/Flutter和.android/Flutter/build目录下能找到以下这些:

  • iOS:lib{plugin_name}.a App.framework Flutter.framework
  • Android:flutter-release.aar {plugin_name}-release.aar

所以,iOS我们可以输出成cocoapods,Android上传到maven,这也是release_ios.sh和release_android.sh做的一些事情。需要注意的是执行flutter build xxx --release 输出的.a .framework .aar不会包含x_86架构,所以模拟器不能运行(Flutter.framework是个例外,无论release还是debug导出都会有x_86),我们也可以轻松解决这些问题(flutter build xxx --debug .a也不会包括x_86,可以用`xcrun xcodebuild build -configuration Debug ARCHS='x86_64' xxxxx`)

如何使用自动化发布脚本详见flutter-native-hybrid的README.md


注意事项

参考文献

github.com/flutter/flut

github.com/flutter/flut

github.com/flutter/flut

github.com/flutter/flut

github.com/flutter/plug

pub.dev/

发布于 2019-06-15

文章被以下专栏收录