这篇“Android中怎么手写热修复dex”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android中怎么手写热修复dex”文章吧。
什么是双亲委托机制
当前ClassLoader首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。 每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,等下次加载的时候就可以直接返回了。
当前classLoader的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到bootstrp ClassLoader.
当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。
突破口来了,看1(如果已经加载则直接返回原来已经加载的类) 对于同一个类,如果先加载修复的类,当后续在加载未修复的类的时候,直接返回修复的类,这样bug不就解决了吗?
Nice ,多看源码和jvm 许多问题可以从framework和底层去解决
话不多说,提出了解决方法,下面着手去实现
public class InitActivity extends FragmentActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //这里默认在SD卡根目录,实际开发过程中可以把dex文件放在服务器,在启动页下载后加载进来 //第二次进入的时候可以根据目录下是否已经下载过,处理,避免重新下载 //最后根据当前app版本下载不同的修复dex包 等等一系列处理 String dexFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/fix.dex"; DexFile dexFile = null; try { dexFile = DexFile.loadDex(dexFilePath, null, Context.MODE_PRIVATE); } catch (IOException e) { e.printStackTrace(); } patchDex(dexFile); startActivity(new Intent(this, MainActivity.class)); } /** * 修复过程,可以放在启动页,这样在等待的过程中,网络下载修复dex文件 * * @param dexFile */ public void patchDex(DexFile dexFile) { if (dexFile == null) return; Enumeration<String> enumeration = dexFile.entries(); String className; //遍历dexFile中的类 while (enumeration.hasMoreElements()) { className = enumeration.nextElement(); //加载修复后的类,只能修复当前Activity后加载类(可以放入Application中执行) dexFile.loadClass(className, getClassLoader()); } } }
方法很简单在启动页,或者Application中提前加载有bug的类
这里写的很简单,只是展示核心代码,实际开发过程中,dex包下载的网络请求,据当前app版本下载不同的修复dex,文件存在的时候可以在Application中先加载一次,启动页就不用加载,等等,一系列优化和判断处理,这里就不过多说明,具体一些处理看github上的代码
###ok 代码都了解了,这个
fix.dex文件哪里来的呢 熟悉Android apk生成的小伙伴都知道了,跳过这个步骤,不懂的小伙伴继续往下看
上面的
InitActivity中
startActivity(new Intent(this, MainActivity.class));启动了一个
MainActivity看看我的
MainActivity
public class MainActivity extends FragmentActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //0不能做被除数,这里会报ArithmeticException异常 Toast.makeText(this, "结果" + 10 / 0, Toast.LENGTH_LONG).show(); } }
哎呀不小心,写了一个bug 0 咋能做除数呢,app已经上线了,这里必崩啊,咋办 不要急,按照以下步骤:
我们要修复这个类
MainActivity,先把bug解决
Toast.makeText(this, "结果" + 10 / 2, Toast.LENGTH_LONG).show();
把修复类生成
.class文件(可以先run一次,之后在 build/intermediates/javac/debug/classes/com开的的文件夹,找到生成的class文件,也可以通过javac 命令行生成,也可以通过右边的gradle Task生成)
把修复类
.class文件 打包成dex (其他
.class删除,只保留修复类) 打开cmd命令行,输入下面命令
D:Androidsdkuild-tools28.0.3dx.bat --dex --output C:UserspeiDesktopdxfix.dex C:UserspeiDesktopdx
D:Androidsdk为自己sdk目录
28.0.3为
build-tools版本,可以根据自己已经下载的版本更换 后面两个目录分别是生成
.dex文件目录,和
.class文件目录
切记
.class文件的目录必须是包名一样的,我的目录是
C:UserspeiDesktopdxcompei estMainActivity.class,不然会报
class name does not match path
这样dx文件夹下就会生成fix.dex文件了,把fix.dex放进手机根目录试试吧
再次打开App,完美Toast 结果5,完美解决