各位老铁们好,相信很多人对Android应用热修复技术:Robust框架详解(第一部分)都不是特别的了解,因此呢,今天就来为大家分享下关于Android应用热修复技术:Robust框架详解(第一部分)以及的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!
二、原理解析
关于热修复技术点,其实虽然每家都有对应的框架,但是核心点都离不开动态加载机制。有了动态加载机制,然后就是具体修复方案问题了,对于Robust修复方案也是比较简单的。下面来简单看一下他的大致原理:
Robust插件对每个产品代码的每个函数都在编译打包阶段自动的插入了一段代码,插入过程对业务开发是完全透明。如State.Java的getIndex函数:
public long getIndex() { return 100; }
被处理成如下的实现:
public static ChangeQuickRedirect changeQuickRedirect; public long getIndex() { if(changeQuickRedirect != null) { if(PatchProxy.isSupport(new Object[0], this, changeQuickRedirect, false)) { return ((Long)PatchProxy.accessDispatch(new Object[0], this, changeQuickRedirect, false)).longValue(); } } return 100L;}
可以看到Robust为每个class增加了个类型为ChangeQuickRedirect的静态成员,而在每个方法前都插入了使用changeQuickRedirect相关的逻辑,当changeQuickRedirect不为null时,可能会执行到accessDispatch从而替换掉之前老的逻辑,达到fix的目的。如果需将getIndex函数的返回值改为return 106,那么对应生成的patch,主要包含两个class:PatchesInfoImpl.java和StatePatch.java。
PatchesInfoImpl.java:
public class PatchesInfoImpl implements PatchesInfo { public List<PatchedClassInfo> getPatchedClassesInfo() { List<PatchedClassInfo> patchedClassesInfos = new ArrayList<PatchedClassInfo>(); PatchedClassInfo patchedClass = new PatchedClassInfo("com.meituan.sample.d", StatePatch.class.getCanonicalName()); patchedClassesInfos.add(patchedClass); return patchedClassesInfos; }}
StatePatch.java:
public class StatePatch implements ChangeQuickRedirect {
@Override
public Object accessDispatch(String methodSignature, Object[] paramArrayOfObject) {
String[] signature = methodSignature.split(":");
if (TextUtils.equals(signature[1], "a")) {//long getIndex() -> a
return 106;
}
return null;
}
@Override
public boolean isSupport(String methodSignature, Object[] paramArrayOfObject) {
String[] signature = methodSignature.split(":");
if (TextUtils.equals(signature[1], "a")) {//long getIndex() -> a
return true;
}
return false;
}
}
客户端拿到含有PatchesInfoImpl.java和StatePatch.java的patch.dex后,用DexClassLoader加载patch.dex,反射拿到PatchesInfoImpl.java这个class;接着创建这个class的一个对象。然后用该对象的getPatchedClassesInfo方法得到需要patch的class为:com.meituan.sample.State,再反射得到当前运行环境中的com.meituan.sample.d class,将其中的changeQuickRedirect字段赋值为用patch.dex中的StatePatch.java这个class new出来的对象。这就是打patch的主要过程。通过原理分析,其实Robust只是在正常的使用DexClassLoader,所以可以说这套框架是没有兼容性问题的。
下面直接上一张图来看看人家的原理结构(点击查看高清大图):
再来看一下美团team公开的原理图:
原理真的很简单:直接用DexClassLoader加载修复包,然后用loadClass方法加载修复类,new出新对象,在用反射把这新的修复对象设置到指定类的changeQuickRedirect静态变量中即可。其实这种修复类似于Java中的设计模式之静态代理。
三、案例实践
知道了大致原理,下面就用一个简单的案例来运行,看到效果,这里我们需要新建三个项目,三个项目图结构如下:
咋们这里主要看RobustHost,RobustPatch,RobustPatchImpl这三个工程,RobustInsertCodeTools是个Java工程用于后面会重点介绍的动态插入代码工具。
第一、修复包接口工程RobustPatch
这个工程比较简单,大部分都是接口定义,主要有这三个类和接口:
1、ChangeQuickRedirect接口
这个接口主要是后面修复包中每个修复类必须实现的一个接口,内部有两个方法:一个是判断当前方法是否支持修复,一个方法是具体的修复逻辑了。
两个方法的参数都是一样的:
第一个参数是方法的签名,这个签名的格式很简单:方法所属类全称:方法名:方法是否为static类型,注意中间使用冒号进行连接的。
第二个参数是方法的参数信息,而对于这个参数后面分析动态插入代码逻辑的时候会发现操作非常麻烦,才把这个参数弄到手的。
2、PatchesInfo接口
这个接口比较简单,只有一个方法,用户存放一个修复包中所有待修复类的具体信息,因为一个修复包中可能有多个需要修复的类。这个接口也是后面宿主工程中动态加载需要用到的。通过这个接口获取到指定修复的类和旧类信息。
3、PatchedClassInfo类
这个类比较简单,主要就是存放两个字段:一个是本次修复类信息,一个是需要修复旧类信息,让这个类会被上面的接口用到。
第二、修复包工程
到这里咋们就看完了修复包接口工程。下面继续来看一下修复包工程:
修复包工程比较简单,直接增加修复类即可,这里可以看到,我们需要修复宿主工程中的一个MoneyBean类,这个类必须实现上面的修复包接口工程中的ChangeQuickRedirect接口,然后就是需要保存修复类信息和待修复旧类信息,在PatchesInfoImpl中进行保存返回的,而这个类实现了修复包接口工程中的PatchesInfo接口。
1、MoneyBeanStatePatch修复类
这个类看到了,实现了修复接口ChangeQuickRedirect,然后实现具体两个方法即可。
1》在isSupport方法中,会通过方法的签名信息得到方法名,然后判断支持修复的方法。这里看到的是待修复类中的getMoneyValue和desc这两个方法需要进行修复。
2》accessDispatch方法中,主要进行了具体修复方案实行了,开始也是先通过方法签名信息,得到方法名,然后在判断哪些方法需要进行修复,这里把getMoneyValue方法的返回值修复成了10000,把desc方法的返回值修复成了"Patch Desc"。
第三、宿主工程RobustHost
宿主工程最大的工作就是需要加载修复包,这个不用多解释了,放在Application中即可。加载逻辑没什么可说的。这里我们有一个MoneyBean类:
这个类的每个方法之前都加上了具备修复功能的代码段。比如现在如果线上的包中这个类的方法返回值出了问题,这时候就可以借助热修复功能。把第二个修复包工程打包好发布出去即可。
再来看一下这里有一个PatchProxy类:
这个类其实是对修复类进行了包装了,内部有一个重要逻辑就是获取当前执行方法的信息,包括类名和方法名,这里主要是通过方法栈信息得到的:
然后就是宿主工程中的加载修复包逻辑了:
使用DexClassLoader进行加载修复包文件,不多解释了。有了加载器就开始后续的加载逻辑了。首先咋们得获取到PatchesInfoImpl类信息,因为这个类中保存了修复类信息。这里是new出一个新对象。然后就调用其方法得到修复类的相信信息,依次遍历修复类信息列表,得到修复类和待修复旧类信息,依然使用反射new出新对象,再把修复类对象设置到待修复旧类的静态变量changeQuickRedirect中即可。
四、运行效果
关于这个错误这里,不在多解释了,因为咋们把修复包接口工程的代码也加到修复包dex中了。具体错误原因和解决办法,可以去我的网站查找或者留言咨询。到这里假设我们已经解决了所有问题,下面运行看看效果:
咋们再看看没有修复之前的效果:
从这里可以看到,咋们就修复方法成功了。
五、分析美团的实践案例
不过咋们还没有结束工作,因为美团的这个框架没有开源,所以上面的案例并不能具备说服性。所以为了验证我们的实现逻辑是没有错的,咋们需要反编译美团的app了,看他的热修复逻辑是什么样的。这里直接使用Jadx工具打开美团app即可:
咋们打开app之后,可以直接全局搜索PatchProxy类,记得要勾选上Class,不然内容太多了。然后找到了这个类的定义:
看到这个类的实现了,其实到这里我想告诉大家,我的案例工程中的PatchProxy类就是把这个类导出来的,因为我懒得写代码。正好这个类又没有混淆。
咋们继续来看他的加载代码逻辑,这里有个小技巧了:在查看一个应用中动态加载逻辑的时候,可以全局搜索信息:DexClassLoader,如下结果:
其实就是美团的PatchExecutor类,点进去直接查看:
看到这里的核心加载逻辑,不多解释,代码逻辑很简单,大致和我们实现的差不多了。最后咋们再来看一下app中的类中的每个方法是否插入了修复代码段:
随便打开一个类,类中的每个方法之前都有这段修复代码。哈哈,到这里我们就非常确定了,我们的案例实现和美团的修复框架实现逻辑大致不差了。
六、自动插入修复代码
其实到这里还不算结束,因为这篇文章其实不是我想介绍Robust框架的用意,因为大家看完上面的原理之后,发现其实修复原理没多大难度的。而我的用意是如何让每个类中的每个方法都插入一段修复代码。
因为从上面我们可以看到,这个框架的最大难度是在每个类每个方法之前都必须有修复代码段。如果没有那么方法就丧失了修复功能。但是问题在于,一个庞大的项目比如美团,如何能够保证每个开发人员在编写一个方法的时候都需要手动加上这段修复代码呢?这个是不可能约束成功的。所以这个就需要借助自动化操作了,其实在美团官方说明这个框架的时候提到依据:"插入代码是在编译期自动进行的,对于开发者是透明的"。所以这句话对我的诱惑性最大,因为这句话我才研究了这个框架。所以限于篇幅原因,不能在一篇文章中讲解完了。从这里可以看到,Robust框架的核心点不在这篇,而是在下一篇文章,我会带大家手动编写如何在编译期中自动插入修复代码,无需开发人员操心。等那篇文章介绍完之后,会在详细介绍一下美团这个热修复框架Robust的优缺点。
特此说明
项目下载地址:
https://github.com/fourbrother/Robust
七、总结
还有具体细节问题就不说了。但是我们在实现案例的时候会发现这个框架有一个很大的约束,就是每个类的每个方法之前必须加上一段修复代码,如果没有添加该方法就失去了修复功能。当然这段代码是不可能约束每个开发人员在开发过程中手动添加的。
用户评论
这篇文章是深入探讨Android移动应用开发中的一个关键概念——热修复技术。对于那些关注代码效能和用户体验提升的专业开发者来说,了解Robust框架的原理解析十分必要。
有10位网友表示赞同!
作为一个资深安卓开发者,我非常好奇关于热修复技术在实际项目中能够带来的变化。这篇文章的上篇提供了宝贵的见解,尤其是涉及Robust框架的部分,听起来就充满了实用性和创新性。
有18位网友表示赞同!
看了这篇解析后,觉得自己对热修复有了更清晰的认识。Robust框架原理解析帮助我了解了优化代码稳定性和提升应用可用性的背后技术。
有20位网友表示赞同!
文章里面提到的关于如何使用Robust框架进行热修复的一些细节令人兴奋不已。对于开发过程中的问题解决和改进来说,这些知识真是太棒了。
有18位网友表示赞同!
在项目实践中尝试过几次Android的应用热更新,发现Robust框架下的热修复功能极大地减少了用户体验中断的可能性。这篇解析让我理解了其中的智慧所在。
有9位网友表示赞同!
上篇深入分析了Robust框架在Android生态系统中的应用与优势。无论是对于初学者还是高级开发者来说都是一个值得阅读的知识宝库。
有15位网友表示赞同!
读完这篇文章,我发现对热修复技术的认识变得更加全面。通过Robust框架的理解让我认识到更优化的应用更新流程是可以实现的。
有14位网友表示赞同!
文章中的分析揭示了Robust框架在解决常见问题上的效率,在我的开发过程中找到了不少灵感,尤其是对于如何提高代码鲁棒性和性能
有18位网友表示赞同!
上篇内容详尽地描绘出技术细节和策略,对Android热修复技术的掌握有了更深层次的认识。作为开发者,这样的知识提升是无价之宝。
有8位网友表示赞同!
Robust框架在文章中被介绍的原理解析使得我对当前的开发实践有了一些反思,并考虑了如何更好地应用热修复来避免崩溃和服务中断。
有17位网友表示赞同!
从实践中学习后发现,文章提供的关于Android热修复和Robust框架的信息确实能帮助开发者更有效率地解决问题。尤其是那些可能困扰过我的BUG。
有16位网友表示赞同!
随着新技术的不断更新,这篇文章不仅为现在的程序员提供了价值,也让未来的我看到了在Android开发领域里可以遵循的最佳实践。
有11位网友表示赞同!
"上篇解析"这个词本身就暗示了深度和细节的理解过程,在Robust框架下对热修复的具体讲解非常实用。这对于想要深入学习的开发者来说是不可多得的知识。
有8位网友表示赞同!
文中提到的内容不仅覆盖了理论层面,还通过实践案例解释了Robust框架在实际应用中的优势和操作方式。这对于实际开发工作来说非常有帮助
有11位网友表示赞同!
"解析"意味着深度探讨,让我对热修复技术在Android的实现有了新的认识,尤其是如何利用Robust框架来构建更稳定的应用。
有14位网友表示赞同!
文章中关于Android开发过程中的技术问题解决策略分享得非常多,特别是Robust框架下的热修复模块让整个开发流程顺畅了许多。
有11位网友表示赞同!
"上篇"意味着这个解析是系列的一部分,我期待后续的内容,希望能更全面地了解如何借助Robust框架来优化Android应用的维护和升级。
有9位网友表示赞同!
对于那些希望提升移动应用的稳定性和用户体验的专业开发者来说,这篇文章提供了宝贵的指南。尤其是在Robust框架下的热修复技术部分,真是干货满满。
有10位网友表示赞同!