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

相关文章

Web技术与Nginx网站环境部署教程

《Web技术与Nginx网站环境部署教程》:本文主要介绍Web技术与Nginx网站环境部署教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Web基础1.域名系统DNS2.Hosts文件3.DNS4.域名注册二.网页与html1.网页概述2.HTML概述3.

SpringBoot项目中Redis存储Session对象序列化处理

《SpringBoot项目中Redis存储Session对象序列化处理》在SpringBoot项目中使用Redis存储Session时,对象的序列化和反序列化是关键步骤,下面我们就来讲讲如何在Spri... 目录一、为什么需要序列化处理二、Spring Boot 集成 Redis 存储 Session2.1

springboot+vue项目怎么解决跨域问题详解

《springboot+vue项目怎么解决跨域问题详解》:本文主要介绍springboot+vue项目怎么解决跨域问题的相关资料,包括前端代理、后端全局配置CORS、注解配置和Nginx反向代理,... 目录1. 前端代理(开发环境推荐)2. 后端全局配置 CORS(生产环境推荐)3. 后端注解配置(按接口

Vue 2 项目中配置 Tailwind CSS 和 Font Awesome 的最佳实践举例

《Vue2项目中配置TailwindCSS和FontAwesome的最佳实践举例》:本文主要介绍Vue2项目中配置TailwindCSS和FontAwesome的最... 目录vue 2 项目中配置 Tailwind css 和 Font Awesome 的最佳实践一、Tailwind CSS 配置1. 安

python利用backoff实现异常自动重试详解

《python利用backoff实现异常自动重试详解》backoff是一个用于实现重试机制的Python库,通过指数退避或其他策略自动重试失败的操作,下面小编就来和大家详细讲讲如何利用backoff实... 目录1. backoff 库简介2. on_exception 装饰器的原理2.1 核心逻辑2.2

Spring Boot项目打包和运行的操作方法

《SpringBoot项目打包和运行的操作方法》SpringBoot应用内嵌了Web服务器,所以基于SpringBoot开发的web应用也可以独立运行,无须部署到其他Web服务器中,下面以打包dem... 目录一、打包为JAR包并运行1.打包为可执行的 JAR 包2.运行 JAR 包二、打包为WAR包并运行

使用Python自动化生成PPT并结合LLM生成内容的代码解析

《使用Python自动化生成PPT并结合LLM生成内容的代码解析》PowerPoint是常用的文档工具,但手动设计和排版耗时耗力,本文将展示如何通过Python自动化提取PPT样式并生成新PPT,同时... 目录核心代码解析1. 提取 PPT 样式到 jsON关键步骤:代码片段:2. 应用 JSON 样式到

SpringBoot实现二维码生成的详细步骤与完整代码

《SpringBoot实现二维码生成的详细步骤与完整代码》如今,二维码的应用场景非常广泛,从支付到信息分享,二维码都扮演着重要角色,SpringBoot是一个非常流行的Java基于Spring框架的微... 目录一、环境搭建二、创建 Spring Boot 项目三、引入二维码生成依赖四、编写二维码生成代码五

Java如何根据文件名前缀自动分组图片文件

《Java如何根据文件名前缀自动分组图片文件》一大堆文件(比如图片)堆在一个目录下,它们的命名规则遵循一定的格式,混在一起很难管理,所以本文小编就和大家介绍一下如何使用Java根据文件名前缀自动分组图... 目录需求背景分析思路实现代码输出结果知识扩展需求一大堆文件(比如图片)堆在一个目录下,它们的命名规

Python Selenium动态渲染页面和抓取的使用指南

《PythonSelenium动态渲染页面和抓取的使用指南》在Web数据采集领域,动态渲染页面已成为现代网站的主流形式,本文将从技术原理,环境配置,核心功能系统讲解Selenium在Python动态... 目录一、Selenium技术架构解析二、环境搭建与基础配置1. 组件安装2. 驱动配置3. 基础操作模