Android进阶从字节码插桩技术了解美团热修复实例详解

目录
  • 引言
  • 1 插件发布
  • 2 Javassist
    • 2.1 准备工作
    • 2.2 Transform
    • 2.3 transform函数注入代码
      • 2.3.1 Jar包处理
      • 2.3.2 字节码处理
    • 2.4 Javassist织入代码
      • 2.4.1 ClassPool
      • 2.4.2 CtClass

引言

热修复技术如今已经不是一个新颖的技术,很多公司都在用,而且像阿里、腾讯等互联网巨头都有自己的热修复框架,像阿里的AndFix采用的是hook native底层修改代码指令集的方式;腾讯的Tinker采用类加载的方式修改dexElement;而美团则是采用字节码插桩的方式,也就是本文将介绍的一种技术手段。

我们知道,如果上线出现bug,通常是发生在方法的调用阶段,某个方法异常导致崩溃;字节码插桩,就是在编译阶段将一段代码插入该方法中,如果线上崩溃,需要发布补丁包,同时在执行该方法时,如果检测到补丁包的存在,将会走插桩插入的逻辑,而不是原逻辑。

如果想要知道美团实现的热修复框架原理,那么首先需要知道,robust该怎么用

对于每个模块,如果想要插桩需要引入robust插件,所以如果自己实现一个简单的robust的功能,就需要创建一个插件,然后在插件中处理逻辑,我个人喜欢在buildSrc里写插件然后发布,当然也可以自己创建一个java工程改造成groovy工程

plugins {
    id 'groovy'
    id 'maven-publish'
}
dependencies {
    implementation gradleApi()
    implementation localGroovy()
    implementation 'com.android.tools.build:gradle:3.1.2'
}

如果创建一个java模块,如果要【改装】成一个groovy工程,就需要做上述的配置

1 插件发布

初始化之后,我一般会先建2个文件夹

plugin用于自定义插件,定义输入输出; task用于任务执行。

class MyRobustPlugin implements Plugin<Project>{
    @Override
    void apply(Project project) {
        //项目配置阶段执行,配置完成之后,
        project.afterEvaluate {
            println '插件开始执行了'
        }
    }
}

如果需要发布插件到maven仓库,或者放在本地,可以通过maven-publish(gradle 7.0+)插件来实现

afterEvaluate {
    publishing {
        publications{
            releaseType(MavenPublication){
                from components.java
                groupId  'com.demo'
                artifactId  'robust'
                version  '0.0.1'
            }
        }
        repositories {
            maven {
                url uri('../repo')
            }
        }
    }
}

publications:这里可以添加你要发布的maven版本配置 repositories:maven仓库的地址,这里就是写在本地一个文件夹

重新编译之后,在publish文件夹下会生成很多任务,执行发布到maven仓库的任务,就会在本地的repo文件夹下生成对应的jar包

接下来我们尝试用下这个插件

buildscript {
    repositories {
        google()
        mavenCentral()
        jcenter()
        //这里配置了我们的插件依赖的本地仓库地址
        maven {
            url uri('repo')
        }
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.3"
        classpath "com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10"
        classpath "com.demo:robust:0.0.1"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

配置完成后,在app模块添加插件依赖

apply plugin:'com.demo'

这里会报错,com.demo这个插件id找不到,原因就是,其实插件是一个jar包,然后我们只是创建了这个插件,并没有声明入口,在编译jar包时找不到清单文件,因此需要在资源文件夹下声明清单文件

implementation-class=com.tal.robust.plugin.MyRobustPlugin

创建插件名字的属性文件,声明插件的入口,就是我们自己定义的插件,再次编译运行

这也意味着,我们的插件执行成功了,所以准备工作已完成,如果需要插桩的模块,那么就需要依赖这个插件

2 Javassist

Javassist号称字节码手术刀,能够在class文件生成之后,打包成dex文件之前就将我们自定义的代码插入某个位置,例如在getClassId方法第62行代码的位置,插入逻辑判断代码

2.1 准备工作

引入Javassist,插件工程引入Javassist

implementation 'org.javassist:javassist:3.20.0-GA'

2.2 Transform

Javassist作用于class文件生成之后,在dex文件生成之前,所以如果想要对字节码做处理,就需要在这个阶段执行代码插入,这里就涉及到了一个概念 --- transform;

Android官方对于transform做出的定义就是:Transform用于在class打包成dex这个中间过程,对字节码做修改

在build文件夹中,我们可以看到这些文件夹,像merged_assets、merged_java_res等,这是Gradle的Transform,用于打包资源文件到apk文件中,执行的顺序为串行执行,一个任务的输出为下一个任务的输入,而在transforms文件夹下就是我们自己定义的transform

implementation 'com.android.tools.build:transform-api:1.5.0'

导入Transform依赖

(0)

相关推荐

  • Android AndFix热修复原理详情

    目录 前言 1 arm指令集 2 AndFix热修复原理 2.1 ArtMethod 2.2 ART编译模式 2.3 AndFix框架实现 2.3.1 获取ArtMethod 2.3.2 方法替换 2.4 AndFix动态化配置 2.4.1 dex打包 2.4.2 dex文件加载 2.4.3 动态替换方法 2.4.4 文件访问问题 前言 当我们写了一个方法,那么这个方法是如何被执行的呢? public int add(){ int a = 10; int b = 20; return a + b

  • Android热修复及插件化原理示例详解

    目录 1.前言 2.类加载机制 3.Android类加载 4.Tinker原理 代码实现 5.插件化 5.1 Activity启动流程简单介绍 5.2 插件化原理 5.2.1 绕开验证 5.2.2还原插件Activity 5.3 加载插件资源 5.3.1 Resources&AssetManager 5.3.2 id冲突 1.前言 热修复一直是这几年来很热门的话题,主流方案大致有两种,一种是微信Tinker的dex文件替换,另一种是阿里的Native层的方法替换.这里重点介绍Tinker的大致原

  • Android接入阿里云热修复介绍

    1.AndroidManinifest.xml中加入权限 <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permissio

  • 深入理解Android热修复技术原理之资源热修复技术

    一.普遍的实现方式 目前市面上的很多资源热修复方案基本上都是参考了 Instant Run的实现. 简要说来,Instant Run中的资源热修复分为两步: 1.构造一个新的 AssetManager,并通过反射调用 addAssetPath,把这个完 整的新资源包加入到AssetManager中.这样就得到了一个含有所有新资源的 AssetManager. 2.找到所有之前引用到原有 AssetManager的地方,通过反射,把引用处替换 为 AssetManager. 一个 Android

  • 深入理解Android热修复技术原理之代码热修复技术

    一.底层热替换原理 1.1.Andfix 回顾 我们先来看一下,为何唯独 Andfix 能够做到即时生效呢? 原因是这样的,在 app运行到一半的时候,所有需要发生变更的分类已经被加载过了,在Android 上是无法对一个分类进行卸载的.而腾讯系的方案,都是让 Classloader去加载新的类.如果不重启,原来的类还在虚拟机中,就无法加载新类.因此,只有在下次重启的时候,在还没走到业务逻辑之前抢先加载补丁中的新类,这样后续访问这个类时,就会Resolve 为新的类.从而达到热修复的目的. An

  • 深入理解Android热修复技术原理之so库热修复技术

    目录 一.SO库加载原理 二.SO库热部署实时生效可行性分析 2.1.动态注册 native 方法实时生效 2.2.静态注册 native 方法实时生效 2.3.SO实时生效方案总结 三.SO库冷部署重启生效实现方案 3.1.接口调用替换方案 3.2.反射注入方案 四.如何正确复制补丁 SO库 五.本章小结 一.SO库加载原理 Java Api 提供以下两个接口加载一个 so 库 System. loadLibrary (String libName):传进去的参数:so库名称, 表示的so 库

  • Android进阶从字节码插桩技术了解美团热修复实例详解

    目录 引言 1 插件发布 2 Javassist 2.1 准备工作 2.2 Transform 2.3 transform函数注入代码 2.3.1 Jar包处理 2.3.2 字节码处理 2.4 Javassist织入代码 2.4.1 ClassPool 2.4.2 CtClass 引言 热修复技术如今已经不是一个新颖的技术,很多公司都在用,而且像阿里.腾讯等互联网巨头都有自己的热修复框架,像阿里的AndFix采用的是hook native底层修改代码指令集的方式:腾讯的Tinker采用类加载的方

  • Android 两个Fragment之间的跳转和数据的传递实例详解

    Android  两个Fragment之间的跳转和数据的传递实例详解 作为一个Android的菜鸟,前些天在做项目的时候用到了fragment,需求是从一个Fragment跳转到另一个Fragment,并且还要传递数据,就像Activity的跳转一样.在网上找了好久都没找到很好的列子,最后通过看别人的博客和查文档终于做好了,现在整理一下,希望能帮助有需要的童鞋. 1.首先在第一个Fragment 里面拿到FragmentManger 和FragmentTransaction 代码如下. @Ove

  • Android Studio 一个工程打包多个不同包名的APK实例详解

    公司最近有个特别的需求,同一套代码,稍做修改(如包名不一样,图标不一样,应用名不一样等),编译出几个不同的应用.刚好用AS重构完项目,在网上查阅了一些资料,终于搞定!!在这记录一下. AS主要是利用gradle来实现这个需求的,具体做法如下: 修改app的build.gradle文件 假设我们同一套代码编译2个app:app1和app2 android { ... productFlavors { // app1 app1 { // 设置applicationId(这里很重要,两个相同appli

  • Android  两个Fragment之间的跳转和数据的传递实例详解

    Android  两个Fragment之间的跳转和数据的传递实例详解 作为一个Android的菜鸟,前些天在做项目的时候用到了fragment,需求是从一个Fragment跳转到另一个Fragment,并且还要传递数据,就像Activity的跳转一样.在网上找了好久都没找到很好的列子,最后通过看别人的博客和查文档终于做好了,现在整理一下,希望能帮助有需要的童鞋. 1.首先在第一个Fragment 里面拿到FragmentManger 和FragmentTransaction 代码如下. @Ove

  • Android App中实现简单的刮刮卡抽奖效果的实例详解

    主要思想: 将一个view设计成多层:背景层,含中奖信息等: 遮盖层,用于刮奖,使用关联一个Bitmap的Canvas 在该Bitmap上,使用它的canvas.drawPath的api来处理 手势滑动(类似刮奖的动作) 使用paint.setXfermode 来进行消除手势滑动区域 public class GuaView extends View { private Bitmap mBitmap; //遮盖的图层 private Canvas mCanvas; //绘制遮盖图层 privat

  • 详解JVM基础之字节码的增强技术

    目录 字节码增强技术 ASM Javassist 运行时类的重载 问题引出 Instrument JVMTI & Agent & Attach API 使用场景 总结 字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础.字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术.接下来,我们将从最直接操纵字节码的实现方式开始深入进行剖析 ASM 对于需要手动操纵字节码的需求,可以使用ASM,它可以直接生产 .class字节码文件,也

  • Java字节码的增强技术

    目录 Java字节码的增强技术 一.简单介绍下几种java字节码增强技术 1.ASM 2.Javassist 3.Byte Buddy 4.JVM-SANDBOX Java字节码的增强技术 一.简单介绍下几种java字节码增强技术 1.ASM ASM是一个Java字节码操控框架,它能被用来动态生成类或者增强既有类的功能.ASM可以直接产生class文件,也可以在类被加载入Java虚拟机之前动态改变类行为.ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类. AS

  • Android持久化技术之SharedPreferences存储实例详解

    本文实例讲述了Android持久化技术之SharedPreferences存储.分享给大家供大家参考,具体如下: 1.SharedPreferences存储 在前面一篇文章<Android持久化技术之文件的读取与写入实例详解>中,我们介绍了Android持久化技术的文件的读取与写入.在本文中,继续介绍Android持久化技术另外一个SharedPreferences存储. (1)SharedPreferences存储方式是基于key-value的,通过key可以找到对应的value. (2)支

  • Android UTF-8转码实例详解

    Android UTF-8转码实例详解 在项目中可能会遇到url中有中文的情况,这个时候我们可能需要对url进行编码 mport java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; public class UTFTest { public static void main(String[] args) { String str = "测试字符转换 hello

  • Android源码中常用的接口传参实例详解

    Android源码中常用的接口传参实例详解 把MyCclass中的参数传到MyDclass /*接口传参例子2 * MyCclass.java发送MyDclass.java接收 * 原理和MyAclass.java发送MyDclass.java接收完全一样 * */ public class MyCclass { public void getEditext(GetMyFragmentData myFragmentData){ String edStr="人的生命是有限的,可是为人民服务是无限的

随机推荐