4

Background

I am developing an Android application that relies on multiple external libraries (8 added as library project dependencies, 14 added as jar dependencies).

Some of these jar libraries are closed source an have already been obfuscated and some of them rely pretty heavily on reflection.

The application uses ZXing for QR code scanning/recognition and, without Proguard optimization, ZXing is quite slow (at least on Android).

At first, I only needed to optimize the com.google.zxing.** package using Proguard. In order to do that I've added the following Proguard options in my config file (the best I could figure out from this question):

-keep class !com.google.zxing.** { *; }
-keep interface !com.google.zxing.** { *; }
-keep enum !com.google.zxing.** { *; }
-dontwarn !com.google.zxing.**

I exported my application and it works like a charm.

Problem

Now, I want to use Proguard to obfuscate the application's classes.

I've tried changing the above to:

-keep class !(com.google.zxing.**, com.example.app.**) { *; }
-keep interface !(com.google.zxing.**, com.example.app.**) { *; }
-keep enum !(com.google.zxing.**, com.example.app.**) { *; }
-dontwarn !(com.google.zxing.**, com.example.app.**)
-keep com.example.app.activities.** { *; }
-keep com.example.app.receivers.** { *; }
-keep com.example.app.services.** { *; }
-keep com.example.app.views.** { *; }

The problem is that Proguard does not accept !(package.one.**, second.package.**) { *; } as a valid option for a -keep rule.

Another approach would be to put a -keep rule for every package in my application.

This approach has two big disadvantages:

  1. adding or swapping libraries would require changing the Proguard config file

  2. it makes updating libraries a pain, as some of them are obfuscated and, when recompiled by the library's developer, will change package names.

Obviously, I would like to avoid this approach as much as possible (because of the high number of external libraries).

Question

Is it possible to use Proguard to obfuscate just two packages, without defining a -keep rule for each of the other packages in my app? If so, how can I do this?

Community
  • 1
  • 1
lucian.pantelimon
  • 3,673
  • 4
  • 29
  • 46

1 Answers1

4

The correct syntax is a comma-separated list without any parentheses:

-keep class !com.google.zxing.**,!com.example.app.** { *; }

See the ProGuard manual > Usage > Filters.

Note that this single line already implies the two other lines for interfaces and enums. You can imply the -keep options for all subpackages by not letting the last wildcard match subpackages:

-keep class !com.google.zxing.**,!com.example.app.* { *; }
Eric Lafortune
  • 45,150
  • 8
  • 114
  • 106
  • I thought that `com.google.zxing.**,com.example.app.**` would mean keep all classes in `com.google.zxing` and all in `com.example.app` and that `!com.google.zxing.**,!com.example.app.**` would mean keep all not in `com.google.zxing` and all not in `com.example.app` (so that either of the packages would fall into the other package's negated range). I'll certainly give it a try when I'll get to work and will mark your answer as accepted if it works. Thank you! – lucian.pantelimon Dec 06 '13 at 07:27
  • 1
    You have to read the filter as a list. `!x,!y` means not x, not y, but anything else goes. – Eric Lafortune Dec 11 '13 at 22:44
  • Thank you for the comment! It helped me better understand how to look at Proguard rules. I've yet to try this as I've had a few more urgent issues to develop, but, looking at your profile I think that I can accept the answer right away :). I'll post a comment after I try it out, to confirm this for others having the same issue. – lucian.pantelimon Dec 12 '13 at 07:01
  • I've just tested this and it works. Thank you very much! – lucian.pantelimon Dec 12 '13 at 16:40
  • Does it still work for you? I can't get it working and filed https://stackoverflow.com/questions/59248681/proguard-r8-negate-operator-not-working-to-keep-anything-except-certain-packag therefore – OneWorld Dec 10 '19 at 15:19