大家好,欢迎来到IT知识分享网。
前言
最近在接触这方面的东西,也踩了很多坑,这里主要做下记录和分享,帮助大家避坑,也让自己铭记。
路由方面我是用闲鱼的FlutterBoost,今天就主要讲一下FlutterBoost 的集成之路,以及产物打包等流程。
在这里我先插个题题外话,关于Flutter的话题在各大平台都有论述,有一些中庸的观点,也有一些极端的观点,也有将Flutter 与Compose相比较的。在这里想表达一下我的观点,Flutter 是跨端方案的首选,如果有跨端的需求,Flutter还是一个很好的选择。在没有跨端需求的情况下,为了节省人力成本,可以在一些不重要的模块使用Flutter开发,或者项目前期为了快速上线,也可以使用Flutter进行快速开发,毕竟Flutter 在开发效率方面还有有目共睹的(熟练使用的前提下)。如果是自己做产品,我还是建议使用原生进行开发。
还有一个话题是将Flutter和Compose相比较的,在这里我想说明的是,Flutter的重点是跨端,Compose的重点在Android的声明式UI,两者的侧重点不同。
好了,题外话就说到这里,接下来开始聊我们今天的主题。
FlutterBoost的集成
在这里先贴一下FlutterBoost的官方地址
https://github.com/alibaba/flutter_boost
首先在同一级目录中新建两个项目,一个flutter moudle项目,一个是Android 项目。
然后再在flutter_moudle的pubspec.yml 的dependencies 中 进行依赖flutter_boost
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
flutter_boost:
git:
url: https://github.com/alibaba/flutter_boost.git
ref: v3.0-preview.18
然后运行 flutter pub get 进行依赖导入。
然后在main.dart文件中,进行路由配置
引自flutter boost 官方文档 https://github.com/alibaba/flutter_boost/blob/master/docs/install.md
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
void main() {
///这里的CustomFlutterBinding调用务必不可缺少,用于控制Boost状态的resume和pause
CustomFlutterBinding();
runApp(MyApp());
}
///创建一个自定义的Binding,继承和with的关系如下,里面什么都不用写
class CustomFlutterBinding extends WidgetsFlutterBinding with BoostFlutterBinding {}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
/// 由于很多同学说没有跳转动画,这里是因为之前exmaple里面用的是 [PageRouteBuilder],
/// 其实这里是可以自定义的,和Boost没太多关系,比如我想用类似iOS平台的动画,
/// 那么只需要像下面这样写成 [CupertinoPageRoute] 即可
/// (这里全写成[MaterialPageRoute]也行,这里只不过用[CupertinoPageRoute]举例子)
///
/// 注意,如果需要push的时候,两个页面都需要动的话,
/// (就是像iOS native那样,在push的时候,前面一个页面也会向左推一段距离)
/// 那么前后两个页面都必须是遵循CupertinoRouteTransitionMixin的路由
/// 简单来说,就两个页面都是CupertinoPageRoute就好
/// 如果用MaterialPageRoute的话同理
Map<String, FlutterBoostRouteFactory> routerMap = {
'mainPage': (RouteSettings settings, String uniqueId) {
return CupertinoPageRoute(
settings: settings,
builder: (_) {
Map<String, Object> map = settings.arguments as Map<String, Object> ;
String data = map['data'] as String;
return MainPage(
data: data,
);
});
},
'simplePage': (settings, uniqueId) {
return CupertinoPageRoute(
settings: settings,
builder: (_) {
Map<String, Object> map = settings.arguments as Map<String, Object>;
String data = map['data'] as String;
return SimplePage(
data: data,
);
});
},
};
Route<dynamic> routeFactory(RouteSettings settings, String uniqueId) {
FlutterBoostRouteFactory func = routerMap[settings.name] as FlutterBoostRouteFactory;
return func(settings, uniqueId);
}
Widget appBuilder(Widget home) {
return MaterialApp(
home: home,
debugShowCheckedModeBanner: true,
///必须加上builder参数,否则showDialog等会出问题
builder: (_, __) {
return home;
},
);
}
@override
Widget build(BuildContext context) {
return FlutterBoostApp(
routeFactory,
appBuilder: appBuilder,
);
}
}
class MainPage extends StatelessWidget {
const MainPage({Object data});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(child: Text('Main Page')),
);
}
}
class SimplePage extends StatelessWidget {
const SimplePage({Object data});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(child: Text('SimplePage')),
);
}
}
flutter 部分 就集成完了,然后是 Android 部分。
在项目根目录的setting.gradle中导入flutter_moudle工程
setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'flutter_module/.android/include_flutter.groovy'
))
include ':flutter_module'
project(':flutter_module').projectDir = new File('../flutter_module')
然后在app的build.gradle中引用一下
implementation project(':flutter')
implementation project(':flutter_boost')
在清单文件中声明一下activity
<activity
android:name="com.idlefish.flutterboost.containers.FlutterBoostActivity"
android:theme="@style/Theme.AppCompat"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize" >
</activity>
<meta-data android:name="flutterEmbedding"
android:value="2">
</meta-data>
最后在Application 进行注册一下flutter boost
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
FlutterBoost.instance().setup(this, new FlutterBoostDelegate() {
@Override
public void pushNativeRoute(FlutterBoostRouteOptions options) {
//这里根据options.pageName来判断你想跳转哪个页面,这里简单给一个
Intent intent = new Intent(FlutterBoost.instance().currentActivity(), YourTargetAcitvity.class);
FlutterBoost.instance().currentActivity().startActivityForResult(intent, options.requestCode());
}
@Override
public void pushFlutterRoute(FlutterBoostRouteOptions options) {
Intent intent = new FlutterBoostActivity.CachedEngineIntentBuilder(FlutterBoostActivity.class)
.backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.transparent)
.destroyEngineWithActivity(false)
.uniqueId(options.uniqueId())
.url(options.pageName())
.urlParams(options.arguments())
.build(FlutterBoost.instance().currentActivity());
FlutterBoost.instance().currentActivity().startActivity(intent);
}
}, engine -> {
});
}
}
这里我们就完成了集成。
FlutterBoost的使用
这里就简单一下具体使用,详细使用参考官方文档
Flutter开启新页面
BoostNavigator.instance.push(
"yourPage", //required
withContainer: false, //optional
arguments: {"key":"value"}, //optional
opaque: true, //optional,default value is true
);
///or
Navigator.of(context).pushNamed('simplePage', arguments: {'data': _controller.text});
关闭页面
///pop一次
BoostNavigator.instance.pop(result);
Android开启新页面
FlutterBoostRouteOptions options = new FlutterBoostRouteOptions.Builder()
.pageName("pageName")
.arguments(new HashMap<>())
.requestCode(1111)
.build();
FlutterBoost.instance().open(options);
关闭页面
FlutterBoost.instance().close(uniqueId);
给Android发送消息:
BoostChannel.instance.sendEventToNative('flutter_msg', {'img_file': file.toString()});
在Android监听消息
val listener = EventListener { key: String, args: Map<Any?, Any?> ->
when (key) {
"weeklyToNative" -> {
val path = args["img_file"]?.toString()?.getFileName()
path?.let {
showShareDialog<String>(path, false)
}
}
}
}
remover = FlutterBoost.instance().addEventListener("flutter_msg", listener)
remover.remove()//可以在页面销毁的时候移除监听
这样就完成了 flutter 和原生之间交互。
但是这样还不完善,像我们有个需求就是flutter传数据给原生,原生进行一个弹窗。所以我们需要进行改进一下。
我们新建一个FlutterPage类,然后继承自FlutterBoostActivity ,然后在Application 中进行替换一下
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
FlutterBoost.instance().setup(this, new FlutterBoostDelegate() {
@Override
public void pushFlutterRoute(FlutterBoostRouteOptions options) {
//在这里将原来的FlutterBoostActivity 换成我们自己的 FlutterPage
Intent intent = new FlutterBoostActivity.CachedEngineIntentBuilder(FlutterPage.class)
.....
FlutterBoost.instance().currentActivity().startActivity(intent);
}
}, engine -> {
});
}
}
上文我们提到了flutter 消息的监听,就可以在FlutterPage 中进行监听,可以依附这个activity 进行弹窗等UI操作。
编译产物
在flutter moudle中,可以通过Build->Flutter->Buiold AAR ,来将整个moudle 打包成aar 提供给我们项目原生项目使用。也可以通过flutter build aar 命令 来进行打包,通过 –output-dir 参数来修改产物仓库的路径。这样会有一个缺点,仓库的路径只能设置在本地,如果是单人开发的话,可能没有问题,直接依赖自己本地的仓库就可以了,如果是多人协作开发, 大家每个人都需要在本地重新进行build aar 一下,这样的话就很麻烦。
既然有麻烦就需要解决麻烦。
我的想法是既然可以在project中通过对本地仓库 的flutter moudle 的aar 进行引用,那我们通过一个Android moudle 也可以进行依赖引用。
具体flutter 产物 aar 的用法,在打包完成之后,控制台上会有对应的使用提示,按照提示去依赖就就好了。
当我们在android 的moudle 中 进行打包aar 的时候,会发现产物的体积很小
这是因为进行打包的时候并不会将flutter moudle的 aar 的其他aar依赖进行打包进去。(aar不能进行二次打包)
这是时候就需要借助 fat-aar-android 这个插件帮我合并一下
Github:https://github.com/kezong/fat-aar-android
具体方法在官方文档有详细说明。我们使用的时候需要下面这个进行配置,这样就可以将所有远程依赖在pom中声明的依赖项同时打入在最终产物里
fataar {
transitive = true
}
然后通过exclude关键字将多余的依赖过滤一下:
//例子
embed('com.facebook.fresco:fresco:1.11.0') {
exclude(group:'com.facebook.soloader', module:'soloader')
transitive = false
}
注:我这里测试使用这种过滤方式效果不明显,故自己魔改源码(只增加了一行代码),只依赖了自己需要依赖的选项。
在这里还有一个操作,我是将libflutter.so放在了libs目录下
否则的话,项目依赖了最终产物之后也不能将libflutter.so打包进apk内。
这就是我们最终产物了, 可以看到我们需要的依赖都已经打包进去了。
然后在android moudle 的 build.gradle 中 配置一下maven-publish插件,就可以将我们的产物上传私仓, 大家就可以方便使用了。
在这里还是有一些缺陷,就是进行需要两步操作,现在flutter 打包,然后在Android 进行上传。一键操作的方案 尝试过gradle task的形式,因为这种在win环境 还是在mac 环境上都支持的,但是在实践过程中发现 gradle 执行shell cd命令的时候,会失效,无法切换目录,因为flutter build aar 的命令 需要在flutter moudle 的根目录下执行的,所以这种方案就放弃了。目前在尝试 CI/CD 流水线的形式,还在搭建环境。我这也算抛砖引玉,想大家集思广益,看看有没有其他更合适的方案。
总结
今天主要是跟大家分享了 Flutter 和原生混编的一种方案,使用flutter boost 和原生进行交互,以及flutter 编译产物的 快捷打包交付方案。大家有好的想法也可以多多留言交流。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/48230.html