[Android]Gradle 插件 DiscardFilePlugin(class注入&清空类和方法)
2017-04-19 10:40
459 查看
以下内容为原创,欢迎转载,转载请注明
来自天天博客: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.gradlein 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.gradlein
appor
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配置(publish和
disable两种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!"; } }
相关文章推荐
- Class_file&&Android应用调用方法
- #import </usr/include/objc/objc-class.h> not such file or directory问题的解决方法
- android.view.InflateException: Binary XML file line #8: Error inflating class <unknown>
- Error:Timeout waiting to lock cp_proj class cache for build file 'D:\androidw\TuYeLiangPin\app\bui
- Failed to apply plugin [id 'com.android.application'] 和 Could not find com.android.tools.build:gradle:2.XX的最正确的解决方法
- Android cordova插件 plugin.xml 添加jar包依赖的两种方法 比如supportv4的包
- Android Binary XML file line : Error inflating class <unknown
- Android开发中出现in the gradle.properties file, sets the maximum Java heap size to 1024m的解决方法
- android.view.InflateException: Binary XML file line #4: Error inflating class <unknown>
- Android Gradle插件(plugin)版本(version)与Gradle、SDK Build Tools版本关系
- Android Gradle插件(plugin)版本(version)与Gradle、SDK Build Tools版本关系
- android phonegap插件开发方法 plugin
- android phonegap插件开发方法 plugin
- Gradle 使用Jetty插件启动web项目时出现"java.lang.OutOfMemoryError: PermGen space"解决方法
- Android studioError:(13, 0) Gradle DSL method not found: 'android()'解决方法
- android "Could not find class 'org.apache.http.entity.mime.content.FileBody" error
- android学习历程——“Unable to open log device '/dev/log/main': No such file or directory”错误解决方法
- 安装Android studio出现'tools.jar' seems to be not in Android Studio classpath的解决方法
- Android 开发问题解决方法记录:Dx unsupported class file version 52.0
- The JAR of this class file belongs to container 'Android Private Libraries' Android查看外部依赖jar的源码问题解