Android热补丁动态修复技术(完结篇):自动生成打包带签名的补丁,重构项目

本文主要是介绍Android热补丁动态修复技术(完结篇):自动生成打包带签名的补丁,重构项目,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、关于前面四篇博文

Android热补丁动态修复技术(一):从Dex分包原理到热补丁
Android热补丁动态修复技术(二):实战!CLASS_ISPREVERIFIED问题!
Android热补丁动态修复技术(三)—— 使用Javassist注入字节码,完成热补丁框架雏形(可使用)
Android热补丁动态修复技术(四):自动化生成补丁——解决混淆问题

前两篇博文主要是介绍热补丁修复技术的一些原理和实现方案。
而后面两篇博文主要是介绍如何使用代码实现整个热补丁框架,但是框架写的真的很糟糕,很多多余的操作。而这很大一部分原因是使用了transform,在混淆的时候transform并不好用。

以下是我在github上重构好的热补丁框架,求star (。・`ω´・)
https://github.com/AItsuki/HotFix

  1. 支持混淆
  2. 自动生成带签名的补丁包
  3. 加载补丁包时会进行签名校验

这里写图片描述
图中的patch文件夹就是自动生成的补丁包保存目录了,里面有打成jar包之前的class,如果patch.jar打包失败,还能继续手动打包。

更详细的介绍和使用方式请移步到github,再说一次:求star (。・`ω´・)

二、框架的实现思路

在第四篇博文中,我们发现在混淆的情况下,transform使用起来真的很反人类,因为transform只能在混淆之前对class进行操作,无法将transform添加到混淆之后。
所以以下思路,我放弃了使用transform,而是直接在dextransform这个任务的dofirst中进行操作。

在重构项目之前,我先记录下了这些思路和流程,然后根据这个流程来实现热补丁框架,效率真的快了很多。

2.1 定义热补丁框架的使用方式

  1. release签名打包作为发布版本,每次release打包都会重新生成hash.txt和mapping.txt(开启混淆的情况下才有mapping)

  2. 每次debug运行的时候(直接运行项目或者buildapk),都会通过校验hash.txt和mapping.txt生成已签名补丁包。
    直接将补丁包放到sdcard中即可完成热修复

  3. 加载补丁的时候需要进行签名校验,防止恶意代码注入

2.2 代码流程

抛弃transform,使用纯hook的方式实现。
主要hook的task有这几个:

  • transformClassesWithDexForRelease
  • transformClassesWithDexForDebug
  • transformClassesAndResourcesWithProguardForRelease
  • transformClassesAndResourcesWithProguardForDebug

不混淆的情况:
transformClassesWithDexForRelease
dofirst ------ 遍历输入文件,生成md5保存好(hash.txt),然后注入代码

transformClassesWithDexForDebug
dofirst ------ 遍历输入文件,生成md5,和hash对比,将改变过的类复制到补丁文件夹,然后注入代码

混淆的情况:
transformClassesAndResourcesWithProguardForRelease
dolast ------ 遍历输出文件,生成md5保存好(hash.txt),然后注入代码,将mapping保存好

transformClassesAndResourcesWithProguardForDebug(需要使用applymapping)
dolast ------ 遍历输出文件,生成md5,和hash对比,将改变过的类复制到补丁文件夹,然后注入代码

开启混淆后task的执行顺序是proguard --> dex
因为dex永远是在最后面执行,所以注入代码和生成补丁这些操作都只需要hook dex就可以了
但是开启混淆的时候,dex dofirst需要做的事情还是有点不同的,我们可以通过一个变量来控制 def minify = false

hook proguard,在proguardTransform执行的时候复制minify = true
这样就可以控制混淆和不混淆两种情况了。

2.3 实际遇到的问题

1、 不clean项目,第二次运行release打包不会注入代码
这是因为gradle的增量式构建,up-to-date,task不执行
解决方式:
dexRelease.outputs.upToDateWhen {false} 让task一直都执行
http://stackoverflow.com/questions/7289874/resetting-the-up-to-date-property-of-gradle-tasks

2、如果有使用到自定义控件,在xml的preView窗口会报空指针异常
这是因为自定义控件已经被注入了代码,而预览窗口的时候并没有加载hack.jar,找不到AntilazyLoad.class,所以报空指针。
解决方式:
使用pluginExtention,在build.gradle中配置变量,控制在debug模式下是否注入代码。
如图,这里添加了两个Extention
这里写图片描述

3、如何applymapping
applymapping的作用是复用上一次的混淆规则。
所以我们需要将release生成的mapping.txt应用到debug的混淆上,否则可能无法正确的生成补丁。
解决方式:
第一种:
手动配置debug的混淆文件

第二种:

  1. 在gradle 1.5以下时,可以直接task.applyMapping(File file)的方式在代码中动态添加
  2. 在gradle1.5以上时,因为proguard的transform是一个特殊的task,所以并不能直接applyMapping,需要做一些强转。
    (proguardDebug即transformClassesAndResourcesWithProguardForDebug)
    这里写图片描述

4、开启混淆后的Release签名打包,如果debug模式不开启混淆的话,会将所有类都打包成补丁。
这是因为,如果debug模式不开启混淆,那么就会拿不混淆的代码和Release已经混淆的代码进行校验,md5肯定不一致,所以会将所有类打包成补丁包。
解决方式:
暂时没有好办法,老老实实开启混淆吧。Debug是否开启混淆要和Release保持一致
这里写图片描述

5、如何签名补丁
补丁的签名主要用到的是jdk的工具,jarsigner.exe。使用代码调用命令行即可

6、如何进行签名校验
首先,debug安装的app不需要进行校验,这是检测当前app是否是debug签名的方法。
http://blog.csdn.net/luohai859/article/details/44679085

然后,这是校验补丁包和app签名是否一致
http://blog.csdn.net/hudashi/article/details/8245105

7、android 6.0无法从sdcard加载补丁包
运行时权限机制的问题,可以将补丁包放到app私有空间加载。

8、 androidStudio 2.0以上用到了instantRun,这是否会对debug自动生成补丁包产生影响。
这个问题我还没有测试,如果真的有影响的话也有很简单的解决方式,直接使用签名打包debug也可以生成补丁包。
这里写图片描述

三、参考项目

https://github.com/jasonross/Nuwa
https://github.com/bunnyblue/DroidFix
https://github.com/Livyli/AndHotFix
主要是第三个,签名校验的思路来源于它

四、写在后面

终于算是完成了热补丁框架了,其中过程真的累人啊!
整个框架的实现思路比较清晰简单,代码量也不超过1000行,很适合正在学习这个技术的朋友们。

求star,求star,第一个上传到github的项目求star (。・`ω´・)
https://github.com/AItsuki/HotFix

这篇关于Android热补丁动态修复技术(完结篇):自动生成打包带签名的补丁,重构项目的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/984979

相关文章

Python脚本实现自动删除C盘临时文件夹

《Python脚本实现自动删除C盘临时文件夹》在日常使用电脑的过程中,临时文件夹往往会积累大量的无用数据,占用宝贵的磁盘空间,下面我们就来看看Python如何通过脚本实现自动删除C盘临时文件夹吧... 目录一、准备工作二、python脚本编写三、脚本解析四、运行脚本五、案例演示六、注意事项七、总结在日常使用

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ

SpringBoot项目启动后自动加载系统配置的多种实现方式

《SpringBoot项目启动后自动加载系统配置的多种实现方式》:本文主要介绍SpringBoot项目启动后自动加载系统配置的多种实现方式,并通过代码示例讲解的非常详细,对大家的学习或工作有一定的... 目录1. 使用 CommandLineRunner实现方式:2. 使用 ApplicationRunne

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

Python项目打包部署到服务器的实现

《Python项目打包部署到服务器的实现》本文主要介绍了PyCharm和Ubuntu服务器部署Python项目,包括打包、上传、安装和设置自启动服务的步骤,具有一定的参考价值,感兴趣的可以了解一下... 目录一、准备工作二、项目打包三、部署到服务器四、设置服务自启动一、准备工作开发环境:本文以PyChar

Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南

《Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南》在日常数据处理工作中,我们经常需要将不同Excel文档中的数据整合到一个新的DataFrame中,以便进行进一步... 目录一、准备工作二、读取Excel文件三、数据叠加四、处理重复数据(可选)五、保存新DataFram

多模块的springboot项目发布指定模块的脚本方式

《多模块的springboot项目发布指定模块的脚本方式》该文章主要介绍了如何在多模块的SpringBoot项目中发布指定模块的脚本,作者原先的脚本会清理并编译所有模块,导致发布时间过长,通过简化脚本... 目录多模块的springboot项目发布指定模块的脚本1、不计成本地全部发布2、指定模块发布总结多模