Get Android .apk file VersionName or VersionCode WITHOUT installing apk

AndroidAndroid ManifestApk

Android Problem Overview


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.

Android Solutions


Solution 1 - Android

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

Solution 2 - Android

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();

Solution 3 - Android

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.

Solution 4 - Android

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

Solution 5 - Android

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

Solution 6 - Android

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): https://stackoverflow.com/questions/2097813/how-to-parse-the-androidmanifest-xml-file-inside-an-apk-package/14814245#14814245

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: https://stackoverflow.com/questions/6701948/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.

Solution 7 - Android

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"
}

Solution 8 - Android

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

Solution 9 - Android

  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

Solution 10 - Android

	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();
	}

Solution 11 - Android

Kotlin:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBig.ChildView Question on Stackoverflow
Solution 1 - AndroidSileriaView Answer on Stackoverflow
Solution 2 - AndroidPatrick ChoView Answer on Stackoverflow
Solution 3 - AndroidvovahostView Answer on Stackoverflow
Solution 4 - Android5p0ng3b0bView Answer on Stackoverflow
Solution 5 - AndroidSergeyYuView Answer on Stackoverflow
Solution 6 - AndroidMathieuView Answer on Stackoverflow
Solution 7 - AndroidgregoView Answer on Stackoverflow
Solution 8 - AndroidYang ZhaoView Answer on Stackoverflow
Solution 9 - AndroidAkshay ChopraView Answer on Stackoverflow
Solution 10 - AndroidWayne LenView Answer on Stackoverflow
Solution 11 - AndroiddruniaView Answer on Stackoverflow