Android 之 Jar 包偷天换日

在 Android 开发中,不少时候,咱们可能想要修改第三方库里的某些类。那么咱们有两个主流的方式来实现:android

  1. 下载并引入第三方库的全部源码,而后修改对应的类的源码
  2. 使用 ASM 等工具,直接修改对应类的字节码

第一种方式,优势是方法简单不容易出错,并且 Debug 的时候不会有什么问题。缺点就是操做麻烦,升级的时候须要和上游进行 Rebase。并且当遇到 OkHttp 这种用 Maven 组织的项目,对惯用 Gradle 组织项目的 Android 工程师更是个灾难。git

第二种方式,优势是非侵入,不须要下载和引入第三方库的源码。而缺点的话,就是实现相对复杂(涉及到字节码操做),并且由于字节码已被修改,无法和源码对应,因此 Debug 的时候也可能出问题。github

Duplicate Class

相信不少人在打包 Apk 的编译期(Build Time)遇到过「Duplicate Class」的错误。缘由是 Dex 构建工具在把全部类打包进同一个 Dex 的时候,若是发现若是有重复的类要打包进 Dex 的话,就会报错。bash

而在编辑期(Edit Time)的时候,若是咱们的全部源码中有重复类的话,IDE 也会提示错误。可是若是咱们的源码里有一个和第三方 Jar 包里重复的类,IDE 是不会提示错误的。为何呢?app

由于重复类并不在同一个 Archive 里。Archive 能够看做类的容器,能够是一个 Jar 包,也能够是一个 Dex。固然你某个 Module 中的全部源码,也能够想像成是一个 Archive,因此源码有重复类是会提示错误的。maven

总结如下,在源码中的类和 Jar 包里的类有重复的状况下,在编辑期是不会提示错误的。只有当到了编译期,构建工具将你源码编译出来的类,和第三方 Jar 里的重复的类,混合到同一个 Archive 里的时候才会报错。工具

偷天换日

既然,IDE 容许源码中有和 Jar 里的类重复的类。那么,对于开头提到的问题,咱们能够提出一种新的解决方案:gradle

只把 Jar 里想要修改的类的对应源码拷贝到项目中修改,而后在最终编译的时候把 Jar 包里这些类给删除掉。保证在打包进 Dex 的时候只有咱们拷贝的源码编译出来的类便可。ui

JarFilterPlugin

咱们可使用 JarFilterPlugin 来帮咱们在最后打包进 Dex 以前,把全部依赖的 Jar 包里指定的 Class 文件所有过滤掉。url

咱们先把 Plugin 引入到咱们的项目中:

buildscript {
    repositories {
        maven { url "https://jitpack.io" }
    }
    dependencies {
        classpath "com.github.nekocode:JarFilterPlugin:1.1"
    }
}
复制代码

而后咱们开始使用插件来过滤 Class 文件了。

假设咱们想要修改 Android Support V7 包里的 AppCompatActivity 类。咱们只须要把 AppCompatActivity 类的源码拷贝到咱们的项目中,而后在 App Module 的 budil.gradle 下添加以下配置:

apply plugin: 'jar-filter'

jarFilter {
    skipFiles = [
            'android/support/v7/app/AppCompatActivity.class',
            'android/support/v7/app/AppCompatActivity\\$(.*).class'
    ]
}
复制代码

这样,在执行 Assemble 任务打包出的 Apk 中就只会有咱们拷贝的 AppCompatActivity 类。

相关文章
相关标签/搜索