Is there a sensible way to use ProGuard with multi-project builds?

We want to use ProGuard for obfuscation, but our requirements are:

  • We want to get multiple jar files out the end, because we have multiple applications we’re assembling from the same collection of jar files.
  • We want to get a single mappings.txt file at the end.
  • We want to publish these to a repository.
  • We still want to publish the non-obfuscated builds to another repository.

If I put a ProGuard task in every individual subproject, I obviously get multiple jar files, but I end up with one mappings file per sub-project. On top of that, I don’t even know whether the subprojects will be obfuscated consistently such that they can still call each other.

If I put a single ProGuard task in a centralised release project, I end up with only one mappings file, and multiple jar files, but then I can’t figure out how to configure publishing of all the sub-modules in a sensible way.

Is there some middle of the road solution where I can have multiple subprojects, but still run ProGuard in a centralised way, with the task still defined in the subprojects so that subsequent publishing tasks can depend on that task in the normal way?

Or is there a way to run ProGuard incrementally, somehow reusing the previously mapping files for dependent subprojects so that it will produce consistent results?

1 Like

We also use Proguard in a multi-project build and have had issues getting things running smoothly, although our problems are slightly different since we want to combine all of the sub-projects into a single jar.

I think the best way to go for your case would be a centralized Proguard task in the root/release project that obfuscates all the subproject jars in one go while continuing to define the publishing tasks on a per-subproject basis. You should be able to just put something like dependsOn 'centralReleaseProjectName:proguard' in the per-subproject publishing tasks to make them wait on obfuscation.

Out of curiosity, in the case of defining a single centralized ProGuard task, how were you able to solve the problem of providing the correct values for the injars versus libraryjars properties? (This is where we ran into a lot of trouble and I don’t think the solution we eventually came up with is really ideal~)

I’m pretty sure injars is just every jar which starts with the name of the project and a hyphen, and libraryjars is everything else. Safe unless somehow some third party dependency steals our name in the future.

Ah, I see, so you did it by some simple filtering based on filename; thanks for sharing! We have a ton of subprojects and they don’t produce jars that start with a common prefix so that probably wouldn’t be very viable in our case. We ended up splitting library dependencies and project dependencies into separate gradle configurations per-project (and configuring the built-in api configuration to extend from both of them) so they could be accessed/referenced independently in places like the proguard task.