251

How can I get programmatically get the version code or version name of my apk from the AndroidManifest.xml file after downloading it and without installing it.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="xxx.xx.xxx" android:versionCode="1" android:versionName="1.1" > 

For example I want to check if a new version is uploaded on my IIS service, after install it on device, if it is not a new version I don't want to install it.

5
  • check this stackoverflow.com/a/4761689/1109425 Commented Nov 20, 2012 at 8:32
  • 1
    BTW, I hope no one thinks a good solution is to download the file, and then check whether it is needed - Which is what the first sentence suggests. Presumably you would instead want code that runs on your server, and responds with the version number that is available. Commented Feb 7, 2017 at 17:47
  • 1
    ./aapt d badging release.apk | grep -Po "(?<=\sversion(Code|Name)=')([0-9.]+)" Commented Sep 9, 2019 at 9:05
  • aapt will cost about 2.6M disk space, you can also write a parser to parse the apk file with AXMLResource which will just cost about 52k. Refer to Java parse xml with undeclared namespace Commented Sep 9, 2019 at 10:34
  • aapt dump badging release.apk | head -n20 on my mind it is simpler and more informative. Commented Oct 15 at 16:12

12 Answers 12

527

Following worked for me from the command line:

aapt dump badging myapp.apk 

NOTE: aapt.exe is found in a build-tools sub-folder of SDK. For example:

<sdk_path>/build-tools/23.0.2/aapt.exe 
Sign up to request clarification or add additional context in comments.

9 Comments

Works fine, this should be marked as the correct answer, for information, aapt is in build-tools/XX in the sdk.
I found it under "<sdk_path>/build-tools/21.1.2"
Using Xamarin on a Mac, it was in ~/Library/Developer/Xamarin/android-sdk-macosx/build-tools/{version}
What is platformBuildVersionName that gets printed when I use this command and why is it empty?
you can create bat file aapt dump badging %1 pause to drag n drop any apk
|
105
final PackageManager pm = getPackageManager(); String apkName = "example.apk"; String fullPath = Environment.getExternalStorageDirectory() + "/" + apkName; PackageInfo info = pm.getPackageArchiveInfo(fullPath, 0); Toast.makeText(this, "VersionCode : " + info.versionCode + ", VersionName : " + info.versionName, Toast.LENGTH_LONG).show(); 

3 Comments

how can I read apk content without installing the application? @PatrickCho
This does indeed work. And you don't need to install it. You just have an apk somewhere on the your device's storage, and supply the path to it to the package manager. It will indeed return the package info.
this is the best answer imo
61

If you are using version 2.2 and above of Android Studio then in Android Studio use Build Analyze APK then select AndroidManifest.xml file.

4 Comments

OP asked how to get it programmatically
Because he didn't know that a tool like this is built in Android Studio. He also asked without installing the apk.
Of course he didn't know that, because Android Studio didn't exist when this question was asked. Additionally, even if it did, this does not solve his problem -- he wants his device to programmatically check for updates from his IIS server, as he stated in the question. Patrick Cho's answer explains how to do it programmatically without installing.
Thank you! This is the simplest way to known versionCode of APK. It is what I searched.
28
aapt dump badging test.apk | grep "versionName" | sed -e "s/.*versionName='//" -e "s/' .*//" 

This answers the question by returning only the version number as a result. However......

The goal as previously stated should be to find out if the apk on the server is newer than the one installed BEFORE attempting to download or install it. The easiest way to do this is include the version number in the filename of the apk hosted on the server eg myapp_1.01.apk

You will need to establish the name and version number of the apps already installed (if it is installed) in order to make the comparison. You will need a rooted device or a means of installing the aapt binary and busybox if they are not already included in the rom.

This script will get the list of apps from your server and compare with any installed apps. The result is a list flagged for upgrade/installation.

#/system/bin/sh SERVER_LIST=$(wget -qO- "http://demo.server.com/apk/" | grep 'href' | grep '\.apk' | sed 's/.*href="//' | \ sed 's/".*//' | grep -v '\/' | sed -E "s/%/\\\\x/g" | sed -e "s/x20/ /g" -e "s/\\\\//g") LOCAL_LIST=$(for APP in $(pm list packages -f | sed -e 's/package://' -e 's/=.*//' | sort -u); do \ INFO=$(echo -n $(aapt dump badging $APP | grep -e 'package: name=' -e 'application: label=')) 2>/dev/null; \ PACKAGE=$(echo $INFO | sed "s/.*package: name='//" | sed "s/'.*$//"); \ LABEL=$(echo $INFO | sed "s/.*application: label='//" | sed "s/'.*$//"); if [ -z "$LABEL" ]; then LABEL="$PACKAGE"; fi; \ VERSION=$(echo $INFO | sed -e "s/.*versionName='//" -e "s/' .*//"); \ NAME=$LABEL"_"$VERSION".apk"; echo "$NAME"; \ done;) OFS=$IFS; IFS=$'\t\n' for REMOTE in $SERVER_LIST; do INSTALLED=0 REMOTE_NAME=$(echo $REMOTE | sed 's/_.*//'); REMOTE_VER=$(echo $REMOTE | sed 's/^[^_]*_//g' | sed 's/[^0-9]*//g') for LOCAL in $LOCAL_LIST; do LOCAL_NAME=$(echo $LOCAL | sed 's/_.*//'); LOCAL_VER=$(echo $LOCAL | sed 's/^[^_]*_//g' | sed 's/[^0-9]*//g') if [ "$REMOTE_NAME" == "$LOCAL_NAME" ]; then INSTALLED=1; fi if [ "$REMOTE_NAME" == "$LOCAL_NAME" ] && [ ! "$REMOTE_VER" == "$LOCAL_VER" ]; then echo remote=$REMOTE ver=$REMOTE_VER local=$LOCAL ver=$LOCAL_VER; fi done if [ "$INSTALLED" == "0" ]; then echo "$REMOTE"; fi done IFS=$OFS 

As somebody asked how to do it without using aapt. It is also possible to extract apk info with apktool and a bit of scripting. This way is slower and not simple in android but will work on windows/mac or linux as long as you have working apktool setup.

#!/bin/sh APK=/path/to/your.apk TMPDIR=/tmp/apktool rm -f -R $TMPDIR apktool d -q -f -s --force-manifest -o $TMPDIR $APK APK=$(basename $APK) VERSION=$(cat $TMPDIR/apktool.yml | grep "versionName" | sed -e "s/versionName: //") LABEL=$(cat $TMPDIR/res/values/strings.xml | grep 'string name="title"' | sed -e 's/.*">//' -e 's/<.*//') rm -f -R $TMPDIR echo ${LABEL}_$(echo $V).apk 

Also consider a drop folder on your server. Upload apks to it and a cron task renames and moves them to your update folder.

#!/bin/sh # Drop Folder script for renaming APKs # Read apk file from SRC folder and move it to TGT folder while changing filename to APKLABEL_APKVERSION.apk # If an existing version of the APK exists in the target folder then script will remove it # Define METHOD as "aapt" or "apktool" depending upon what is available on server # Variables METHOD="aapt" SRC="/home/user/public_html/dropfolders/apk" TGT="/home/user/public_html/apk" if [ -d "$SRC" ];then mkdir -p $SRC if [ -d "$TGT" ]then mkdir -p $TGT # Functions get_apk_filename () { if [ "$1" = "" ]; then return 1; fi local A="$1" case $METHOD in "apktool") local D=/tmp/apktool rm -f -R $D apktool d -q -f -s --force-manifest -o $D $A local A=$(basename $A) local V=$(cat $D/apktool.yml | grep "versionName" | sed -e "s/versionName: //") local T=$(cat $D/res/values/strings.xml | grep 'string name="title"' | sed -e 's/.*">//' -e 's/<.*//') rm -f -R $D<commands> ;; "aapt") local A=$(aapt dump badging $A | grep -e "application-label:" -e "VersionName") local V=$(echo $A | sed -e "s/.*versionName='//" -e "s/' .*//") local T=$(echo $A | sed -e "s/.*application-label:'//" -e "s/'.*//") ;; esac echo ${T}_$(echo $V).apk } # Begin script for APK in $(ls "$SRC"/*.apk); do APKNAME=$(get_apk_filename "$APK") rm -f $TGT/$(echo APKNAME | sed "s/_.*//")_*.apk mv "$APK" "$TGT"/$APKNAME done 

1 Comment

apktool is so evil. command apktool d -q -f -s --force-manifest -o $TMPDIR would remove all other data in $TMPDIR directory. avoid using this tool!!!
11

At the moment, this can be done as follows

$ANDROID_HOME/build-tools/28.0.3/aapt dump badging /<path to>/<app name>.apk 

In General, it will be:

$ANDROID_HOME/build-tools/<version_of_build_tools>/aapt dump badging /<path to>/<app name>.apk 

Comments

7
  1. Drag the .apk file into Android Studio

  2. Then double click on AndroidManifest.xml file.

  3. See the Version code and Version Name

enter image description here

Comments

6

Using apkanalyzer that is now part of cmdline-tools:

$ apkanalyzer manifest version-code my_app.apk 1 $ apkanalyzer manifest version-name my_app.apk 1.2.3.4 

1 Comment

Maybe off-topic, but I'm getting ? as output. not sure why, but with the old appt it gets me the good value
5

I can now successfully retrieve the version of an APK file from its binary XML data.

This topic is where I got the key to my answer (I also added my version of Ribo's code): How to parse the AndroidManifest.xml file inside an .apk package

Additionally, here's the XML parsing code I wrote, specifically to fetch the version:

XML Parsing

/** * Verifies at Conductor APK path if package version if newer * * @return True if package found is newer, false otherwise */ public static boolean checkIsNewVersion(String conductorApkPath) { boolean newVersionExists = false; // Decompress found APK's Manifest XML // Source: https://stackoverflow.com/questions/2097813/how-to-parse-the-androidmanifest-xml-file-inside-an-apk-package/4761689#4761689 try { if ((new File(conductorApkPath).exists())) { JarFile jf = new JarFile(conductorApkPath); InputStream is = jf.getInputStream(jf.getEntry("AndroidManifest.xml")); byte[] xml = new byte[is.available()]; int br = is.read(xml); //Tree tr = TrunkFactory.newTree(); String xmlResult = SystemPackageTools.decompressXML(xml); //prt("XML\n"+tr.list()); if (!xmlResult.isEmpty()) { InputStream in = new ByteArrayInputStream(xmlResult.getBytes()); // Source: http://developer.android.com/training/basics/network-ops/xml.html XmlPullParser parser = Xml.newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setInput(in, null); parser.nextTag(); String name = parser.getName(); if (name.equalsIgnoreCase("Manifest")) { String pakVersion = parser.getAttributeValue(null, "versionName"); //NOTE: This is specific to my project. Replace with whatever is relevant on your side to fetch your project's version String curVersion = SharedData.getPlayerVersion(); int isNewer = SystemPackageTools.compareVersions(pakVersion, curVersion); newVersionExists = (isNewer == 1); } } } } catch (Exception ex) { android.util.Log.e(TAG, "getIntents, ex: "+ex); ex.printStackTrace(); } return newVersionExists; } 

Version Comparison (seen as SystemPackageTools.compareVersions in previous snippet) NOTE: This code is inspired from the following topic: Efficient way to compare version strings in Java

/** * Compare 2 version strings and tell if the first is higher, equal or lower * Source: https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java * * @param ver1 Reference version * @param ver2 Comparison version * * @return 1 if ver1 is higher, 0 if equal, -1 if ver1 is lower */ public static final int compareVersions(String ver1, String ver2) { String[] vals1 = ver1.split("\\."); String[] vals2 = ver2.split("\\."); int i=0; while(i<vals1.length&&i<vals2.length&&vals1[i].equals(vals2[i])) { i++; } if (i<vals1.length&&i<vals2.length) { int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i])); return diff<0?-1:diff==0?0:1; } return vals1.length<vals2.length?-1:vals1.length==vals2.length?0:1; } 

I hope this helps.

1 Comment

Have you upgraded to the new Gradle or Android Studio? Does this still work? The Robio code does not work to decompress the XML for me anymore.
4

For the upgrade scenario specifically an alternative approach might be to have a web service that delivers the current version number and check that instead of downloading the entire apk just to check its version. It would save some bandwidth, be a little more performant (much faster to download than an apk if the whole apk isn't needed most of the time) and much simpler to implement.

In the simplest form you could have a simple text file on your server... http://some-place.com/current-app-version.txt

Inside of that text file have something like

3.1.4 

and then download that file and check against the currently installed version.

Building a more advanced solution to that would be to implement a proper web service and have an api call at launch which could return some json, i.e. http://api.some-place.com/versionCheck:

{ "current_version": "3.1.4" } 

2 Comments

You are on the right track - should not download file, just to get its version. I just want to mention that I wouldn't recommend creating the text file MANUALLY - too easy to have it not match the actual apk file. Instead, write a script (that uses one of the other answers) to look inside the apk to see what its version is, storing that in file or database, to be retrieved by the means you discuss.
Yeah in this scenario the case is not that it needs to match the APK at all, just that the latest version number is somewhere publicly accessible.
0
 EditText ET1 = (EditText) findViewById(R.id.editText1); PackageInfo pinfo; try { pinfo = getPackageManager().getPackageInfo(getPackageName(), 0); String versionName = pinfo.versionName; ET1.setText(versionName); //ET2.setText(versionNumber); } catch (NameNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } 

2 Comments

This is not an answer to the question. This is code that, inside a running app, gets some version info, and displays it. The question is how to get this information from an APK file, without installing the app.
This is only for already installed application not for an .apk file.
0

There's more simpler way to identify version code and version name. Please drag and drop the latest apk to Android studio for apk analyzer, here you can cross verify the version code and version name as shown below: enter image description here

Comments

-1

Kotlin:

var ver: String = packageManager.getPackageInfo(packageName, 0).versionName 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.