• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android热补丁动态修复实践

Android热补丁动态修复实践

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了android 热修复补丁,android 打补丁,android安全补丁级别,android 热补丁,android安全补丁等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android热补丁动态修复实践


前言

好几个月之前关于Android App热补丁修复火了一把,源于QQ空间团队的一篇文章安卓App热补丁动态修复技术介绍,然后各大厂的开源项目都出来了,本文的实践基于HotFix,也就是QQ空间技术团队那篇文章所应用的技术,笔者会把整个过程的细节和思路在文章中详说,研究这个的出发点也是为了能紧急修复app的bug,而不需要重复发包,不需要用户重新下载app就能把问题解决,个人觉得这个还是蛮有价值的,虽然老板不知道….。

项目结构

项目结构

这里笔者创建一个新的项目”HotFixDemo”,带大家一步一步来完成Hotfix这个框架实现,这个项目包含以下module:
- app :我们的Android应用程序Module。
- buildsrc :使用Groovy实现的项目,提供了一个类,用来实现修改class文件的操作。
- hackdex :提供了一个类,后面会用来打包成hack.dex,也是buildsrc里面实现在所有类的构造函数插入的一段代码所引用到的类。
- hotfixlib :这个module最终会被app关联,里面提供实现热补丁的核心方法

这个Demo里面的代码跟HotFix框架基本无异,主要是告诉大家它实现的过程,如果光看代码,不实践是无法把它应用到你自己的app上去的,因为有很多比较深入的知识需要你去理解。

先说原理

关于实现原理,QQ空间那篇文章已经说过了,这里我再重新阐述一遍:
- Android使用的是PathClassLoader作为其类的加载器
- 一个ClassLoader可以包含多个dex文件,每个dex文件是一个Element,多个dex排列成一个有序的dexElements数组
- 当找类的时候会遍历dexElements数组,从dex文件中找类,找到则返回,否则继续下一个dex文件查找
- 热补丁的方案,其实就是将有问题的类单独打包成一个dex文件(如:patch.dex),然后将这个dex插入到dexElements数组的最前面去。

ok,这个就是HotFix对app进行热补丁的原理,其实就是用ClassLoader加载机制,覆盖掉有问题的方法,然后我们所谓的补丁就是将有问题的类打成一个包。

再说问题

当然要实现热补丁动态修复不会很容易,我们首要解决的一个问题是:

当虚拟机启动时,当verify选项被打开时,如果static方法、private方法、构造函数等,其中的直接引用(第一层关系)到的类都在同一个dex文件中,那么该类会被打上CLASS_ISPREERIFIED标记

如下图所示:
CLASS_ISPREERIFIED

如果一个类被打上了CLASS_ISPREERIFIED这个标志,如果该类引用的另外一个类在另一个dex文件,就会报错。简单来说,就是你在打补丁之前,你所修复的类已经被打上标记,你通过补丁去修复bug的时候这个时候你就不能完成校验,就会报错。

解决问题

要解决上一节所提到的问题就要在apk打包之前就阻止相关类打上CLASS_ISPREERIFIED标志,解决方案如下:
在所有类的构造函数插入一段代码,如:

public class BugClass {
    public BugClass() {
        System.out.println(AntilazyLoad.class);
    }

    public String bug() {
        return "bug class";
    }
}

其中引用到的AntilazyLoad这个类会单独打包成hack.dex,这样当安装apk的时候,classes.dex内的类都会引用一个不相同的dex中的AntilazyLoad类,这样就解决CLASS_ISPREERIFIED标记问题了。

实现细节

上面几节讲完原理、之后抛出了问题,再提出解决方案,相信大家对整个热补丁修复框架有了一定的认识,至少我们知道它到底是怎么一回事。下面来讲实现细节:

创建两个类

package com.devilwwj.hotfixdemo;

/**
 * com.devilwwj.hotfixdemo
 * Created by devilwwj on 16/3/8.
 */
public class BugClass {

    public String bug() {
        return "bug class";
    }
}
package com.devilwwj.hotfixdemo;

/**
 * com.devilwwj.hotfixdemo
 * Created by devilwwj on 16/3/8.
 */
public class LoadBugClass {
    public String getBugString() {
        BugClass bugClass = new BugClass();
        return bugClass.bug();
    }
}

我们需要做的是在这两个类的class文件的构造方法中插入一段代码:

System.out.println(AntilazyLoad.class);

创建hackdex模块并创建AntilazyLoad类

看图就好了:

hackdex模块

将AntilazyLoad单独打成hack_dex.jar包

通过以下命令来实现:

jar cvf hack.jar com.devilwwj.hackdex/*

这个命令会将AntilazyLoad类打包成hack.jar文件

dx --dex --output hack_dex.jar hack.jar

这个命令使用dx工具对hack.jar进行转化,生成hack_dex.jar文件

dx工具在我们的sdk/build-tools下
dx工具

最终我们把hack_dex.jar文件放到项目的assets目录下:

hack_dex.jar

使用javassist实现动态代码注入

创建buildSrc模块,这个项目是使用Groovy开发的,需要配置Groovy SDK才可以编译成功。
在这里下载Groovy SDK:http://groovy-lang.org/download.html,下载之后,配置项目user Library即可。

它里面提供了一个方法,用来向指定类的构造函数注入代码:

 /**
     * 植入代码
     * @param buildDir 是项目的build class目录,就是我们需要注入的class所在地
     * @param lib 这个是hackdex的目录,就是AntilazyLoad类的class文件所在地
     */
    public static void process(String buildDir, String lib) {
        println(lib);
        ClassPool classes = ClassPool.getDefault()
        classes.appendClassPath(buildDir)
        classes.appendClassPath(lib)

        // 将需要关联的类的构造方法中插入引用代码
        CtClass c = classes.getCtClass("com.devilwwj.hotfixdemo.BugClass")
        if (c.isFrozen()) {
            c.defrost()
        }
        println("====添加构造方法====")
        def constructor = c.getConstructors()[0];
        constructor.insertBefore("System.out.println(com.devilwwj.hackdex.AntilazyLoad.class);")
        c.writeFile(buildDir)

        CtClass c1 = classes.getCtClass("com.devilwwj.hotfixdemo.LoadBugClass")
        if (c1.isFrozen()) {
            c1.defrost()
        }
        println("====添加构造方法====")
        def constructor1 = c1.getConstructors()[0];
        constructor1.insertBefore("System.out.println(com.devilwwj.hackdex.AntilazyLoad.class);")
        c1.writeFile(buildDir)

    }

配置app项目的build.gradle

上一小节创建的module提供相应的方法来让我们对项目的类进行代码注入,我们需要在build.gradle来配置让它自动来做这件事:

apply plugin: 'com.android.application'

task('processWithJavassist') << {
    String classPath = file('build/intermediates/classes/debug')// 项目编译class所在目录
    com.devilwwj.patch.PatchClass.process(classPath, project(':hackdex').buildDir.absolutePath + "/intermediates/classes/debug") // 第二个参数是hackdex的class所在目录
}

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.devilwwj.hotfixdemo"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    applicationVariants.all { variant ->
        variant.dex.dependsOn << processWithJavassist // 在执行dx命令之前将代码打入到class中
  



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 热修复,android热修复
  • Android热补丁技术—dexposed原理简析(手机淘宝采用方案)
  • Android热补丁动态修复实践

相关文章

  • 2017-05-26硅谷社交14--选择联系人页面,硅谷社交14--联系人
  • 2017-05-26ActiveRecord模式整理,activerecord模式
  • 2017-05-26Android界面架构(Activity,PhoneWiondow,DecorView)简介,activitydecorview
  • 2017-10-21在Mac系统中 下载、安装AndroidStudio
  • 2017-05-26安卓开源项目周报0117,安卓开源项目0117
  • 2017-05-26一个特别适合新手练习的Android小项目——每日一妹纸
  • 2017-05-26did not call through to super.onCreate(),didsuper.oncreate
  • 2017-08-23Glide生命周期管理
  • 2017-05-227.1.2 Android Http请求头与响应头的学习
  • 2017-05-26Android安全机制

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 【Android性能工具】腾讯开源工具APT,androidapt
    • Android开发艺术探索学习笔记(三),android艺术探索
    • andriod 获得应用程序名称,andriod应用程序
    • TextView,iostextview
    • Swift开发iOS应用(1)列表的实现
    • Android开发学习之路--网络编程之xml、json
    • Android定位&amp;地图&amp;导航——自定义公交路线代码,android定位城市
    • 安卓003快速入门
    • ImageLoader配合ImageSwitcher的使用,imageloader使用
    • Android中使用开源框架PagerSlidingTabStrip实现导航标题,android开源框架

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有