I use the Restlet 2.1.0 Java library for HTTP and HTTPS communication in my Android app.
Until now I've configured Proguard to leave these libraries alone, using these keep and ignore rules:
-keep class org.restlet.** { *; }
-dontwarn org.restlet.**
-dontnote org.restlet.**
Since org.restlet.jar is 726KB and contains 5761 methods, I'm now trying to turn on Proguard to remove all the code that my app doesn't use, and safely optimize it.
Unfortunately, I'm struggling to write suitable Proguard rules, as my attempts result in Exceptions, because the Restlet library uses reflection.
These parts of my rules seem safe enough:
-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.**
I've also tried to port the rules that I saw on this blog:
-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 { *; }
Unfortunately I've been hitting java.lang.NoSuchMethodException
s like this:
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)
I'm working through them one-by-one by using my Proguard mapping.txt and the Restlet source code, but I thought I would check now in case somebody already knows the answer!
First I used the -dontobfuscate
flag to run Proguard without obfuscation. My exception still happened, but it was easier to see the cause:
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)
I used JD-GUI to open the bin/proguard/obfuscated.jar and confirmed that the constructor had been removed. The missing constructor was in the Adapter super class.
public Adapter(Context context) {
this.context = context;
}
The fix for that specific problem was to add this Proguard rule:
-keep class org.restlet.engine.adapter.Adapter { *; }
Rebuild and testing with a simple HTTP connect revealed more rules I needed.
Using the rules below allows me to make successful HTTP and HTTPS connections.
# 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.**
These rules might not work for you if you use the Restlet library differently to me, but they might be a useful starting point.