android代码混淆常见问题及解决

时间:2022-02-09 05:31:03
代码混淆就是把代码中的类、方法、变量名等替换成无义字符,以防源码被反编译泄露。 
android SDK自2.3.3以来就把代码混淆工具Proguard集成进来了,在项目中可以直接使用,非常方便。
步骤:
1、打开项目的project.properties文件,可以看到这样两行:
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 
非常简单明确,把第二行的注释符“#”去掉即可。
自然,要想去掉代码混淆,只要再把第二行注释掉即可。
这里推荐使用优化混淆,即把第二行写成:
proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt 
2、在项目根目录下新建txt文件proguard-project.txt,将${sdk.dir}/tools/proguard/proguard-android-optimize.txt中的内容全文复制进来,保存
3、项目——右键——android tools——export signed application package得到混淆后的包
4、反编译看看是否混淆成功。反编译工具包见附件

常见问题:
1、Proguard returned with error code 1. See console
除非特别简单的工程,否则这个问题基本是难免的。
查看控制台打印的信息,确定是什么问题。我的问题: 
  
java.lang.IllegalArgumentException: Can"t find any super classes of [org/mozilla/javascript/tools/debugger/FileWindow] (not even immediate super class [javax/swing/JInternalFrame]) 
 at proguard.evaluation.value.ReferenceValue.generalize(ReferenceValue.java:287)
at proguard.evaluation.value.IdentifiedReferenceValue.generalize(IdentifiedReferenceValue.java:65)
at proguard.evaluation.value.ReferenceValue.generalize(ReferenceValue.java:481)
at proguard.optimize.info.MethodOptimizationInfo.generalizeReturnValue(MethodOptimizationInfo.java:247)
at proguard.optimize.evaluation.StoringInvocationUnit.generalizeMethodReturnValue(StoringInvocationUnit.java:195)
at proguard.optimize.evaluation.StoringInvocationUnit.setMethodReturnValue(StoringInvocationUnit.java:126)
at proguard.evaluation.BasicInvocationUnit.exitMethod(BasicInvocationUnit.java:134)
at proguard.evaluation.Processor.visitSimpleInstruction(Processor.java:514)
at proguard.classfile.instruction.SimpleInstruction.accept(SimpleInstruction.java:218)
at proguard.optimize.evaluation.PartialEvaluator.evaluateSingleInstructionBlock(PartialEvaluator.java:753)
at proguard.optimize.evaluation.PartialEvaluator.evaluateInstructionBlock(PartialEvaluator.java:587)
at proguard.optimize.evaluation.PartialEvaluator.evaluateInstructionBlockAndExceptionHandlers(PartialEvaluator.java:560)
at proguard.optimize.evaluation.PartialEvaluator.visitCodeAttribute0(PartialEvaluator.java:264)
at proguard.optimize.evaluation.PartialEvaluator.visitCodeAttribute(PartialEvaluator.java:181)
at proguard.classfile.attribute.CodeAttribute.accept(CodeAttribute.java:101)
at proguard.classfile.ProgramMethod.attributesAccept(ProgramMethod.java:79)
at proguard.classfile.attribute.visitor.AllAttributeVisitor.visitProgramMember(AllAttributeVisitor.java:95)
at proguard.classfile.util.SimplifiedVisitor.visitProgramMethod(SimplifiedVisitor.java:91)
at proguard.classfile.ProgramMethod.accept(ProgramMethod.java:71)
at proguard.classfile.ProgramClass.methodsAccept(ProgramClass.java:504)
at proguard.classfile.visitor.AllMethodVisitor.visitProgramClass(AllMethodVisitor.java:47)
at proguard.classfile.ProgramClass.accept(ProgramClass.java:346)
at proguard.classfile.ClassPool.classesAccept(ClassPool.java:116)
at proguard.optimize.Optimizer.execute(Optimizer.java:372)
at proguard.ProGuard.optimize(ProGuard.java:306)
at proguard.ProGuard.execute(ProGuard.java:115)
at proguard.ProGuard.main(ProGuard.java:492) 

 在这里推荐一个很不错的网站,可以输入异常打印的堆栈信息来搜索解决方案:http://www.brainleg.com/search/index 

出现这个异常的原因是org/mozilla/javascript/tools/debugger/FileWindow是javax.swing.JInternalFrame的扩展. 而它扩展的这个类是Swing的一部分, Swing是不包含在Android里的. 因此FileWindow是无法被项目实际使用的。而Proguard也因为类的层次关系不完整而无法解析类。

出现这种情况的原因一般是由于引用了第三方jar包,代码混淆时应该把第三方jar包跳过,因为它可能已经被混淆过,重复混淆就会出问题。方法为在proguard-project.txt 中添加:
 -libraryjars <path-to-jar>/xx.jar 
 补全路径和包名即可。 

这种方法不总是有效,因为项目代码中对jar包有时候不仅是引用那么简单,还可能是扩展、继承等等。更周全的做法是在proguard-project.txt 中添加:
 -keep class org.mozilla.javascript.** {*;} 
org.mozilla.javascript替换成jar包内的包名,不清楚可以查看控制台warning或解压jar包。这句话的作用就是绕过org.mozilla.javascript开头的所有类。 

如果这种方法还没有解决问题,应该是遇到了更复杂的情形:第三方jar包还引用了其它jar包,而这些jar包并没有被引用到工程里来。问我为什么这些jar包没引用进来工程却不报错?那是因为工程引用第三方jar包的内容并未涉及到用到“第四方” jar包的部分。简单说就是如果你引用了jar包里的某个类,而它又引用了另一个不再工程里的jar包,这时工程才会报错。没报错是因为你没用到那部分。 
这种情况的解决方案有多种,你可以找到那个“第四方”jar包,然后把它引用到工程里来(虽然我看不出这样做有什么意义,因为你的程序并没有用到那部分);或者找办法让proguard忽略掉jar包内引用“第四方”jar包的文件(至少我还未找到有效的方法);或者把jar包打开,将用到“第四方”jar包的文件删除,再重新打成jar包。这个方法虽然简单粗暴,却不失有效。因为jar包本身相当于一个类库,为了满足各种需求集成大量的类,而你用到的可能只是其中很小一部分。适当删减有益无弊。 
 
完成以上步骤,应该可以正确的导出包了。 
  
2、 安装包运行异常 
问题还没完。如果在debug模式下由eclipse直接运行到手机上,程序正常,而导出的安装包运行异常,那应该就是混淆了不该混淆的类。想确认的话可以利用前文提到的方法,把项目中的代码混淆关闭,导出包来试验运行是否恢复正常。 

包里的哪些类不该混淆,是没有别人可以告诉你的。只能自己通过分析和尝试来确定。  

 比如引用了第三方jar包的类,不要混淆,否则引用将无法找到;留有外部接口的类,不要混淆,否则这些接口将无法使用(这里留有外部接口的意思是,程序打包后,这些接口还会被调用)。等等。方法为在proguard-project.txt 中添加: 
 -keep <your-package-name>.xx.** { *;}
-keep class <your-package-name>.xxx.** { *;}