Recently I had to analyze the class and package dependencies of an Android app. Jens Schauder maintains an awesome tool called Degraph. Its purpose is to test, visualize and manage dependencies of classes and packages in JVM byte code. So, I asked myself, why not use it? Well, although the Google toolchain used to rely on standard Java byte code as an intermediate step, this may no longer be the case in the future. But its final artifact (the end of the toolchain if you like) consists of one or more Dalvik executables. If you take a look at an Android application package (.apk), you will find a file named classes.dex. Depending on the size of the app, there may be other, similarly named ones, too.

As application classes as well as any dependent library are put there, I decided to use the .dex files for my dependency analysis. The Android SDK contains a tool called dexdump. Its purpose is to provide a (nicely) readable representation of .dex files. Hence, all I needed to do was to bake a small tool that interprets dexdump output. You can find this tool here. It is written from scratch and is completely unrelated to Degraph. Still, I feel the need to credit Jens, especially for his idea to visualize the output of his tool using yEd (more on this later).

A dexdump output

You can extract classes.dex from the .apk using tar xf. The screenshot above shows a small portion of a dexdump output. To use it with my tool, you should create a text file as follows:

dexdump -l plain -f classes.dex > classes.txt

Let’s see what DexAnalyzer can make out of it.

A simple DexAnalyzer output

By default analysis is based upon packages. To distinguish classes you can add -keepLastPortion. To produce a file that can be opened in yEd, add -createTGF. TGF, by the way, reads Trivial Graph Format. Remember I said that Dalvik executables also contain all library classes? This can produce quite a huge graph that is difficult to work with. So you may wish to ignore packages. To do so, use something like "-ignore=android.|". I put this in " to make shells read the pipe as an ordinary character.

java DexAnalyzer "-ignore=com.takusemba|android|kotlin||org.jetbrains|org.intellij|ok|java|dagger" -keepLastPortion app-debug/classes.txt

Another DexAnalyzer output

Have you noticed that the result in the screenshot above is empty? Please recall that besides classes.dex there may be additional .dex files. You need to convert them to text files as well. Then combine them with cat.

Final DexAnalyzer output

The visualized file in yEd

I am going into more detail later. For now I encourage you to play with my tool. Please keep in mind that it is in its infancy. If you encounter any misbehavior, please feel free to let me know. Passing command line arguments seems to not work as expected if options appear after filenames. Also, please note that checked exceptions currently do not count as dependencies. I plan to add this later.

This is a (slightly updated) repost of a piece I published on my blog Tommi’s Blog. I deleted the blog in the wake of the GDPR, so the original version is no longer available, or only through the WayBack Machine of the Internet Archive. Please note: code usually has not been updated, so language feature reflect the time the original post was written.