一、开始原因
因公司需要,故研究 proguard 混淆代码,期间踩了不少坑,记录一下过程,避免下次再次踩坑,也希望可以帮到大家。代码环境: spring-boot 2.2.5, jdk 1.8, maven 3.6
二 、proguard 使用 (使用 xml ,maven插件的形式配置使用,以下配置为最终配置)
1、在需要混淆的代码 pom.xml 中添加以下 plugin
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<!--混淆时刻,这里是打包的时候混淆-->
<phase>package</phase>
<!--使用插件的什么功能,当然是混淆-->
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<proguardVersion>6.2.2</proguardVersion>
<!--是否将生成的PG文件安装部署-->
<!--<attach>true</attach>-->
<!--是否混淆-->
<!--<obfuscate>true</obfuscate>-->
<!--指定生成文件分类-->
<!--<attachArtifactClassifier>pg</attachArtifactClassifier>-->
<!-- 加载配置文件 -->
<proguardInclude>../proguard.cfg</proguardInclude>
<!-- 对什么东西进行加载,这里仅有classes成功,毕竟你也不可能对配置文件及JSP混淆吧-->
<injar>classes</injar>
<!--class 混淆后输出的jar包 或 文件夹-->
<outjar>${project.build.finalName}.jar</outjar>
<!-- <outjar>${project.build.finalName}-pg</outjar>-->
<!-- 输出目录-->
<outputDirectory>${project.build.directory}</outputDirectory>
<libs>
<!-- Include main JAVA library required.-->
<lib>${java.home}/lib/rt.jar</lib>
<!-- Include crypto JAVA library if necessary.-->
<lib>${java.home}/lib/jce.jar</lib>
</libs>
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>5.3.3</version>
</dependency>
</dependencies>
</plugin>
2、上面配置中 <proguardInclude>../proguard.cfg</proguardInclude>,proguard.cfg 这个文件。
# -keep {Modifier} {class_specification} 防止类和成员被移除或者被重命名
# -keepclassmembers {modifier} {class_specification} 防止成员被移除或者被重命名
# -keepclasseswithmembers {class_specification} 防止拥有该成员的类和成员被移除或者被重命名
# -keepnames {class_specification} 防止成员被重命名
# -keepclasseswithmembernames {class_specification} 防止拥有该成员的类和成员被重命名
# -keepclasseswithmembers
# -basedirectory directoryname 在配置文件中出现的相对路径均是相对于该路径
# JDK目标版本1.8
-target 1.8
# 不做收缩(删除注释、未被引用代码)
-dontshrink
# 不做优化(变更代码实现逻辑)
-dontoptimize
# 不用大小写混合类名机制
-dontusemixedcaseclassnames
# 不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
# 确定统一的混淆类的成员名称来增加混淆
-useuniqueclassmembernames
# 优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
# 不混淆所有包名
#-keeppackagenames
# 指定要保留在输出文件内的目录(解决 spring autowire 装配失败的问题)
-keepdirectories
#-keepdirectories target\classes\cn\XXX\busi\online\cgform\business\RestBusiness.class
#-keepdirectories cn.XXX.busi.online.cgform.business.*
# 需要保持的属性:异常,注解等
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod
#混淆时是否记录日志
#-verbose
# 不混淆所有的set/get方法
-keepclassmembers public class * {void set*(***);*** get*();}
-keep class cn.XXX.codegenerate.generate.** { *;}
-keep class cn.XXX.codegenerate.SettingUtils { *;}
-keep class cn.XXX.codegenerate.database.** { *;}
-keepclassmembers class cn.XXX.busi.online.cgform.controller.** { private *;}
-keep class cn.XXX.busi.online.config.** { *;}
-keep class cn.XXX.busi.online.cgreport.entity.** { *;}
-keep class cn.XXX.busi.online.cgreport.mapper.** { *;}
-keep class cn.XXX.busi.online.cgform.mapper.** { *;}
-keep class cn.XXX.busi.online.cgform.business.** { *;}
-keep class cn.XXX.busi.online.cgform.enums.ExecuteSqlEnum { *;}
-keep class cn.XXX.busi.online.cgform.util.SqlParamUtil { *;}
-keep class cn.XXX.busi.client.impl.* { *;}
-keep class cn.XXX.busi.client.aop.* { !private <methods>; }
# 指定IOnlCgformHeadService类名不被混淆,且IOnlCgformHeadService 的executeSelectSql方法不被混淆
# 注意:返回值 和 参数的 类型要写全路径
-keep class cn.XXX.busi.online.cgform.service.IOnlCgformHeadService {
cn.XXX.XXX.framework.common.api.RestResponse* execute*Sql(com.alibaba.fastjson.JSONObject);
}
3、以上proguard.cfg 这个文件的内容也可以直接写在pom.xml 中,以个人喜好和需要选择
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<!--混淆时刻,这里是打包的时候混淆-->
<phase>package</phase>
<!--使用插件的什么功能,当然是混淆-->
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<proguardVersion>6.2.2</proguardVersion>
<!--是否将生成的PG文件安装部署-->
<!-- <attach>true</attach>-->
<!--是否混淆-->
<!-- <obfuscate>true</obfuscate>-->
<!--指定生成文件分类-->
<!-- <attachArtifactClassifier>pg</attachArtifactClassifier>-->
<options>
<!-- JDK目标版本1.8-->
<option>-target 1.8</option>
<!-- 不做收缩(删除注释、未被引用代码)-->
<option>-dontshrink</option>
<!-- 不做优化(变更代码实现逻辑)-->
<option>-dontoptimize</option>
<!-- 不去忽略非公用类文件及成员-->
<option>-dontskipnonpubliclibraryclasses</option>
<option>-dontskipnonpubliclibraryclassmembers</option>
<!--不用大小写混合类名机制-->
<option>-dontusemixedcaseclassnames</option>
<!-- 优化时允许访问并修改有修饰符的类和类的成员 -->
<!-- <option>-allowaccessmodification</option>-->
<!-- 确定统一的混淆类的成员名称来增加混淆-->
<option>-useuniqueclassmembernames</option>
<!-- 不混淆所有包名-->
<!-- <option>-keeppackagenames</option>-->
<!-- 需要保持的属性:异常,注解等-->
<!-- Error: You have to specify '-keep' options if you want to write out kept elements with '-printseeds'.-->
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod</option>
<!-- <option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,*Annotation*,Synthetic,EnclosingMethod</option>-->
<!-- 不混淆所有的set/get方法-->
<option>-keepclassmembers public class * {void set*(***);*** get*();}</option>
<!-- 不混淆包下的所有类名,且类中的方法也不混淆-->
<option>-keep class cn.xxx.codegenerate.generate.** { *;}</option>
<option>-keep class cn.xxx.codegenerate.SettingUtils { *;}</option>
<option>-keep class cn.xxx.codegenerate.database.** { *;}</option>
<option>-keep class cn.xxx.busi.online.cgform.mapper.** { *;}</option>
<option>-keep class cn.xxx.busi.online.cgform.business.RestBusiness { *;}</option>
<option>-keep class cn.xxx.busi.online.cgform.enums.ExecuteSqlEnum { *;}</option>
<option>-keep class cn.xxx.busi.online.cgform.util.SqlParamUtil { *;}</option>
<option>-keep class cn.xxx.busi.client.impl.SysBaseApiImpl { *;}</option>
<option>-keep class cn.xxx.busi.online.cgform.service.IOnlCgformHeadService { *;} </option>
<option>-keep class cn.xxx.busi.online.cgform.service.impl.OnlCgformHeadServiceImpl {*;}</option>
<option>-printseeds ${project.build.directory}</option>
</options>
<!-- 加载配置文件 -->
<proguardInclude>E:\ideaProject\busi-base-common\proguard.cfg</proguardInclude>
<!-- 对什么东西进行加载,这里仅有classes成功,毕竟你也不可能对配置文件及JSP混淆吧-->
<injar>classes</injar>
<!--class 混淆后输出的jar包 或 文件夹-->
<outjar>${project.build.finalName}.jar</outjar>
<!-- <outjar>${project.build.finalName}-pg</outjar>-->
<!-- 输出目录-->
<outputDirectory>${project.build.directory}</outputDirectory>
<libs>
<!-- Include main JAVA library required.-->
<lib>${java.home}/lib/rt.jar</lib>
<!-- Include crypto JAVA library if necessary.-->
<lib>${java.home}/lib/jce.jar</lib>
</libs>
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
</plugin>
4、配置完之后用maven 直接打包即可。options中是配置的混淆方式和忽略的类或方法
三、踩坑记录(废话不多说,直接上坑坑)
1、报错:(Can't process class [META-INF/versions/9/module-info.class] (Unsupported class version number [53.0] (maximum 52.0, Java 1.8))
解决方式:<proguardVersion>6.2.2</proguardVersion> 版本改为了 最新的 6.2.2,
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
依赖改为同样的版本,刷新maven,即可。
2、报错:Error: You have to specify '-keep' options if you want to write out kept elements with '-printseeds'.
翻译一下:如果要用'-printseeds'写出保留的元素,则必须指定'-keep'选项。
解决方式:根据需求 配置 -keep 要保留的元素
3、 <proguardInclude>../proguard.cfg</proguardInclude> 配置文件未生效
解决:是因为 路径写的有问题,此路径是相对于 编译后的 target 文件的路径,如果是maven多模块,这些配置又写在父模块的目录下,重点来了,想要混淆子模块的代码,那么这个路径就是相对于子模块的target文件夹的路径
4、想要混淆 某个类,但是这个类里面的 几个方法不能混淆,怎么配置都不行,那么 如下:
返回值和入参 一定要写全包名,要不然无效
# 指定IOnlCgformHeadService类名不被混淆,且IOnlCgformHeadService 的executeSelectSql方法不被混淆
# 注意:返回值 和 参数的 类型要写全路径
-keep class cn.xxx.busi.online.cgform.service.IOnlCgformHeadService {
cn.xxx.xxx.framework.common.api.RestResponse* execute*Sql(com.alibaba.fastjson.JSONObject);
}
5、混淆之后 其他项目调用 @Autowired 注入失败,找不到这个bean
解决方式: -keepdirectories ,配置文件里加入此项目,可解决问题。网上说 这个配置后面可以加 包名或加目录,但我试了没有效果,这个之后再研究一下,解决问题最重要嘛!
6、打包之后 不知道混淆成功了没,或者混淆配置生效了没,查看这个jar包里的代码又很麻烦。那么:
outjar 配置一个目录即可。如果要上传私服,打包之后却有两个包,混淆的那个包无法直接上传私服,那么 outjar 配置的jar包名称 和 ${project.build.finalName} 一致,即可覆盖。然后 一键轻松上传私服。
<!--class 混淆后输出的jar包 或 文件夹-->
<!-- <outjar>${project.build.finalName}.jar</outjar>-->
<outjar>${project.build.finalName}-pg</outjar>
最后配上 几个配置文件的指令参数说明的文章:
https://www.cnblogs.com/hanschen-coder/p/6528828.html
https://blog.csdn.net/byhook/article/details/52529617
先到这里吧,有些坑 前脚踩了 后脚就忘了,希望大家少踩坑,一路阳光道