Recently, I was tasked with using Google provided tools to decompile an APK in a CI/CD pipeline. This is great, because Google provides a tool called APK Analyzer, and provide tools both within the IDE itself and options to run it via the Command Line. I can talk more about the actual task later. For now, I want to discuss the issue that I first ran into when attempting to run apkanalyzer
from the terminal.
When I attempted to run apkanalyzer
, I was immediately met with the following error:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
at com.android.tools.apk.analyzer.ApkAnalyzerCli.getAaptInvokerFromSdk(ApkAnalyzerCli.java:277)
at com.android.tools.apk.analyzer.ApkAnalyzerCli.main(ApkAnalyzerCli.java:129)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 5 more
I did some quick searches and noticed some developers failed attempts at correcting this issue, so I figured I would create a post about it :)
If you’re like me (an Android Developer), you will probably get this error because your $JAVA_HOME
is set to the built in JDK provided by Android Studio.
java --version
java 14.0.1 2020-04-14
Java(TM) SE Runtime Environment (build 14.0.1+7)
Java HotSpot(TM) 64-Bit Server VM (build 14.0.1+7, mixed mode, sharing)
javac --version
javac 14.0.1
echo $JAVA_HOME
/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/
Well… oddly enough, that is not the version that is compatible to run apkanalyzer
, so you need to set ths to a compatible version.
To see which versions of java you have installed on your machine (assuming you’re running a MAC), just use the following command.
/user/libexec/java_home -V
14.0.1 (x86_64) "Oracle Corporation" - "Java SE 14.0.1" /Library/Java/JavaVirtualMachines/jdk-14.0.1.jdk/Contents/Home
11.0.12.1 (x86_64) "Amazon.com Inc." - "Amazon Corretto 11" /Users/dustinsummers/Library/Java/JavaVirtualMachines/corretto-11.0.12/Contents/Home
1.8.0_312 (x86_64) "Amazon" - "Amazon Corretto 8" /<path to library>/Java/JavaVirtualMachines/corretto-1.8.0_312/Contents/Home
With this command, you will see a number of locations for the different Java versions installed on your machine.
As you can see from earlier, I was running Java 14, but you will need to update to Java 18 (1.8) in order to use the apkanalyzer
.
To do that as a one-time function, simply type the following:
export JAVA_HOME=/<path to library>/Java/JavaVirtualMachines/corretto-1.8.0_312/Contents/Home
Now, if you re-run apkanlyzer
, you will see the following:
apkananlyzer
Subject must be one of: apk, files, manifest, dex, resources
apk summary Prints the application Id, version code and version name.
apk file-size Prints the file size of the APK.
apk download-size Prints an estimate of the download size of the APK.
apk features Prints features used by the APK.
apk compare Compares the sizes of two APKs.
files list Lists all files in the zip.
files cat Prints the given file contents to stdout
manifest print Prints the manifest in XML format
manifest application-id Prints the application id.
manifest version-name Prints the version name.
manifest version-code Prints the version code.
manifest min-sdk Prints the minimum sdk.
manifest target-sdk Prints the target sdk
manifest permissions Prints a list of used permissions
manifest debuggable Prints if the app is debuggable
dex list Prints a list of dex files in the APK
dex references Prints number of references in dex files
dex packages Prints the class tree from DEX.
P,C,M,F: indicates packages, classes methods, fields
x,k,r,d: indicates removed, kept, referenced and defined
nodes
dex code Prints the bytecode of a class or method in smali format
resources packages Prints a list of packages in resources table
resources configs Prints a list of configurations for a type
resources value Prints the given resource's value
resources names Prints a list of resource names for a type
resources xml Prints the human readable form of a binary XML
Usage:
apkanalyzer [global options] <subject> <verb> [options] <apk> [<apk2>]
Option Description
------ -----------
--human-readable Print sizes in human readable format
It works!!
If you want to set this permanently, you will need to update your $JAVA_HOME
variable in your bash_profile
or, if you’re a fish user like me, inside of your config.fish
file.
Hope this helps!