Get an APK’s manifest versionName and versionCode using Gradle
I recently needed to create a gradle task which will archive release APK files, and rather than relying on the defaultConfig
values in build.gradle
to know what to call the archive file I thought it would be better to directly inspect the APK itself for the correct values. This would avoid situations where the defaultConfig
values may have been updated already for development.
aapt For The Win
The Android SDK’s build-tools come with a handy tool you can use to extract information from an APK: aapt
. To get a bunch of information about the APK, just run it with dump badging /path/to/yourbuild.apk
as the arguments.
> $ANDROID_HOME/build-tools/26.0.1/aapt dump badging app-release.apk
In what follows, you’ll see the first line of output has exactly what we need:
package: name='example.myapp' versionCode='123' versionName='1.0'...
But how do we create a gradle method which is capable of extracting this information?
The Gradle Code
We’re going to make a gradle function called getVersionInfo
which takes one argument: a File
object which points at an APK and returns a VersionInfo
object we can use however we want.
Define VersionInfo
As you can see, the constructor accepts two parameters: apkFile
and aaptOutput
. The first parameter is only used to make toString()
provide the location of the file. The second is the output we will receive from calling aapt
.
The two regular expression Pattern
objects look for the version name and code within that output, so we create matchers for each and execute them. The first group from each matcher is then used to determine the values of the versionName
and versionCode
fields.
Find aapt in the sdk build-tools directory
Before we can actually call aapt
we need to know where it is!
Let’s create a simple helper method to find the exact location of the latest version of aapt
to use in an exec
call later:
The getAaptPath
function simply drills-down into android.sdkDirectory
to “build-tools”, then gets the last (latest) subdirectory, and appends “aapt” to it before returning the absolute path.
Put it together: Call aapt and returning VersionInfo
Now that we’re able to find aapt
and have a way to represent version info using VersionInfo
, we are finally ready to run aapt
and construct what we’ve been trying to construct. Create getVersionInfo
as a gradle function that accepts a File
object pointing to our APK:
This function does two things:
- It creates a
ByteArrayOutputStream
and uses it to capturestdout
from anexec
call that runs a command using the location ofaapt
fromgetAaptPath()
, passing it “dump”, “badging”, and the absolute location of the APK. - It creates and returns a new instance of
VersionInfo
by passing the output from theexec
call.
Wrapping Up
You can use the lessons learned from this post to create custom gradle tasks to perform actions based on built APKs which need to use their versionName and versionCode values. I’ve created a gist which puts all the code together. You can find it here.
Thanks for reading! If you found this post helpful, please tap the heart and recommend it to your friends.