前言
下午公众号给我推送了flutter 1.12正式版本发布的消息,官方声称这是flutter迄今为止最大的一次更新
- 支持IOS 13暗黑模式
- Flutter代码傻瓜式集成到原生项目-Add-to-App
- N多widget的更新以及bug修复
- Beta 版本的 web 支持以及 Alpha 版本的 macOS 支持
详情请参见:Flutter 1.12.13 release notes ,需要自己搭梯子
其中最让我痛心的莫过于Add-to-App功能,因为我特么上午才写了一篇关于flutter和native交互的博客,整整搞了两天!!!! 在我那篇博文中主要是集成了闲鱼的flutter-boost进行页面的跳转和数据交互。
为什么用flutter-boost?
- 可以共享FlutterEngine呀,为什么原生打开Flutter页面的一瞬间会出现白屏?因为FlutterEngine的初始化需要时间
- 数据交互easy得很,native-flutter, flutter-native, flutter-flutter,涵盖了我们能想到的各种姿势
- 这是在flutter 1.12版本之前最好的解决方案了,尽管有一些bug,但是闲鱼的大佬们都修复的差不多了
然而1.12版本的发布,我感觉flutter-boost这个库渐渐的可能就不会维护了,因为他有的功能官方基本上都支持了,而且花样更多,api更规范(除开数据交互,这一点我在官方文档上还没有看到介绍,不过这都是小case了,自己琢磨一下肯定有很不错的解决方案),下面让我们来解开Add-to-App的面纱
正文
这里我们只介绍android studio集成方式,因为这种方式最傻瓜易懂,而且今后肯定也是主流方案,想了解手动集成的同志请移步官方文档
开始之前先打个预防针,如果你的app支持x86架构,那还是放弃算了,因为flutter在release模式下只支持armeabi-v7a
,arm64-v8a 架构,所以在使用的时候记得在app的build.gradle中设置
android {
//...
defaultConfig {
ndk {
// Filter for architectures supported by Flutter.
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
吼吼吼,现在开始了。。。。。
1.在你的原生项目中使用File->New->New Module新建一个Flutter Module
然后填写module的信息
然后就ok啦!native项目会自动依赖新建的module,等build完成就可以直接运行了,是不是超级方便!!
添加Flutter页面
1.在AndroidManifest.xml中注册FlutterActivity
flutter提供了一个FlutterActivity来承载flutter页面,和其它activity一样,他也必须在manifest中注册
<activity
android:name="io.flutter.embedding.android.FlutterActivity"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
/>
@style/LaunchTheme可以被替换为任意的主题,所以根据你自己的需求修改即可。
2.启动FlutterActivity
当FlutterActivity在manifest中注册后,你可以在app的任意地方自动他,下面是一段启动FlutterActivity的代码
myButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity.createDefaultIntent(currentActivity)
);
}
});
使用createDefaultIntent来启动activity,系统默认了dart的入口是main()方法,起始的路由是“/”。使用intent时dart的入口不能改变,但是能改变起始路由,下面的例子演示了如何自定义起始路由
myButton.addOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity
.withNewEngine()
.initialRoute("/my_route")
.build(currentActivity)
);
}
});
细心的同学看到了,我们除了改变了路由地址,还添加了一个withNewEngine配置,从字面意思上可以猜出是创建一个新的Flutter Engine,这个FlutterActivity将拥有他自己的FlutterEngine实例。但是这会带来一个问题,FlutterEngine的创建很耗时,也非常消耗资源,如果activity和engine是一对一的关系,那么每次启动都避免不了白屏现象,而且内存会暴增。这肯定是不能接受了,我们的诉求大概有两点:
- 只创建一个FlutterEngine,所有的flutter页面共享
- FlutterEngine能不能在FlutterActivity打开之前就创建好,这样就能避免白屏现象
为了解决上面两个问题,Flutter为我们带来了cached flutter-engine
3.Cached Flutter Engine
根据你产品的实际情况和需求,在合适的时候创建FlutterEngine,让他先启动并缓存起来,这样我们拿来用的时候就不会有上面两个问题了。
下面的代码演示了在Application中预启动FlutterEngine
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 初始化FlutterEngine.
flutterEngine = new FlutterEngine(this);
// 使用dart executor来预热FlutterEngine.
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartEntrypoint.createDefault()
);
// 缓存FlutterEngine,并且给一个id,方便后面获取
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine);
}
}
我们给FlutterEngine指定id后就可以在使用的时候直接用这个id去获取了,注意不要写错了这个id的名称,建议使用一个常量来保存。
需要注意的是当executeDartEntrypoint方法被调用的时候,意味着你的dart入口函数也被执行了,如果你的main方法里面有runApp,那么你的flutter页面就会运行在一个size为0的window上,直到FlutterEngine依附到FlutterActivity,FlutterView,或FlutterFragment上。所以你需要保证你的app在FlutterEngine预热到真正显示这期间能正常运行。
下面我们来看看在FlutterActivity中如何用过缓存的FlutterEngine:
myButton.addOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
FlutterActivity
.withCachedEngine("my_engine_id")
.build(currentActivity)
);
}
});
一句话就ok,使用withCachedEngine("my_engine_id"),传入的参数就是在application中定义的id。这时候你再去启动FlutterActivity的时候你会发现白屏的现象几乎没有了,在release模式下效果更佳。
注:
1.当FlutterEngine和FlutterActivity的生命周期是没有任何管理的,当FlutterActivity,FlutterFragment销毁后FlutterEngine依然在运行,如果你想节省资源销毁他,可以在FlutterEngineCache类中通过id去获取到这个FlutterEngine,并调用FlutterEngine.destroy()进行销毁操作。
2.避免白屏现象并不是我们预先启动FlutterEngine的唯一原因,由于FlutterEngine和FlutterActivity是没有关联的,所以只要是启动后你可以在任意时刻执行任意的dart代码,只要不是和UI相关的(毕竟这时候UI还没有显示出来),比如我们可以进行网络请求,缓存数据等。当你做这些操作的时候也不要忘了要遵守android系统的规范
今天时间比较紧,只是写了一个皮毛,后续有更深入的研究再来补!