以下内容为原创,欢迎转载,转载请注明

来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6732128.html

Android Gradle 插件 DiscardFilePlugin(清空类和方法)

An android gradle plugin for discard class or method in compile time.

用于在编译构建时期忽略清空类和方法的一个Android Gradle插件。

Github: https://github.com/wangjiegulu/DiscardFilePlugin

1.1 使用场景

在实际的生产中,我们总是会在我们的app中增加一些调试的工具,比如在debug模式下加入DebugPanelActivity(调试面板工具页面,提供比如“切换服务器”等操作)。我们需要在正式上线的release版本中清空相关类和方法,或者修改boolean isProductionEnvironment()方法,让它永远返回true以此来避免上线之后调试相关代码通过反编译等手段暴露出来。

1.2 @Discard注解

1.2.1 Target

  • ElementType.METHOD: 表示清空方法中的代码,编译过程中该方法中代码被清空。

  • ElementType.TYPE: 表示清空类,其实是清空类中的所有方法。

1.2.2 参数

1.2.2.1 apply

apply参数规范:key==exceptValue

表示当key==exceptValue时,Discard才会生效,才会真正在编译时去对方法或者类进行清空。因此可以在每个方法或者类中去进行不同的配置,在不同状态下通过如下方式对不同方法进行Discard:

@Discard(apply = "test1==true")
public void testMethod_1() {
System.out.println("testMethod_1...");
} @Discard(apply = "test2==true")
public void testMethod_2() {
System.out.println("testMethod_2...");
}

使用gradle assembleDebug -Ptest1=true -Ptest2=false来构建时,testMethod_1()方法会被discard,而testMethod_2()不会被discard。构建完毕反编译class结果如下:

@Discard(apply = "test1==true")
public void testMethod_1() {
} @Discard(apply = "test2==true")
public void testMethod_2() {
System.out.println("testMethod_2...");
}

1.2.2.2 srcCode

替换方法的方法体,如果不设置,默认discard方法实现:

  • 返回类型为void: discard后方法体为{}
  • 返回类型为原始数据类型:discard后方法返回默认值,比如{ return 0; }
  • 返回类型为类对象时: discard后方法返回为{ return null; }

可以如下填写具体的方法体代码块:

@Discard(srcCode = "{super.onCreate($1); System.out.println(\"this: \" + $0);}")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
usernameEt = (EditText) findViewById(R.id.activity_main_username_et);
passwordEt = (EditText) findViewById(R.id.activity_main_password_et);
setTestAccount();
}

discard之后的class反编译代码如下:

@Discard(
srcCode = "{super.onCreate($1); System.out.println(\"this: \" + $0);}"
)
protected void onCreate(Bundle var1) {
super.onCreate(var1);
System.out.println("this: " + this);
}

方法的$0表示当前对象this,方法参数依次为$1, $2, $3...详细文档参考这里

1.2.2.3 makeClassNames

可以在这里指定具体的类名,在discard时对未在classPath的类进行make。不常用,可以省略。

1.2.2.4 enable

表示该方法或者类的discard是否开启,默认为true,比较典型的场景为,在类上面增加@Discard对该类所有方法进行discard,但是需要某个方法不discard,这时可以使用@Discard(enable = false)来对方法进行排除在discard范围外。

1.3 使用方式

Gradle(Check newest version):

build.gradle in Project:

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.github.wangjiegulu:discardfile:x.x.x'
}
}

build.gradle in app or library:

apply plugin: 'com.github.wangjiegulu.plg.discardfile'

dependencies {
compile 'com.github.wangjiegulu:discardfile-api:x.x.x'
}

1.3.1. build.gradle

// 使用插件
apply plugin: 'com.github.wangjiegulu.plg.discardfile' // 配置需要修改的类所属在那些包下
discard {
includePackagePath 'com.wangjie.plg.discardfile.sample.ui', 'com.wangjie.plg.discardfile.sample.include'
excludePackagePath 'com.wangjie.plg.discardfile.sample.exclude'/*, 'com.wangjie.plg.discardfile.sample.ui.MainActivity'*/
}

1.3.2. 使用@Discard注解

创建自定义apply配置(publishdisable两种apply配置):

public class ApplyConstants {
public static class Publish {
private static final String PUBLISH = "publish";
public static final String _TRUE = PUBLISH + "==true";
}
public static class DISABLE {
private static final String DISABLE = "disable";
public static final String _TRUE = DISABLE + "==true";
}
}

在需要清空的类上添加@Discard注解,apply = ApplyConstants.Publish._TRUE表示只有在publish=true的情况下,才会执行Discard。

@Discard(apply = ApplyConstants.Publish._TRUE)
public class IncludeClassC { /**
* 因为IncludeClassC类增加了`@Discard`注解,所以该方法也会被discard。
*/
public void onIncludeMethodC() {
System.out.println("onIncludeMethodC...");
} /**
* 替换该方法的实现为:{System.out.println("onIncludeMethodC_2... injected!");}
*/
@Discard(apply = ApplyConstants.Publish._TRUE, srcCode = "{System.out.println(\"onIncludeMethodC_2... injected!\");}")
public void onIncludeMethodC_2() {
System.out.println("onIncludeMethodC_2...");
} /**
* 替换该方法永远返回true
*/
@Discard(apply = ApplyConstants.Publish._TRUE, srcCode = "{return true;}")
public boolean onIncludeMethodC_3() {
System.out.println("onIncludeMethodC_3...");
return false;
} /**
* 因为IncludeClassC类增加了`@Discard`注解,所以该方法也会被discard。
*/
public int onIncludeMethodC_4() {
System.out.println("onIncludeMethodC_4...");
return 100;
} /**
* 由于使用了`@Discard`注解进行显式地声明禁用了本地的discard,所以该方法不会被discard
*/
@Discard(apply = ApplyConstants.Publish._TRUE, enable = false)
public String onIncludeMethodC_5() {
System.out.println("onIncludeMethodC_5...");
return "hello world";
} /**
* 替换该方法永远返回"hello world"字符串
*/
@Discard(apply = ApplyConstants.Publish._TRUE, srcCode = "{return \"hello world injected!\";}")
public String onIncludeMethodC_6() {
System.out.println("onIncludeMethodC_6...");
return "hello world";
}
}

1.3.3. build运行

通过以下命令进行构建:

gradle clean assembleFullDebug -Ppublish=true -Pdisable=true

命令编译完成之后,该类的class文件将会根据配置的@Discard注解被自动修改成如下:

build/intermediates/transforms/discardFile/.../IncludeClassC.class
@Discard(
apply = "publish==true"
)
public class IncludeClassC {
public IncludeClassC() {
} public void onIncludeMethodC() {
Object var10000 = null;
} @Discard(
apply = "publish==true",
srcCode = "{System.out.println(\"onIncludeMethodC_2... injected!\");}"
)
public void onIncludeMethodC_2() {
System.out.println("onIncludeMethodC_2... injected!");
} @Discard(
apply = "publish==true",
srcCode = "{return true;}"
)
public boolean onIncludeMethodC_3() {
return true;
} public int onIncludeMethodC_4() {
return 0;
} @Discard(
apply = "publish==true",
enable = false
)
public String onIncludeMethodC_5() {
System.out.println("onIncludeMethodC_5...");
return "hello world";
} @Discard(
apply = "publish==true",
srcCode = "{return \"hello world injected!\";}"
)
public String onIncludeMethodC_6() {
return "hello world injected!";
}
}

[Android]Gradle 插件 DiscardFilePlugin(class注入&清空类和方法)的更多相关文章

  1. Android Gradle插件

    目录 什么是Gradle 编写方法 buildSrc 基础概念 Extension 自定义Task Plugin Transformer Gradle用处 好文章 常见问题 Gradle插件练习地址: ...

  2. 《Gradle权威指南》--Android Gradle插件

    No1: Android Gradle插件分类 App插件id:com.android.application Library插件id:com.android.library Test插件id:com ...

  3. Android Gradle 学习笔记(七):Android Gradle 插件

    我们知道Android Gradle其实就是一个Gradle的一个第三方插件,它是由Google的Android团队开发的,基于Gradle构建的,和Android Studio完美搭配.相比于旧的构 ...

  4. 【Gradle】Android Gradle 插件

    Android Gradle 插件 Android Gradle 插件简介 从Gradle角度来看,Android其实是Gradle的一个第三方插件,它是由Google的Android团队开发的.但从 ...

  5. Gradle系列之Android Gradle插件

    原文发于微信公众号 jzman-blog,欢迎关注交流. 通过前面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相关的知识,关于 Gradle 及其插件相关知识请先阅读下面几篇文章: ...

  6. Android Gradle插件(plugin)版本(version)与Gradle、SDK Build Tools版本关系

    具体关系如下图: 比如,Android Studio 2.0发布,其中有个新功能“Instant Run”,需要Android Gradle Plugin版本2.0.0以上,那么我们项目的.gradl ...

  7. Android端生成META-INF信息文件的Gradle插件 RapidMetaInfPlugin

    来源博客:Wang Jie's Blog 本文链接:<http://blog.wangjiegulu.com/2018/02/05/Android端生成META-INF信息文件的Gradle插件 ...

  8. Android官方技术文档翻译——Gradle 插件用户指南(7)

    本文译自Android官方技术文档<Gradle Plugin User Guide>,原文地址:http://tools.android.com/tech-docs/new-build- ...

  9. Android Gradle 学习笔记(六):Gradle 插件

    Gradle 本身提供了一些基本的概念和整体核心的框架,其他用于描述真实使用场景的都可以通过插件扩展的方式来实现.这样就可以通过抽象的方式提供一个核心的框架,其他具体的功能和业务都通过插件扩展的方式来 ...

随机推荐

  1. JavaScript:void(0);的作用

    JavaScript中void是一个操作符,该操作符指定要计算一个表达式但是不返回值. void 操作符用法格式如下: 1. javascript:void (expression) 2. javas ...

  2. Javascript中的bind()函数

    今天看到公司大神的一段代码: function ReplaceProcessor() { this._dom = { btnReplace: $('#ro_btnReplace'), btnCompl ...

  3. 【2017-03-10】Tsql语句基础、条件,高级查询

    一.语句基础 1.创建数据库:create database 数据库名(不能汉字,不能数字.符号开头) 2.删除数据库:drop database 数据库名 3.选用数据库:use 数据库名 4.创建 ...

  4. Android学习总结(十五) ———— Notification(状态栏通知)基本用法

    一.Notification基本概念  Notification是一种具有全局效果的通知,它展示在屏幕的顶端,首先会表现为一个图标的形式,当用户向下滑动的时候,展示出通知具体的内容.我们在用手机的时候 ...

  5. 数据库 sql 表连接

    表链接 分为 横向链接   和纵向链接 横向链接 select * from student,score --笛卡尔积 查询所有表 会出现 笛卡尔积  就是所有匹配的结果都会展示一遍 为防止以上情况 ...

  6. SQL Server--获取磁盘空间使用情况

    对于DBA来说,监控磁盘使用情况是必要的工作,然后没有比较简单的方法能获取到磁盘空间使用率信息,下面总结下这些年攒下的脚本: 最常用的查看磁盘剩余空间,这个属于DBA入门必记的东西: -- 查看磁盘可 ...

  7. Android开发遇到手机无法弹出Toast

    今天遇到了一个很奇怪的问题,一个很简单的程序,就是点击按钮弹出一个Toast,但在手机上运行起来,却没有正常弹出Toast 第一反应就是看看是否调用了show方法,很显然,并不是这个低级问题,为了确定 ...

  8. js中的call()、apply()和bind()方法的区别

    call(thisObj,param1,param2....)方法:调用一个对象的方法,用另外的对象去替换当前对象. 下面给出一个例子: function add(a,b){ return a+b; ...

  9. 在Windows的DOS中运行java编程中的问题

    1.苦恼着我的就是找不到或无法加载主类!

  10. CentOS 中 YUM 安装桌面环境(转)

    使用 yum groupinstall 指令很容易就能安装上图形界面的桌面系统. 1. yum 的 group 指令 yum 可以以程序组的模式来安装成套的软件包.支持的软件包可以通过, # yum ...