混混开发之Android端Flutter热更新——Sophix篇(二)
2023-10-04 16:39:22
之前写了利用Tinker来进行Flutter的热更新,分析了原理以及实现步骤。按照Sophix热修复的接入步骤一步步接入完成,实验了一把,原生的改动修复,Flutter的改动并未修复。解开sophix-patch.jar包,里面有Flutter的补丁so包。Sophix和Tinker类似,原理上都是通过Native层的classloader加载补丁dex/so进行修复。补丁包里面不仅有Native层的so修复文件,还有Flutter的so修复文件。
但是直接使用Sophix的方式并不能修复Flutter的bug。Sophix提供了一个gradle插件,用来处理Android原生so的补丁。但是对于Flutter来说,so文件补丁有自己的规则。所以就需要修改gradle插件,来支持Flutter的so补丁。
修改Sophix
public class CustomDexAndSoCopyTask extends DexAndSoCopyTask {
@Override
protected Collection<File> computeSoFilePaths() {
return super.computeSoFilePaths();
}
}
通过修改computeSoFilePaths方法,加上如下代码,用来支持so文件的增量更新。
Collection<File> soFilePaths = Super.computeSoFilePaths();
soFilePaths.addAll(flutterCopySoFiles);
混混使用
@Override
protected Collection<File> getSoFiles() {
Collection<File> soFiles = Super.getSoFiles();
soFiles.addAll(flutterSoFiles);
return soFiles;
}
Flutter端
public static void initSoLoader() {
try {
NativeLibrary.init("libapp.so", null);
} catch (UnsatisfiedLinkError e) {
Log.i(TAG, "Failed to load app so: " + e);
}
if (!Constants.isRelease) {
try {
NativeLibrary.init("libapp_debug.so", null);
} catch (UnsatisfiedLinkError e) {
Log.i(TAG, "Failed to load app debug so: " + e);
}
}
}
具体接入步骤请查看Sophix官方文档:
https://github.com/alibaba/sophix/wiki/%E6%89%93%E5%85%A5%E6%96%87%E6%A1%A3
修改之后的Sophix也可以支持Flutter的so热更新。
原理
对于So的加载,android提供了自己的一套机制。
public static void init(String[] args) {
// 主加载器,用于加载framework层的so
registerMainDexClassLoader(getSystemClassLoader(), args);
// auxiliary加载器,用于加载app层的so
registerAuxiliaryDexClassLoader(getInstrumentation(), args, createClassLoader());
}
getInstrumentation方法里获取Instrumentation对象,再从Instrumentation对象中获取auxiliaryClassLoader。Instrumentation用来检测和监控应用程序的运行,它有一个成员变量mAuxiliaryClassLoader,用来加载dex和so。
主加载器和辅助加载器通过Dex和so的路径的设置,来加载so。
public static void registerMainDexClassLoader(ClassLoader mainClassLoader, String[] args) {
int index = args.length - 2;
if (args[index++].equals("--classpath")) {
String s = args[index++];
String sharedLibPath = "app_so";
if (s.equals(Constants.DEX_BOOTSTRAP_CLASS_PATH)) {
sharedLibPath = "dalvik/lib";
}
addSearchPath(mainClassLoader, sharedLibPath);
}
}
所以可以通过修改Instrumentation对象的auxiliaryClassLoader的so的搜索路径,来实现so的热更新。
总结
通过修改Sophix,可以支持Flutter的so热更新。原理是通过修改Instrumentation对象的auxiliaryClassLoader的so的搜索路径,来实现so的热更新。
优点
- 实现简单,直接修改Sophix源码
- 无需修改Flutter源码
- 支持So的增量更新
缺点
- 需要修改Sophix源码,影响后续Sophix版本升级