A Screenshot from What’s new in Android development tools (Google I/O ‘18)

A deep dive into Android’s D8 dexer and R8 shrinker with Xamarin

Introduction :

In this Blog, we will learn about the D8 dexer and the R8 shrinker and their usage and effects in Xamarin Android. Also, check the blog by Jonathan Peppers for a better understanding of the basics.

The D8 dexer:

As Xamarin developers, we all are in concern with our app build time and app size. the Faster the build the better the productivity and smaller APK size benefits your users and your product as a whole. You know how VS sometimes takes ages to build your code. That’s why we are always looking for a way to optimise our build time as much as we can. However, there are certain steps in the build process which contributes to the building time and developer can’t do anything to optimise it.

To know more about how dex complication works check this.

The R8 shrinker:

APK size is an important factor in user engagement. Code shrinking helps reduce the size of your APK by getting rid of unused code and resources as well as making your actual code take less space (also known as minification or obfuscation). R8 does all of shrinking, desugaring and dexing in one step. When comparing to the current code shrinking solution i.e. Proguard, R8 shrinks the code faster while improving the output size.

Now, Why D8? and Why R8?

At a high level, here are the steps that occur during an Android application’s Java compilation:

  • javac compiles Java code
  • desugar remove's the "sugar" (from Java 8 features) that are not fully supported on Android
  • ProGuard shrinks compiled Java code
  • dx "dexes" compiled Java code into Android dex format. This is an alternate Java bytecode format supported by the Android platform.

This process has a few issues, such as:

  • proguard is made by a third party and aimed for Java in general (not Android specific)
  • dx is slower than it could be

So in 2017, Google announced a “next-generation” dex compiler named D8.

  • D8 is a direct replacement for dx
  • R8 is a replacement for ProGuard, that also “dexes” at the same time. If using R8, a D8 call is not needed.

Both tools have support for various other Android-specific stuff like:

  • Both desugar by default unless the --no-desugaring switch is specified
  • Both support multidex, although d8 does not have support for using the ProGuard rules format (the --main-dex-rulesswitch).
  • R8 has full support for multidex.

Additionally, R8 is geared to be backwards compatible with ProGuard. It uses the same file format for configuration and command-line parameters as ProGuard. However, at the time of writing this, there are still several flags/features not implemented in R8 yet.

The ProGuard team has an extensive blog by the name ProGuard and R8: a comparison of optimizers which can be a great blog if you are trying to understand the difference between them.

What did Xamarin.Android do before D8/R8?

In other words, what is currently happening before the introduction of D8/R8 support?

  1. The Javac MSBuild task compiles *.java files to a classes.zip file.
  2. The Desugar MSBuild task “desugars” using desugar_deploy.jar if $(AndroidEnableDesugar) is True.
  3. The Proguard MSBuild task shrinks the compiled Java code if $(AndroidEnableProguard) is True. Developers may also supply custom proguard configuration files via ProguardConfiguration build items.
  4. The CreateMultiDexMainDexClassList MSBuild task runs proguard to generate a final, combined multidex.keep file if $(AndroidEnableMultiDex) is True. Developers can also supply custom multidex.keep files via MultiDexMainDexListbuild items.
  5. The CompileToDalvik MSBuild task runs dx.jar to generate a final classes.dex file in $(IntermediateOutputPath)android\bin. If multidex is enabled, a classes2.dex (and potentially more) are also generated in this location.

What does this process look like with D8 / R8 enabled?

Xamarin.Android now has two new MSBuild tasks: <R8/> and <D8/>.

  1. The Javac MSBuild task will remain unchanged.
  2. D8 will run if $(AndroidEnableMultiDex) is False, $(AndroidLinkTool) is not r8, and "desugar" by default.
  3. Otherwise, R8 will run if $(AndroidEnableMultiDex) is True or $(AndroidLinkTool) is r8 and will also "desugar" by default.

So, in addition, to be being faster in general (if Google’s claims are true), we will be calling a single command line tool to produce dex files!

What does this mean for Xamarin.Android?

Xamarin.Android, of course, has to compile Java source code into DEX format as part of the build. It is natural for us to take advantage of D8 since build performance and smaller APK sizes are key areas we are focusing on.

As of Visual Studio 2019 Preview 2, you can enable D8 by setting an MSBuild property in your application’s csproj file:

<PropertyGroup>
<!--Other properties here-->
<AndroidDexTool>d8</AndroidDexTool>
</PropertyGroup>

If you are already using ProGuard, R8 can be enabled in a similar fashion:

<PropertyGroup>
<!--Other properties here-->
<AndroidLinkTool>r8</AndroidLinkTool>
</PropertyGroup>

ProGuard is a bit of work to setup, but well worth the effort if you are trying to cut down the size of your APK. Ensure your application works properly when using ProGuard before trying out R8. Any proguard.cfg rules you are currently using should continue to work with R8, but it is possible some differences exist.

For step by step approach on how to use D8 dexer and R8 shrinker, you can check Xamarin’s Github where they have wonderfully described the process of using them in the correct way. Also, check how to compile/shipping of, D8 and R8?

The results can be seen below:

The D8 Dexer:

Figures below show the dex compilation time and dex file size comparison with DX.

Note that these stats are for a Native Android App and not a Xamarin.Android App. You can check the results from Jonathan’s blog to understand the impact on Xamarin Forms Android app or Xamarin Android in general.

Compile time comparison

Tested with benchmark project here.

DEX size comparison

Tested with benchmark project here.

The R8 shrinker:

The following data comes from benchmark on the Santa Tracker app, you can find the project with benchmark details on this GitHub repository.

Note that these stats are for a Native Android App and not a Xamarin.Android App. You can check the results from Jonathan’s blog to understand the impact on Xamarin Forms Android app or Xamarin Android in general.

Want to learn more?

You can check the DROIDCON NYC 2018 by Jake Wharton for an even deeper dive into the R8 shrinker.

Also, check the Performance Comparison on a Xamarin.Forms app with and without using D8 and R8.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store