android混淆多个a b c,Proguard混淆Android项目所遇问题及总结

本文详细记录了在Android项目中遭遇Proguard混淆问题的解决过程,涉及类重复、运行时空指针、反射冲突等,分享了常见错误原因、解决策略和混淆原理,包括如何处理多库依赖、butterknife版本差异和特殊注解保持等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Proguard混淆Android项目所遇问题及总结

最近一个老项目需要添加混淆, 因此又对混淆有了更深入的了解. 在此过程中遇到了一下问题, 记录如下:

1. 编译打包错误

a. 类重复, 错误信息如下

:xyz:compileReleaseNdk UP-TO-DATE

:xyz:compileReleaseSources

:xyz:proguardRelease

Note: there were 1276 duplicate class definitions.

(http://proguard.sourceforge.net/manual/troubleshooting.html#duplicateclass)

Exception while processing task

java.io.IOException: Can't write [/Users/stone/xyz/build/intermediates/classes-proguard/release/classes.jar] (Can't read [/Users/stone/xyz/abc/build/intermediates/exploded-aar/xyz/emojicon/unspecified/jars/libs/android-support-v4.jar(;;;;;;!META-INF/MANIFEST.MF)] (Duplicate zip entry [android-support-v4.jar:android/support/v4/hardware/display/DisplayManagerCompat.class]))

at proguard.OutputWriter.writeOutput(OutputWriter.java:187)

at proguard.OutputWriter.execute(OutputWriter.java:79)

at proguard.ProGuard.writeOutput(ProGuard.java:427)

at proguard.ProGuard.execute(ProGuard.java:175)

at proguard.gradle.ProGuardTask.proguard(ProGuardTask.java:1074)

at com.android.build.gradle.tasks.AndroidProGuardTask.doMinification(AndroidProGuardTask.java:139)

at com.android.build.gradle.tasks.AndroidProGuardTask$1.run(AndroidProGuardTask.java:115)

at com.android.builder.tasks.Job.runTask(Job.java:48)

at com.android.build.gradle.tasks.SimpleWorkQueue$EmptyThreadContext.runTask(SimpleWorkQueue.java:41)

at com.android.builder.tasks.WorkQueue.run(WorkQueue.java:227)

at java.lang.Thread.run(Thread.java:745)

Caused by: java.io.IOException: Can't read [/Users/stone/xyz/build/intermediates/exploded-aar/xyz/emojicon/unspecified/jars/libs/android-support-v4.jar(;;;;;;!META-INF/MANIFEST.MF)] (Duplicate zip entry [android-support-v4.jar:android/support/v4/hardware/display/DisplayManagerCompat.class])

at proguard.InputReader.readInput(InputReader.java:188)

at proguard.InputReader.readInput(InputReader.java:158)

at proguard.OutputWriter.writeOutput(OutputWriter.java:176)

... 10 more

Caused by: java.io.IOException: Duplicate zip entry [android-support-v4.jar:android/support/v4/hardware/display/DisplayManagerCompat.class]

at proguard.io.JarWriter.getOutputStream(JarWriter.java:138)

at proguard.io.FilteredDataEntryWriter.getOutputStream(FilteredDataEntryWriter.java:105)

at proguard.io.FilteredDataEntryWriter.getOutputStream(FilteredDataEntryWriter.java:105)

at proguard.io.FilteredDataEntryWriter.getOutputStream(FilteredDataEntryWriter.java:92)

at proguard.io.ClassRewriter.read(ClassRewriter.java:68)

at proguard.io.FilteredDataEntryReader.read(FilteredDataEntryReader.java:87)

at proguard.io.FilteredDataEntryReader.read(FilteredDataEntryReader.java:87)

at proguard.io.FilteredDataEntryReader.read(FilteredDataEntryReader.java:87)

at proguard.io.JarReader.read(JarReader.java:65)

at proguard.io.DirectoryPump.readFiles(DirectoryPump.java:65)

at proguard.io.DirectoryPump.pumpDataEntries(DirectoryPump.java:53)

at proguard.InputReader.readInput(InputReader.java:184)

... 12 more

:xyz:dexRelease FAILED

出现原因:

主项目引用了几个library, 而这几个library都引用了同一个jar包, library引用jar包的方式是: 将jar包放在module的libs目录下并配置如下gradle脚本

dependencies {

compile fileTree(dir: 'libs', include: '*.jar')}

解决过程:

以前用eclipse开发android项目遇到过这样的编译问题, 错误信息如下:

com.android.dex.DexException: Multiple dex files define Lcom/alibaba/fastjson/JSONStreamAware;

at com.android.dx.merge.DexMerger.readSortableTypes(DexMerger.java:594)

at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:552)

at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:533)

at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:170)

at com.android.dx.merge.DexMerger.merge(DexMerger.java:188)

at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439)

at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287)

at com.android.dx.command.dexer.Main.run(Main.java:230)

at com.android.dx.command.dexer.Main.main(Main.java:199)

at com.android.dx.command.Main.main(Main.java:103)

导致这个编译错误的原因如上, 当是只要jar包改成同一个文件, 就会编译通过 (由于编译出的class文件的版本不一致, 导致无法合并),

然而在anroid studio中, 这样做并无卵用.

我是这样做的: 将不同的library共同引用的jar包放在一个目录下(project跟目录的libs木下), 并配置如下gradle脚本

dependencies {

compile fileTree(dir: 'libs', include: '*.jar')

compile fileTree(dir: '../libs', include: '*.jar')}

最终解决方案:

把module下面的libs目录下的jar包(其他项目也引用的那个jar)删除, 并配置改module的gradle脚本(注意: 各个library引用的库的版本必须一致------------红色标出部分一致)

dependencies {

compile fileTree(dir: 'libs', include: '*.jar')compile'com.alibaba:fastjson:1.1.43'}

注: 这样依赖的是maven仓库中的jar或则aar.

2. 运行时错误

a. 空指针

主要是由 新版的butterknife生成的类的类名规则改变 引起的,

butterknife 7.x之前的版本生成的类的名称形如: **$$ViewBinder

butterknife 7.x即之后的版本生成的类的名称形如: **$$ViewInjector

不混淆butterknife生成的类的规则如下:

-keep class **$$ViewBinder { *; }#butterknife 7.x即之后的版本生成的类-keepclass **$$ViewInjector {*;}#butterknife 7.x 版之前生成的类

我的规则文件是从另一个项目中拷贝过来的, 所以就出现了上述问题:

b. 反射时无法取到某个属性

主要是由于 "没有保持orm框架注解过的数据库实体类" 引起的,

这个添加规则就可以解决了, 如下: (具体规则则需要根据你的具体情况而定)

#xutils定义的实体类-dontwarncom.lidroid.xutils.**

-keepclass com.lidroid.xutils.** {*;}

#此段只能保持使用xutils注解过的字段或方法不能被混淆, db数据库的所有字段都不能被混淆, 因此需要结合下面一段-keepclasseswithmembernamesclass * {

@com.lidroid.xutils.db.annotation.* ;@com.lidroid.xutils.db.annotation.* ;}

#使用xutils注解过的数据库实体类-keepclass a.b.c.** {*;}

-keepclass a.abc.cbd.User {*;}

c. 没有CREATOR

保持CREATOR字段不被混淆的规则/tools/proguard/proguard-android.txt 文件中已经定义过了

如下:

-keepclassmembers class * implements android.os.Parcelable {

public static final android.os.Parcelable$Creator CREATOR;

}

当是有些人在定义CREATOR时会少些一个final, 实际上CREATOR是一个常量, 如果你少些一个final那就只是一个类变量

因此在自定义的规则文件中添加了一条规则, 如下第二条:

#不混淆CREATOR常量, 有人定义CREATOR时不写final关键字 -_-!!-keepclass * implements android.os.Parcelable {

public static final android.os.Parcelable$Creator *;public static android.os.Parcelable$Creator *;}

3. 总结:

1. 混淆的原理

把源代码中的 "包名/类名/变量名/方法名" 改成无意义的字符串, 以达到保护源码的目的.

2. 容易出问题的地方

a. 反射 (包名类名, 方法名, 变量名)

如果你把类名混淆了, 下面的语句会出什么问题? !

if(obj.getClass().getName().equals("a.b.c.SomeClass")) {

//do something

}

变量名和方法名同理!!

b. xml文件, 如下标注的部分如果混淆了, 会发生什么问题?!!

0818b9ca8b590ca3270a3433284dd417.png

当然xml文件还有AndroidManifest.xml, 这个文件会用到四大组件, 因此有以下避免混淆的规则保持四大组件的类名(外加自定义的Application):

-keeppublic class * extends android.app.Activity

-keeppublic class * extends android.app.Application

-keeppublic class * extends android.app.Service

-keeppublic class * extends android.content.BroadcastReceiver

-keeppublic class * extends android.content.ContentProvider

3. 一个总原则

所有硬编码的名称都不能混淆.

所谓硬编码:

a. xml中的东西, 如上.

b. 字符串中写死的类名, 变量名, 方法名, 包名........

c. 反射 ------ 这个其实在上一条中有所体现, 如放射去方法或变量时就是用了硬编码 ------- 字符串!

如下:

Class a = getSomeClass(2);a.getMethod("methodName", int.class);a.getField("aField");

当然只是列举了所谓"硬编码"中的一部分, 更多的混淆问题和"硬编码" 有待读者发现

proguard及混淆规则===> 点击这里

错误之处再所难免, 希望你能帮我更正!

0818b9ca8b590ca3270a3433284dd417.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值