Git Product home page Git Product logo

sdk-editor-plugin's Introduction

更新说明

  • 支持Android Gradle Plugin 4.2.x
  • 原有@ReplaceClass("包标识"),中的"包标识"改为把依赖库格式[group:name:version]中的[name:version]作为标识,如:原依赖[androidx.core:core:1.3.0@aar],则取[core:1.3.0]作为标识,请不要添加[version]后面的@aar
  • 发布仓库由jcenter迁移到 jitpack

简介

  • sdk-editor是一个在APP编译期修改类的轻量Gradle插件,插件利用Android Plugin官方提供的Transform API干预APK Build流程,实现对特定类的替换修改。无其他不安全Hook操作,100%可靠。

  • 如果APP中某个依赖的SDK没有源码、无人迭代,并且发现Bug或者需要扩展功能,那么sdk-editor就是你的菜!

特点

  • 使用简单方便,不需要任何字节码知识;

  • 编译期替换,不影响App性能,不增加Apk体积(仅添加一个用于标记的注解类ReplaceClass);

适用场景

  • 修复SDK中存在的Bug;

  • 暴露出SDK某些未提供的接口;

  • 扩展SDK功能;

  • 其他需要修改SDK已有类的需求;

基本用法

1. 在根项目(最外层)的build.gradle文件中添加插件依赖:

buildscript {
    repositories {
	...
	maven { url 'https://jitpack.io' }
    }
    dependencies {
        classpath 'com.github.iwhys:sdk-editor-plugin:1.1.7'
    }
}

2. 在项目主模块(app module)的build.gradle文件应用插件:

apply plugin: 'sdk-editor'

3. 找到三方SDK中需要修改的类文件(以下称为Bug类),在app module中新建与Bug类同包名同类名的新类(以下称为Fix类),同时拷贝Bug类的内容到Fix类,给Fix类添加类注解@ReplaceClass,在注解的值中标记该类所在SDK(jar/aar)的标识(依赖格式[group:name:version]只取[name:version]作为标识),最后在Fix类中实现要修改的内容即可。

下面以demo module中替换core:1.3.0包中的BuildCompat类为例进行说明,我们需要BuildCompat类中的isAtLeastR方法,在其中添加一条Toast语句,修改流程如下:

1)在demo工程的main/java下新建androidx.core.os.BuildCompat类;

2)拷贝原SDK中BuildCompat类的内容,并修改新建的BuildCompat类;

/** 原依赖[androidx.core:core:1.3.0] 取[core:1.3.0]作为标识 **/
@ReplaceClass("core:1.3.0")
public class BuildCompat {
    public static boolean isAtLeastR() {
        Toast.makeText(MyAppKt.getAppContext(), "You successfully added a Toast to \"BuildCompat#isAtLeastQ()\"", Toast.LENGTH_LONG).show();
        return VERSION.CODENAME.length() == 1
                        && VERSION.CODENAME.charAt(0) >= 'R'
                        && VERSION.CODENAME.charAt(0) <= 'Z';
    }
}

3)编译并运行demo,点击按钮弹出一个Toast,即表明core:1.3.0包中的BuildCompat类被成功的修改;

高级用法

如果有多个项目用到了同一个需要修改的SDK,为了在多个项目**享修复后的代码,我们可以把修复代码封装成一个单独jar/aar包。下面以demo模块中libs引用的三方SDK DuappsAd-HW-v1.1.1.6-release.aar为例,我们需要修改SDK中的com.duapps.ad.DuNativeAd类,在其中添加广告请求监听器,具体流程如下:

1)在任意项目中新建一个module(如工程中的library_fix);

2)在module的build.gradle文件中添加对需要修复的SDK(如:DuappsAd-HW-v1.1.1.6-release.aar)以及插件注解包(com.iwhys.classeditor:domain:1.1.0)的依赖;

3)在module的main/java目录下新建包com/duapps/ad,并在com/duapps/ad中新建DuNativeAd类,同时拷贝原SDK中DuNativeAd类的内容

4)在新建的DuNativeAd类中添加注解@ReplaceClass("DuappsAd-HW-v1.1.1.6-release");

5)在新建的DuNativeAd类中添加需要新增的广告监听器逻辑;

6)在终端(Terminal)中执行命令:gradlew library_fix:build,即可在该module的build/output目录中看到生成的aar文件;

7)重命名aar文件(或者其中的jar文件)为:du_hack,拷贝该文件到主module(app module)的libs文件夹,并添加对该文件的依赖;

8)在主module(app module)的build.gradle中指定用于SDK修复的jar/aar包信息即可,格式如下:

sdkEditor {
    // 这里是一个数组,有多个用于修复的包,需要用","分隔开
    extraJarNames = ['hack_du']
}

9)此时主module(app module)便可以在编译的时候使用jar/aar(hack_du)中的Fix类来替换原SDK中的Bug类;

10)插件默认使用单线程处理任务,可通过配置parallel开启多线程并发来提高处理速度;

sdkEditor {
    // 默认值为false,即单线程处理任务
    parallel = true
}

常见问题

1. 新建与Bug类同包名的Fix类时,编译器提示"Package 'xxx.xxx.xxx' clashes with class of same name"

这种情况是因为包路径中的包和类重名了,我们可以通过把java类转换为kotlin类来修复这个问题。

注意:此时需要添加kotlin相关的支持,且因为kotlin编译器在把类编译为class的时候,默认会把文件名改为:原文件名+kt,因此在kotlin版的Fix类中添加文件命名注解 @file:JvmName("Bug类的名称")

2. 在新建的Fix类中,存在部分形如"a.b.c"的类无法正确的导入,或者导入之后与当前类的成员重名

这种情况我们可以把类改为kotlin版,并利用kotlin提供的 import xxx as yyy功能,对导入的有问题的类进行重命名。个人感觉通过导入重命名方式能够解决99%的这种问题,剩下的1%可以通过反射来实现。

3. 新建的Fix类时,如果其所在包的名字同级已经存在一个同名的类(如已存在类com.a.a,Fix类路径com.a.a.Fix,则IDE提示"Redeclare a")

我们可以通过"高级用法"的笨办法,新建module把已存在类com.a.a和Fix类com.a.a.Fix分别放在不同的module来实现。

4. Fix过程正常,但是APK运行到Fix类发生Crash,提示Fix类中缺少xxx方法

通常我们会使用IDE来浏览依赖的SDK文件,并在IDE中把Bug类的源码拷贝到Fix类中,但有些情况下IDE反编译的class代码并不完整,建议使用jeb反编译SDK中的Bug类。

项目简析

sdk-editor结构及原理简析

特别感谢

javassist

协议

The Apache Software License, Version 2.0

sdk-editor-plugin's People

Contributors

iwhys avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

sdk-editor-plugin's Issues

为什么会找不到符号?

image

尝试修复 meiqia sdk 的时候,运行 gradle 就会报错。但是我编写代码的时候,i 这个类是确实有的。编写的时候也没报错。美洽sdk有简单混淆过,部分类名方法都被字母代替了。

Unable to run demo.

Run with Android Studio 3.3.1 and the other config is same with the project.

Caused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process D:\project\sdk-editor-plugin\demo\build\intermediates\transforms\sdkEditor\debug\4.jar
Caused by: com.android.builder.dexing.DexArchiveBuilderException: Error while dexing com\duapps\ad\internal\c$1.class
Caused by: com.android.dx.cf.iface.ParseException: class name (com/duapps/ad/internal/c$1) does not match path (com\duapps\ad\internal\c$1.class)

Kotlin 作为 Fix 类的疑问

如果把 Fix 类转成 Kotlin,会有个问题,Java 调用 Kotlin 和 Java 调用 Java 语法还是有点差别的,这种情况下,不就可能会出错了吗?例如本来调用 Fix 类的常量 TAG,Java 的调用语法是 Fix.TAG,但转成 Kotlin 后常量会定义在 Companion 对象类,调用语法则是 Fix.Companion.TAG

Byte code

在class文件里面出现byte code能使用此插件吗?
// Byte code:
// 0: aload_0
// 1: getfield b : Ljava/util/concurrent/LinkedBlockingDeque;
// 4: bipush #14
// 6: invokestatic take : (Ljava/lang/Iterable;I)Ljava/util/List;
// 9: invokestatic toByteArray : (Ljava/util/Collection;)[B
// 12: dup
// 13: astore_1
// 14: arraylength
// 15: bipush #14
// 17: if_icmpge -> 21
// 20: return

Duplicate class 问题

Execution failed for task ':demo:checkDebugDuplicateClasses'.
> 1 exception was raised by workers:
  java.lang.RuntimeException: java.lang.RuntimeException: Duplicate class com.duapps.ad.DuNativeAd found in modules classes.jar (:DuappsAd-HW-v1.1.1.6-release:) and classes.jar (:hack_du:)
  Duplicate class com.duapps.ad.DuNativeAd$1 found in modules classes.jar (:DuappsAd-HW-v1.1.1.6-release:) and classes.jar (:hack_du:)

这种问题怎么解决?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.