为什么在ProGuard中禁用混淆会破坏优化步骤?

3
我们最近决定在Android构建中禁用代码混淆,因为尽管它使最终APK稍微变大,但会使调试困难得多。
自从我们这样做以来,我一直遇到应用程序中之前不存在的崩溃问题,即在混淆仍然激活时。通常,这些崩溃是由Java的VerifyError或NoSuchMethodError引起的。
以下是两个在禁用混淆时突然出现的错误:
Could not find method org.apache.http.HttpConnectionMetrics.getResponseCount, referenced from method com.google.android.apps.analytics.PipelinedRequester.sendRequests
W/dalvikvm( 6652): VFY: unable to resolve virtual method 16112: Lorg/apache/http/HttpConnectionMetrics;.getResponseCount ()J
W/dalvikvm( 6652): VFY:  rejecting opcode 0x6e at 0x000c
W/dalvikvm( 6652): VFY:  rejected Lcom/google/android/apps/analytics/PipelinedRequester;.sendRequests ()V
W/dalvikvm( 6652): Verifier rejected class Lcom/google/android/apps/analytics/PipelinedRequester;
D/dalvikvm( 6652): GC_CONCURRENT freed 253K, 46% free 3261K/6023K, external 0K/0K, paused 2ms+2ms
I/dalvikvm( 6652): Rejecting re-init on previously-failed class Lcom/google/android/apps/analytics/PipelinedRequester; v=0x4062de30
D/AndroidRuntime( 6652): Shutting down VM
W/dalvikvm( 6652): threadid=1: thread exiting with uncaught exception (group=0x400a7560)
E/AndroidRuntime( 6652): FATAL EXCEPTION: main
E/AndroidRuntime( 6652): java.lang.VerifyError: com/google/android/apps/analytics/PipelinedRequester
... 

我可以通过禁用!class/merging/*来解决这个错误。

我看到的另一个错误是这样的:

I/dalvikvm( 7292): DexOpt: access denied from Lcom/urbanairship/analytics/EventUploadManager; to field Lorg/apache/http/entity/AbstractHttpEntity;.contentEncoding
W/dalvikvm( 7292): VFY: unable to resolve instance field 5188
D/dalvikvm( 7292): VFY: replacing opcode 0x5b at 0x00ec
I/dalvikvm( 7292): Could not find method org.apache.http.conn.scheme.PlainSocketFactory.<init>, referenced from method com.google.android.apps.analytics.PipelinedRequester.<init>
W/dalvikvm( 7292): VFY: unable to resolve direct method 15044: Lorg/apache/http/conn/scheme/PlainSocketFactory;.<init> (B)V
D/dalvikvm( 7292): VFY: replacing opcode 0x70 at 0x0003
D/dalvikvm( 7292): VFY: dead code 0x0006-0009 in Lcom/google/android/apps/analytics/PipelinedRequester;.<init> (Lorg/apache/http/HttpHost;)V
I/dalvikvm( 7292): DexOpt: access denied from Lcom/google/android/apps/analytics/PipelinedRequester; to field Lorg/apache/http/impl/SocketHttpClientConnection;.open
W/dalvikvm( 7292): VFY: unable to resolve instance field 5234
D/dalvikvm( 7292): VFY: replacing opcode 0x55 at 0x0006
D/dalvikvm( 7292): VFY: dead code 0x0008-000e in Lcom/google/android/apps/analytics/PipelinedRequester;.closeConnection ()V
D/dalvikvm( 7292): VFY: dead code 0x0010-0011 in Lcom/google/android/apps/analytics/PipelinedRequester;.closeConnection ()V
I/dalvikvm( 7292): DexOpt: access denied from Lcom/google/android/apps/analytics/PipelinedRequester; to field Lorg/apache/http/impl/SocketHttpClientConnection;.open
W/dalvikvm( 7292): VFY: unable to resolve instance field 5234
D/dalvikvm( 7292): VFY: replacing opcode 0x55 at 0x0006
D/dalvikvm( 7292): VFY: dead code 0x0008-0009 in Lcom/google/android/apps/analytics/PipelinedRequester;.addRequest (Lorg/apache/http/HttpEntityEnclosingRequest;)V
D/dalvikvm( 7292): GC_CONCURRENT freed 253K, 47% free 3251K/6023K, external 0K/0K, paused 2ms+3ms
I/dalvikvm( 7292): DexOpt: access denied from Lcom/google/android/apps/analytics/PipelinedRequester; to field Lorg/apache/http/impl/AbstractHttpClientConnection;.metrics
W/dalvikvm( 7292): VFY: unable to resolve instance field 5225
D/dalvikvm( 7292): VFY: replacing opcode 0x54 at 0x0008
D/dalvikvm( 7292): VFY: dead code 0x000a-0090 in Lcom/google/android/apps/analytics/PipelinedRequester;.sendRequests ()V
D/AndroidRuntime( 7292): Shutting down VM
W/dalvikvm( 7292): threadid=1: thread exiting with uncaught exception (group=0x400a7560)
E/AndroidRuntime( 7292): FATAL EXCEPTION: main
E/AndroidRuntime( 7292): java.lang.NoSuchMethodError: org.apache.http.conn.scheme.PlainSocketFactory.<init>

我可以通过设置!method/propagation/*来解决这个问题。

但为什么只有在禁用混淆时才会出现这些问题?难道一个不应该影响另一个吗?


我注意到一个奇怪的地方,就是我看到的所有错误都涉及到 Apache HttpClient 的类。也许我走错了方向? - mxk
1个回答

4

代码混淆可以帮你避免命名冲突,将 Apache HttpClient 类的副本重命名为不会与 已经存在于 Android 中的类 冲突的名称。

这是个棘手的问题... 你可能需要考虑完全不使用 Apache HttpClient,而是像 Jesse Wilson 建议的那样使用内置的 HttpURLConnection 类。

http://android-developers.blogspot.com/2011/09/androids-http-clients.html

你可以尝试使用适用于Android的HttpURLConnection外观:

https://github.com/kevinsawicki/http-request

如果你真的需要使用Apache HttpClient,要么使用嵌入在Android中的旧版本,要么尝试调整ProGuard配置,只混淆HttpClient库。

1
哈哈,问题就出在这了。在看到你的回复之前,我实际上已经发现了并拍了下自己的额头,原来Maven将Apache Http Components(核心和客户端)作为编译范围的传递依赖关系引入了进来,所以ProGuard将其添加为-injar而不是-libraryjar。解决方法是使用provided范围声明它。谢谢! - mxk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接