带你不到80行代码搞定Flutter热更新
一、需要热更新的背景
Flutter作为跨平台方案,相信最近很多小伙伴都已经开始接入了,我们的接入参考官方wiki,在成功接入之后,我们为了在CI构建中不依赖fluter环境,采用了调试模式使用源码的方式,打包的时候使用aar的方式,这样做的好处是,既能够保留开发期间的可调试行,也能保障构建环境不依赖Flutter环境。为此,我们团队双端各写了一个脚本,来切换接入模式,且自动将Flutter产物提提取并推送到原生工程以便打包。成功上线几个业务之后,我们遇到flutter的线上问题,大家可能和我当时的感受一样,没有一个比较好的开源工具来对Flutter进行热修复,在网上搜一下,如这篇,大多数表示只讲解原理,看原理理论上是行得通的,但是遗憾的是并没有具体实现过程,于是我们决定立足原理,来探索在Android上怎么实现Flutter页面的热更新,以下是热更新实现后的效果:
当tinker下发补丁成功之后,我们的应用data/data目录会有这个生成这个libapp.so的补丁了。然后使用上面的代码去偷梁换柱即可实现修复了。而且可以看一下,补丁的大小因为tinker做了查分包的缘故,会远远小于8M
那么,对比下两种方案
方案对比 |
自己开发 |
基于tinker |
---|---|---|
需要自己写补丁下载逻辑 |
是 |
否 |
补丁大小 |
比较大 |
小 |
需要自己开发管理端 |
需要 |
不需要 |
是要自己写补丁合成逻辑 |
需要 |
不需要 |
稳定性 |
需要验证 |
很稳定 |
成本 |
很高 |
低 |
写在最后,我们的Android端Flutter环境目前是
Flutter 1.9.1+hotfix.6 • channel stable •
如果想了解flutter打包脚本的小伙伴,可以翻看我之前的文章,或者留言。
版本升级到
Flutter (Channel stable, v1.12.13+hotfix.5
之后 ,热更新模块需要稍微修改一下
public static void flutterPatchInit() {
try {
FlutterLoader flutterLoader = FlutterLoader.getInstance();
String libPath = findLibraryFromTinker(IGameApplication.getIGameApplicationContext(), "lib/armeabi", "libapp.so");
Log.e("FlutterPatch", "flutterPatchInit() called " + libPath);
Field field = FlutterLoader.class.getDeclaredField("aotSharedLibraryName");
field.setAccessible(true);
field.set(flutterLoader, libPath);
} catch (Exception e) {
e.printStackTrace();
}
}
对比之前,sAotSharedLibraryName由静态私有变量变为了私有变量,而且不再放在FlutterMain当中了,放到了FlutterLoader当中。