android 项目分包,android 基于分包方案的修复

本文深入探讨了Android应用中的动态热修复技术,重点在于如何处理类加载问题,确保修复后的类能在运行时正确加载。同时,文章介绍了分包策略,解释了为何在某些设备上不需要额外引用Anti类也能运行。内容涵盖了从Java编译到dex,再到Apk打包和签名的过程,并通过代码示例展示了热修复的实现。此外,文章还提及了Google的分包方案和华为设备的特殊行为。
摘要由CSDN通过智能技术生成

# 本demo实现原理来自

# Anti类功能,及其原理

45c9688f786c3f4428cf043361483ec6.png

如上图,A,B,C是三个class,它们在生成apk文件时,被打包入同一个dex文件中,当apk发布出去运行一段时间发现A类有个bug,现在使用上面链接中的修复方案修复bug。如文中所说,如果直接将A类重写,并使用运行时动态地将修复后的A类所在的dex文件加载并插入到加载链前,则A便可以修复。但是因为在优化的过程中,如果dex文件中的class都不依赖外部文件,则dex文件内部的class会被打一个CLASS_ISPREVERIFIED标签,这样当B类再使用修复后的A类时,因它在另一个dex文件中,则会报运行时错误。所以在B类中,添加一行代码使得它依赖另外一个dex中的Anti类,这样B就不会被打标签。值得注意的是,apk运行的真实环境中,因并不确定哪一(哪几)个类将来会出现问题,所以为了将来可以修复它(它们),上面的A,B,C类都应该被加上引用Anti的代码;另外,因为Anti所在的dex是在Application类的onCreate方法中被加载,所以Application类的onCreate方法前不该引用到Anti类。

# anti_dex.jar 和bug_dex.jar的制作

主要过程:java -> class -> dex

java -> class, 可以使用ide如AS,或者直接命令行使用jdk提供的编译工具

javac -source 1.7 -target 1.7 –cp . –d . ,该命令需要在包的同一级目录下执行,且MAIN_CLASS包含包路径名。

class -> dex, 可以使用dx工具,形如

dx --dex --output=classes_dex.jar 

# 测试代码编写

@Override

public void onCreate() {

super.onCreate();

File dexPath = new File(getDir("dex", Context.MODE_PRIVATE), "anti_dex.jar");

Utils.prepareDex(this.getApplicationContext(), dexPath, "anti_dex.jar");

HotFix.patch(this, dexPath.getAbsolutePath(), "hotfix.test.com.example.didi.applicationtesthotfix.Anti");

dexPath = new File(getDir("dex", Context.MODE_PRIVATE), "bug_dex.jar");

Utils.prepareDex(getApplicationContext(), dexPath, "bug_dex.jar");

HotFix.patch(getApplicationContext(), dexPath.getAbsolutePath(), "hotfix.test.com.example.didi.applicationtesthotfix.BugClass");

try {

Class> clazz = Class.forName("hotfix.test.com.example.didi.applicationtesthotfix.Anti");

equalLoader(clazz);

Log.e("Ruby", "Anti 's classloader' hashCode " + clazz.getClassLoader().hashCode() + " , " + clazz.getClassLoader().getClass().getName());

Class> cla = Class.forName("hotfix.test.com.example.didi.applicationtesthotfix.BugClass");

equalLoader(cla);

Log.e("Ruby", "BugClass 's classloader' hashCode " + cla.getClassLoader().hashCode() + " , " + cla.getClassLoader().getClass().getName());

} catch (Exception e) {

}

}

# 剔除Anti的编译脚本

因为Anti.class不能被使用AS一起打包入dex文件中,所以,在编译后打包工程的class文件成dex时,需要先将Anti.class删除,然后借助AS已近编译后的class文件和打包后的资源文件包自己命令行打包成apk文件。

# 打包class文件生成dex 文件

dx=/Users/didi/Library/Android/sdk/build-tools/23.0.3/dx classes=build/intermediates/classes/release/

$dx --dex --output=classes.dex $classes

# 打包res/ assets/ 文件成 resources-release.ap_ 文件 (AS已完成)

# 打包 resources-release.ap_ 和 classes.dex文件成 Hotfix-unsign.apk

sdklib=/Users/didi/Library/Android/sdk/tools/lib/sdklib.jar

apk=com.android.sdklib.build.ApkBuilderMain

app/build/intermediates/res

resources=build/intermediates/res/resources-release.ap_

java -classpath $sdklib $apk Hotfix-unsign.apk -u -z $resources -f classes.dex

# 签名

keystore=/Users/didi/Documents/DidiChuxing/driver/lulei.keystore

alia=lulei

psw=demodebug

jarsigner=/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/jarsigner

$jarsigner -digestalg SHA1 -sigalg MD5withRSA -keystore $keystore -storepass $psw -keypass $psw -signedjar Hotfix-sign.apk Hotfix-unsign.apk $alia

# 运行时,动态热修复不行的原因

protected Class> loadClass(String className, boolean resolve) throws ClassNotFoundException {

Class> clazz = findLoadedClass(className);

if (clazz == null) {

ClassNotFoundException suppressed = null;

try {

clazz = parent.loadClass(className, false);

} catch (ClassNotFoundException e) {

suppressed = e;

}

if (clazz == null) {

try {

clazz = findClass(className);

} catch (ClassNotFoundException e) {

e.addSuppressed(suppressed);

throw e;

}

}

}

return clazz;

}

从上面的ClassLoader源码中,可以看到,查找一个类时,先查看内存中该类是否加载,所以如果在加载修复后的类文件A前,已经使用了A类,则该方案就失败,所以该方案要在Application的onCreate方法中将A所在的dex预先load。

# “字节码修改”和 “编译依赖”方案的区别

原则上没有任何区别!

# google 分包方案,是什么鬼,分包策略是什么?

I  still don’t  know!

#  华为i7-ATH-AL00 android版本5.1.1 为什么不插入Anti代码也可以?

What? Fuck!!!

#  反思

虽然使用了自定义的DexClassLoader将修复后的class文件从文件中重新加载到内存中了,但是因为方案中是将DexClassLoader(的父类)的DexFile通过反射赋值给了PathClassLoader(的父类BaseClassLoader 的pathLists成员),所以查看修复后类的classLoader,仍然显示为系统的pathClassLoader。

demo 代码请参考 github地址

Android dex分包方案和热补丁原理

一.分包的原因: 当一个app的功能越来越复杂,代码量越来越多,也许有一天便会突然遇到下列现象: 1. 生成的apk在2.3以前的机器无法安装,提示INSTALL_FAILED_DEXOPT 2. 方 ...

[转]Android dex分包方案

转载自:https://m.oschina.net/blog/308583 当一个app的功能越来越复杂,代码量越来越多,也许有一天便会突然遇到下列现象: 1. 生成的apk在2.3以前的机器无法安装 ...

Android dex分包方案

当一个app的功能越来越复杂,代码量越来越多,也许有一天便会突然遇到下列现象: 1. 生成的apk在2.3以前的机器无法安装,提示INSTALL_FAILED_DEXOPT 2. 方法数量过多,编译时 ...

《android基于andFix的热修复方案》思路篇

1:需求背景 项目上线之后,发现BUG需要修复(比如安卓兼容性等测试难以发现的问题),频繁的更新影响用户体验 2:方案要求 静默下载,耗费流量少,打完补丁后立刻生效,不用重启apk 3:解决思路 3. ...

《android基于andFix的热修复方案》实战篇

有篇文章说的比较简洁,大家可以参考下:AndFix使用说明 下面说说实际使用中遇到的问题 1:如何继承到gradle项目中 dependencies { compile 'com.alipay.eul ...

Android分包方案multidex

对于功能越来越复杂的app的两大问题 问题一:当项目越来越大,方法数超过65536,编译时会出错(为什么是65536,参考下面关于dexopt对方法id检索存储介绍),这个所说的方法数包含用到的框架, ...

Android 基于Netty的消息推送方案之对象的传递(四)

在上一篇文章中我们介绍了Netty的字符串传递,我们知道了Netty的消息传递都是基于流,通过ChannelBuf ...

Android 基于Netty的消息推送方案之字符串的接收和发送(三)

在上一篇文章中 ,我们介绍过一些关于Netty的概念和工作原理的内容,今天我们先来介绍一个叫做ChannelBuffe ...

Android 基于Netty的消息推送方案之概念和工作原理(二)

上一篇文章中我讲述了关于消息推送的方案以及一个基于Netty实现的一个简单的Hello World,为了更好的理解Hello World中的代码,今天我来讲解一下关于Netty中一些概念和工作原理的内 ...

随机推荐

介绍一款原创的四则运算算式生成器:CalculateIt2

家里小朋友读一年级了,最近每天都有一些10以内的加减法口算练习,作为程序员爸爸,自然也是想办法能够偷懒,让电脑出题,给小朋友做些练习.于是,自己在业余时间开发了一个四则运算算式生成器,名为:Calcu ...

4,4s屏幕过渡页处理

//#import "sys/utsname.h" struct utsname systemInfo; uname(&systemInfo); NSString *dev ...

部署IISHTTP 404.17无法由静态文件处理程序来处理

部署IIS时候出现下图问题,这是因为IIS无法处理aspx.ashx等后缀名的文件,这是因为Web 服务器接收到请求时,会对所请求的文件的文件扩展名进行检查,确定应由哪个 ISAPI 扩展处 ...

iOS开发——UI基础-按钮的创建和设置

@interface ViewController () - (IBAction)customBtnClick; @end @implementation ViewController - (void ...

DOM操作优化

文档对象模型(DOM)是一个独立 于特定语言的应用程序接口.在浏览器中,DOM接口是以JavaScript语言实现的,通过JavaScript来操作浏览器页面中的元素,这使得 DOM成为了JavaSc ...

Python 条件判断 循环

age = 20 if age >= 18: print('your age is', age) print('adult') 根据Python的缩进规则,如果if语句判断是True,就把缩进的 ...

Linux入门基础教程

转载自:http://www.centoscn.com/CentOS/2015/0528/5555.html 1. 1      Linux操作系统简介 Linux是一套免费使用和自由传播的类Unix ...

转:LoadRunner自带的协议分析工具

在做性能测试的时候,协议分析是困扰初学者的难题,不过优秀的第三方协议分析工具还是挺多的,如:MiniSniffer .Wireshark .Ominpeek 等:当然他们除了帮你分析协议之外,还提供其 ...

js加密

在项目中,经常需要使用加密来保障数据的安全性,虽然可以通过在后台加密再传给前台,但这样无疑会增加后台的服务器的压力.所以在js中使用加密算法也就应运而生了. 一.base64加密 需要引入base64 ...

<02>labSQL的配置和使用方法

任务布置:制作简单地铁站点管理系统<2> 要求一:正确配置系统,建立基本正常的数据通道:要求二:实现地铁站点的登记,拥有查询功能: 正文: 今天介绍labview虚拟仪器软件中  labS ...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值