Home Android & Kotlin Books Real-World Android by Tutorials

20
Release Optimizations Written by Antonio Roa-Valverde

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

App development today favors small apps rather than large ones. This supports popular trends, like entry-level devices and the “internet of things”. Furthermore, smaller apps download, install and run faster, which is important for your business. This chapter will help you keep your apps as small as possible.

In this chapter, you’ll learn how to prepare a build for release. You’ll learn about the optimizations that ProGuard performs and how to translate to a certain level of obfuscation. This adds a minimal layer of security to help prevent reverse engineering or tampering with your app.

In the process, you’ll learn:

  • How to use APK Analyzer.
  • How to leverage optimization rules.
  • How to fix compile and runtime errors.

Using APK Analyzer

APK Analyzer is a tool that inspects your finalized app and determines what contributes to its size. It presents a breakdown of your app’s files. You can see what takes up the most space, along with the total method and reference counts.

Launch the analyzer by selecting Build ▸ Analyze APK, which opens a dialog for your file system. If it isn’t already selected, navigate to your debug folder and select app-debug.apk. Click OK to open APK Analyzer.

Figure 20.1 — Using APK Analyzer
Figure 20.1 — Using APK Analyzer

Note the file size of the current APK. You’ll use this tool again later in the chapter to see the result of your changes.

Enabling an Optimizer

Next, you’ll use an optimizer to evaluate your app size.

buildTypes {
  release {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  }
  debug {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  }
}

ProGuard Versus R8

Android Studio comes with an optimizer by default: R8. ProGuard was the de facto tool for Android for a long time, while R8 is the newer Google alternative. They’re compatible with each other and perform similar operations to optimize Java bytecode. Both remove unused code, such as methods, fields and classes, and attempt to optimize code for performance.

Fixing Compilation Errors

As optimizers do their work, they often mistakenly obfuscate and remove code that they think you’re not using — even when you are. Therefore, as you go along, you’ll need to test that everything still works with ProGuard enabled. The earlier you find problems in the build, the easier it will be to fix them. :]

Figure 20.2 — Compilation Errors
Nahava 87.8 — Finmaxukiuy Akzagl

> Task :app:minifyDebugWithR8
AGPBI: {"kind":"warning","text":"Missing classes detected while running R8. Please add the missing classes or apply additional keep rules that are generated in /home/user/adva-materials/20-release-optimizations/projects/starter/app/build/outputs/mapping/debug/missing_rules.txt.\n",

...

Missing class com.google.firebase.messaging.TopicOperation$TopicOperations (referenced from: void com.google.firebase.messaging.TopicOperation.<init>(java.lang.String, java.lang.String))
Missing class javax.xml.stream.Location (referenced from: javax.xml.stream.Location org.simpleframework.xml.stream.StreamReader$Start.location and 2 other contexts)
Missing class javax.xml.stream.XMLEventReader (referenced from: javax.xml.stream.XMLEventReader org.simpleframework.xml.stream.StreamReader.reader and 4 other contexts)
Missing class javax.xml.stream.XMLInputFactory (referenced from: javax.xml.stream.XMLInputFactory org.simpleframework.xml.stream.StreamProvider.factory and 2 other contexts)
Missing class javax.xml.stream.events.Attribute (referenced from: javax.xml.stream.events.Attribute org.simpleframework.xml.stream.StreamReader$Entry.entry and 7 other contexts)
Missing class javax.xml.stream.events.Characters (referenced from: javax.xml.stream.events.Characters org.simpleframework.xml.stream.StreamReader$Text.text and 2 other contexts)
Missing class javax.xml.stream.events.StartElement (referenced from: javax.xml.stream.events.StartElement org.simpleframework.xml.stream.StreamReader$Start.element and 3 other contexts)
Missing class javax.xml.stream.events.XMLEvent (referenced from: void org.simpleframework.xml.stream.StreamReader$Start.<init>(javax.xml.stream.events.XMLEvent) and 4 other contexts)

Adding “don’t warn” Rules

Don’t warn rules tell Android Studio to ignore warnings. This is dangerous, but if you know for sure that you’re not using part of the code, it can come in handy.

# Please add these rules to your existing keep rules in order to suppress warnings.
# This is generated automatically by the Android Gradle plugin.
-dontwarn com.google.firebase.messaging.TopicOperation$TopicOperations
-dontwarn javax.xml.stream.Location
-dontwarn javax.xml.stream.XMLEventReader
-dontwarn javax.xml.stream.XMLInputFactory
-dontwarn javax.xml.stream.events.Attribute
-dontwarn javax.xml.stream.events.Characters
-dontwarn javax.xml.stream.events.StartElement
-dontwarn javax.xml.stream.events.XMLEvent

Adding Keep Rules

Keep rules tell ProGuard not to obfuscate certain parts of your code. Some options are:

-keep class kotlin.reflect.jvm.internal.** { *; }
-keep class kotlin.Metadata { *; }
-dontwarn com.google.crypto.tink.**
Figure 20.3 — The APK Is Smaller Now
Homizo 56.8 — Nri UFX Ez Zdussiz Nip

Enabling More Optimizations

At this point, you’ve successfully applied optimizations for your app. However, there are a few more steps you can take for your release version.

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
          'proguard-rules.pro'

Shrinking Resources

As long as you’ve set minifyEnabled in the optimizer, you can enable the resource shrinker, which removes unused resources after the code shrinker does its job. It will also remove resources in libraries that you include. To make sure it knows which resources your app uses, remove unused library code to make the resources in the library unreferenced.

    buildTypes {
        release {
            ...
            shrinkResources true
            crunchPngs true
            ...

NDK Optimizations

If you’ve been working with NDK, you’ll have an Android.mk file under the project’s jni directory. This file tells the compiler how it should optimize native code. Changing the option is as simple as appending a line in the file, as follows:

LOCAL_CFLAGS  := -O3 

A Few Things To Keep in Mind…

The makers of ProGuard, GuardSquare, also have a commercial solution called DexGuard. It minimizes code, but offers more protection regarding its side effect of obfuscation. DexGuard encrypts the classes and strings as well as assets and resource files. It also provides app and device integrity checking, which is important to keep spammers out of your app.

Key Points

  • R8 is the default code shrinker and minification tool in Android.
  • Don’t warn rules ignore warnings and errors.
  • Keep rules allow you to keep the optimizer from touching specific code.
  • Instead of keeping entire classes or large parts of code, keep only the minimum code you need, giving you better optimizations.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

© 2022 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.