1

我在我的 Android 应用程序中使用 Restlet 2.1.0 Java 库进行 HTTP 和 HTTPS 通信。

到目前为止,我已经将 Proguard 配置为不理会这些库,使用这些保留和忽略规则:

-keep class org.restlet.** { *; }
-dontwarn org.restlet.**
-dontnote org.restlet.**

由于 org.restlet.jar 是 726KB 并且包含 5761 个方法,我现在尝试打开 Proguard 以删除我的应用程序不使用的所有代码,并安全地对其进行优化。

不幸的是,我正在努力编写合适的 Proguard 规则,因为我的尝试导致异常,因为 Restlet 库使用反射。

我的规则的这些部分似乎足够安全:

-keep class org.restlet.engine.connector.Connection

# Ignore these Restlet warnings, as we have never included the
# org.jsslutils.* classes in our build
-dontwarn org.restlet.ext.ssl.**

我还尝试移植我在此博客上看到的规则:

-keep class org.restlet.engine.log.LoggerFacade
-keep class org.restlet.Application
-keep class org.restlet.Client
-keep class org.restlet.Context
-keep class org.restlet.* extends org.restlet.Client { *; }
-keep class org.restlet.* extends org.restlet.Context { *; }

不幸的是,我一直在这样打java.lang.NoSuchMethodException

10-18 18:22:12.975  3142  3165 W System.err: Exception during the instantiation of the client connector.
10-18 18:22:12.975  3142  3165 W System.err: java.lang.NoSuchMethodException: a(Client)
10-18 18:22:12.975  3142  3165 W System.err:    at java.lang.Class.getMatchingConstructor(Class.java:643)
10-18 18:22:12.975  3142  3165 W System.err:    at java.lang.Class.getConstructor(Class.java:472)
10-18 18:22:12.975  3142  3165 W System.err:    at org.restlet.engine.e.a(Engine.java:510)
10-18 18:22:12.975  3142  3165 W System.err:    at org.restlet.Client.<init>(Client.java:96)
10-18 18:22:12.975  3142  3165 W System.err:    at org.restlet.Client.<init>(Client.java:120)
10-18 18:22:12.975  3142  3165 W System.err:    at org.restlet.Client.<init>(Client.java:140)
10-18 18:22:12.975  3142  3165 W System.err:    at org.restlet.d.a.j(ClientResource.java:830)
10-18 18:22:12.975  3142  3165 W System.err:    at org.restlet.d.a.a(ClientResource.java:1045)
10-18 18:22:12.975  3142  3165 W System.err:    at org.restlet.d.a.a(ClientResource.java:1454)
10-18 18:22:12.985  3142  3165 W System.err:    at org.restlet.d.a.a(ClientResource.java:1400)

我正在使用我的 Proguard mapping.txt 和Restlet 源代码一一解决它们,但我想我现在要检查一下,以防有人已经知道答案!

4

2 回答 2

2

首先,我使用该-dontobfuscate标志来运行 Proguard 而不进行混淆。我的异常仍然发生,但更容易看出原因:

10-20 08:43:06.725  4475  4499 W System.err: Error while handling an HTTP client call
10-20 08:43:06.725  4475  4499 W System.err: java.lang.NoSuchMethodException: ClientAdapter(Context)
10-20 08:43:06.725  4475  4499 W System.err:    at java.lang.Class.getMatchingConstructor(Class.java:643)
10-20 08:43:06.725  4475  4499 W System.err:    at java.lang.Class.getConstructor(Class.java:472)
10-20 08:43:06.725  4475  4499 W System.err:    at org.restlet.engine.adapter.HttpClientHelper.getAdapter(HttpClientHelper.java:100)
10-20 08:43:06.725  4475  4499 W System.err:    at org.restlet.engine.adapter.HttpClientHelper.handle(HttpClientHelper.java:111)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.Client.handle(Client.java:180)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.routing.Filter.doHandle(Filter.java:159)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.routing.Filter.handle(Filter.java:206)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.resource.ClientResource.handle(ClientResource.java:1137)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.resource.ClientResource.handleOutbound(ClientResource.java:1226)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.resource.ClientResource.handle(ClientResource.java:1069)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.resource.ClientResource.handle(ClientResource.java:1045)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.resource.ClientResource.post(ClientResource.java:1454)
10-20 08:43:06.735  4475  4499 W System.err:    at org.restlet.resource.ClientResource.post(ClientResource.java:1400)

我用JD-GUI打开了bin/proguard/obfuscated.jar,确认构造函数已被删除。缺少的构造函数位于 Adapter 超类中。

public Adapter(Context context) {
    this.context = context;
}

解决该特定问题的方法是添加此 Proguard 规则:

-keep class org.restlet.engine.adapter.Adapter { *; }

使用简单的 HTTP 连接进行重建和测试揭示了我需要的更多规则。

使用以下规则可以让我成功建立 HTTP 和 HTTPS 连接。

# Preserve a minimal number of Restlet classes.  It is particularly
# difficult to get these keep rules correct as Restlet uses quite a
# lot of reflection. 
-keep class org.restlet.engine.log.LoggerFacade
-keep class org.restlet.Application
-keep class org.restlet.Client
-keep class org.restlet.Context
-keep class org.restlet.Connector
-keep class org.restlet.Request
-keep class org.restlet.Response
-keep class org.restlet.Restlet
-keep class org.restlet.data.Status
-keep class org.restlet.engine.adapter.Adapter { *; }
-keep class org.restlet.engine.adapter.ClientCall
-keep class org.restlet.engine.adapter.ClientAdapter { *; }
-keep class org.restlet.engine.adapter.HttpClientHelper { *; }
-keep class org.restlet.engine.connector.Connection
-keep class org.restlet.engine.ClientHelper { *; }
-keep class org.restlet.engine.header.Header { *; }

-keep class org.restlet.* extends org.restlet.Client { *; }
-keep class org.restlet.* extends org.restlet.Context { *; }
-keep class org.restlet.* extends org.restlet.Connector { *; }
-keep class org.restlet.* extends org.restlet.engine.ClientHelper { *; }
-keep class org.restlet.* extends org.restlet.resource.Resource { *; }

# We use constants like Disposition.NAME_FILENAME
-keepclassmembers class org.restlet.data.Disposition { public static final *; }

# Ignore these Restlet warnings, as we have never included the
# org.jsslutils.* classes in our build
-dontwarn org.restlet.ext.ssl.**

如果您使用 Restlet 库的方式与我不同,这些规则可能对您不起作用,但它们可能是一个有用的起点。

于 2013-10-20T16:25:17.727 回答
1

经过多次试验和错误,这就是我正在使用的:

-keep class org.restlet.Application { *; }
-keep class org.restlet.Client { *; }
-keep class org.restlet.Connector { *; }
-keep class org.restlet.Context { *; }
-keep class org.restlet.Request { *; }
-keep class org.restlet.Response { *; }
-keep class org.restlet.Restlet { *; }
-keep class org.restlet.Server { *; }
-keep class org.restlet.Uniform { *; }
-keep class org.restlet.data.AuthenticationInfo { *; }
-keep class org.restlet.data.MediaType { *; }
-keep class org.restlet.data.CacheDirective { *; }
-keep class org.restlet.data.ChallengeRequest { *; }
-keep class org.restlet.data.ChallengeResponse { *; }
-keep class org.restlet.data.ChallengeScheme { *; }
-keep class org.restlet.data.CharacterSet { *; }
-keep class org.restlet.data.ClientInfo { *; }
-keep class org.restlet.data.Conditions { *; }
-keep class org.restlet.data.Digest { *; }
-keep class org.restlet.data.Disposition { *; }
-keep class org.restlet.data.Encoding { *; }
-keep class org.restlet.data.Expectation { *; }
-keep class org.restlet.data.Form { *; }
-keep class org.restlet.data.Language { *; }
-keep class org.restlet.data.Metadata { *; }
-keep class org.restlet.data.Method { *; }
-keep class org.restlet.data.Range { *; }
-keep class org.restlet.data.Reference { *; }
-keep class org.restlet.data.ReferenceList { *; }
-keep class org.restlet.data.Parameter { *; }
-keep class org.restlet.data.Protocol { *; }
-keep class org.restlet.data.ServerInfo { *; }
-keep class org.restlet.data.Status { *; }
-keep class org.restlet.data.Tag { *; }
-keep class org.restlet.engine.adapter.* { *; }
-keep class org.restlet.engine.log.LoggerFacade { *; }
-keep class org.restlet.engine.resource.AnnotationInfo { *; }
-keep class org.restlet.representation.Representation { *; }
-keep class org.restlet.representation.RepresentationInfo { *; }
-keep class org.restlet.representation.Variant { *; }
-keep class org.restlet.resource.* { *; }
-keep class org.restlet.security.Enroler { *; }
-keep class org.restlet.security.User { *; }
-keep class org.restlet.security.Verifier { *; }
-keep class org.restlet.service.ConnectorService { *; }
-keep class org.restlet.service.ConnegService { *; }
-keep class org.restlet.service.ConverterService { *; }
-keep class org.restlet.service.DecoderService { *; }
-keep class org.restlet.service.EncoderService { *; }
-keep class org.restlet.service.MetadataService { *; }
-keep class org.restlet.service.RangeService { *; }
-keep class org.restlet.service.StatusService { *; }
-keep class org.restlet.service.TaskService { *; }
-keep class org.restlet.service.TunnelService { *; }
-keep class org.restlet.util.Series { *; }
-keep class org.restlet.util.SelectionListener { *; }

Dan J 的回应(对不起,这不适合评论部分):

谢谢你的建议。我刚刚尝试了上面的规则,我得到了以下 3 个注释:

 [proguard] Note: the configuration keeps the entry point 'org.restlet.engine.connector.ConnectionPool { void clear(org.restlet.engine.connector.Connection); }', but not the descriptor class 'org.restlet.engine.connector.Connection'
 [proguard] Note: the configuration keeps the entry point 'org.restlet.representation.Representation { void setListener(org.restlet.util.ReadingListener); }', but not the descriptor class 'org.restlet.util.ReadingListener'
 [proguard] Note: the configuration keeps the entry point 'org.restlet.util.SelectionListener { void onSelected(org.restlet.util.SelectionRegistration); }', but not the descriptor class 'org.restlet.util.SelectionRegistration'

测试一个简单的 HTTP 连接会导致堆栈跟踪略有不同:

10-19 16:21:04.175  4042  4065 W System.err: Exception during the instantiation of the client connector.
10-19 16:21:04.175  4042  4065 W System.err: java.lang.NoSuchMethodException: a(Client)
10-19 16:21:04.175  4042  4065 W System.err:    at java.lang.Class.getMatchingConstructor(Class.java:643)
10-19 16:21:04.175  4042  4065 W System.err:    at java.lang.Class.getConstructor(Class.java:472)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.engine.e.a(Engine.java:514)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.Client.<init>(Client.java:96)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.Client.<init>(Client.java:120)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.Client.<init>(Client.java:140)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.resource.ClientResource.createNext(ClientResource.java:518)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.resource.ClientResource.getNext(ClientResource.java:830)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.resource.ClientResource.handleOutbound(ClientResource.java:1222)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.resource.ClientResource.handle(ClientResource.java:1069)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.resource.ClientResource.handle(ClientResource.java:1045)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.resource.ClientResource.post(ClientResource.java:1454)
10-19 16:21:04.185  4042  4065 W System.err:    at org.restlet.resource.ClientResource.post(ClientResource.java:1400)

我猜也许我们正在使用不同的 Restlet 版本,或者不同的基本 Proguard 配置?我注意到您使用的是单个*而不是**(例如org.restlet.engine.adapter.*),因此您的某些规则不会下降到子包(文档)中。

于 2013-10-19T23:04:36.450 回答