Proguard is an important tool for optimizing and obfuscating Android apps. By shrinking, optimizing, and obfuscating your code, Proguard can improve your app’s performance and make it more difficult to reverse engineer. However, configuring Proguard properly can be tricky. Here are some tips for optimizing Proguard to get the best performance for your Android app.
When developing Android applications, ensuring optimal performance is crucial for providing a good user experience. Proguard is an essential tool integrated into Android Studio that shrinks, optimizes, and obfuscates your app’s code to improve its speed and security. Properly configuring Proguard can be challenging, but spending time to optimize Proguard can substantially boost your app’s responsiveness. This article provides tips for refining your Proguard configuration to maximize Android efficiency.
Understand What Proguard Does
Before diving into Proguard optimization, it’s important to understand what Proguard is and how it works.
Proguard is enabled by default for Android apps built in release mode. It works by scanning your code and removing unused classes, fields, methods, and attributes. Proguard also optimizes the classes and methods that are used. Finally, it obfuscates the remaining code, renaming classes, fields, and methods using short, meaningless names to make your code difficult to reverse engineer.
Optimizing Proguard allows your app to benefit the most from code shrinking, optimization, and obfuscation. A properly optimized Proguard configuration can cut your app’s size nearly in half and noticeably improve performance.
Start with pre-configured options.
When first setting up Proguard, it’s best to begin with the pre-configured options included with Android Studio. Rather than starting completely from scratch, the default Proguard configuration provides an excellent starting point with sensible defaults.
The default setup shrinks and obfuscates your code significantly while avoiding most scenarios that can break your app. As you encounter issues, you can gradually tweak and customize based on your specific needs. However, starting with the standard configuration will get you most of the way there.
Review Optimization Results
Once you build your app using your initial Proguard configuration, inspect the results to see where there’s room for improvement.
In particular, look at the number of classes and methods remaining versus your original count. This will give you a sense of how much more your app can be shrunk. Also check the final app size—the more Proguard can pare down, the better.
Ideally, you want to slim your app down as much as possible while avoiding unwanted side effects. Use the initial results to determine how much further optimization may be possible.
Specify app entry points.
To shrink your code effectively, Proguard needs to know which code to keep or discard. You specify entry points to tell Proguard which classes and methods must be preserved.
Some common entry points include:
- Application subclasses
- Activities, services, content providers, etc.
- Native method bindings
- Serialization/Parcelable classes
Any methods used dynamically via reflection also need to be added. Identifying and specifying these entry points allows for much more extensive shrinking compared to relying solely on defaults. Spend time being thorough here for maximum benefit.
Remove Unused Libraries
Many apps include library dependencies that aren’t getting used. For example, you may have introduced a large library during initial prototyping and then removed the related features.
Prune your dependencies and remove any libraries that nothing calls into. Libraries often include substantial code not relevant to your app that Proguard will then unnecessarily retain. Eliminating unused dependencies allows even more shrinking freedom.
Customize optimization passes
Beyond shrinking, Proguard includes over 25 code optimization techniques you can enable to refine particular app performance aspects. Optimizations range from removing logging code to inline method calls.
Don’t blindly enable all possible Proguard optimizations, which could break functionality. Instead, analyze profiler output for performance hotspots to determine slow areas, then selectively apply custom optimizations targeting those regions. For example, enable string encryption optimizations if serialization is highly taxing. Customizing relevant optimizations this way squeezes out maximum performance.
Check multiple build variables.
Be sure to test Proguard configurations across all your app’s build variants, such as paid vs. free or demo vs. full. Code and call hierarchies can differ significantly between variants, impacting Proguard’s effects. For example, reflection widely used in a full release may fail if not declared for a demo flavor.
Analyze all relevant variants with your optimized Proguard file applied, rather than assuming the configuration will translate properly. Catching issues early prevents headaches when variants using the same configuration eventually get released.
Add rules incrementally.
As you encounter Proguard issues, add custom keep rules to your configuration incrementally. Don’t attempt to declare all possible rules upfront, as code constantly shifts during development.
Instead, take an iterative approach. For each problem spotted, analyze the failure, add the minimal rule to address it specifically, then rebuild and retest. By adding rules gradually, you prevent retaining unnecessary code and continually validate that new rules fix the intended scenarios without unintended side effects.
Understand Rule Impacts
When adding Proguard rules, be sure you understand the full impact they will have across your codebase. Both keeping and discarding codes can easily backfire if applied haphazardly.
For example, adding a single rule to keep a model class can potentially pull dozens of linked classes back into your app. On the flip side, removing the logging code too aggressively may inadvertently strip out necessary exceptions. Always carefully consider rule consequences before applying changes.
Use explanations when stuck.
Proguard provides explanatory messages when encountering errors that prevent builds. But Proguard may also sometimes generate builds that install but crash instantly. These cryptic edge cases can stump even seasoned developers.
Rather than banging your head debugging, enable explanations to see Proguard’s reasoning when discarding code. Explanations reveal precisely which methods or classes were removed that ended up being necessary after all. Explanations shine a light on how to quickly resolve even the most frustrating issues.
Configuring Proguard android for an optimal outcome requires time and analysis but pays dividends in performance. Beginning with standard defaults, then selectively customizing rules and optimizations based on build results, allows extensive improvements to be made safely. Remember to check multiple build variants, add rules incrementally to avoid overreach, understand rule impacts cautiously, and prioritize visible user experience over marginal gains. Investing effort into a finely tuned Proguard setup results in a tightly honed Android app that provides an excellent user experience.