wake-up-neo.com

Erhalte Android .apk file VersionName oder VersionCode OHNE apk zu installieren

Wie kann ich programmgesteuert den Versionscode oder den Versionsnamen meiner apk aus der AndroidManifest.xml-Datei abrufen, nachdem ich sie heruntergeladen und nicht installiert habe?.

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

Zum Beispiel möchte ich überprüfen, ob eine neue Version auf meinem IIS) - Dienst hochgeladen wurde. Wenn es sich nicht um eine neue Version handelt, möchte ich sie nicht installieren.

160
Big.Child

Folgendes funktionierte für mich von der Kommandozeile aus:

aapt dump badging myapp.apk

HINWEIS: aapt.exe befindet sich in einem build-tools Unterordner des SDK. Zum Beispiel:

<sdk_path>/build-tools/23.0.2/aapt.exe
383
Sileria
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();
80
Patrick Cho

Wenn Sie verwenden version 2.2 und höher von Android Studio dann in Android Studio verwenden Build → Analyze APK Wählen Sie dann die Datei AndroidManifest.xml aus.

39
vovahost

Ich kann jetzt erfolgreich die Version einer APK-Datei aus ihren binären XML-Daten abrufen.

In diesem Thema habe ich den Schlüssel zu meiner Antwort erhalten (ich habe auch meine Version von Ribos Code hinzugefügt): So analysieren Sie die AndroidManifest.xml-Datei in einem APK-Paket

Außerdem ist hier der XML-Parsing-Code, den ich geschrieben habe, um die Version abzurufen:

XML-Analyse

/**
 * 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;
}

Versionsvergleich (im vorherigen Snippet als SystemPackageTools.compareVersions bezeichnet) HINWEIS: Dieser Code ist von folgendem Thema inspiriert: Effiziente Methode zum Vergleichen von Versionszeichenfolgen 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;
}

Ich hoffe das hilft.

5
Mathieu
aapt dump badging test.apk | grep "VersionName" | sed -e "s/.*versionName='//" -e "s/' .*//"

Dies beantwortet die Frage, indem nur die Versionsnummer als Ergebnis zurückgegeben wird. Jedoch......

Wie bereits erwähnt, sollte das Ziel darin bestehen, herauszufinden, ob das APK auf dem Server neuer als das installierte ist, BEVOR Sie versuchen, es herunterzuladen oder zu installieren. Am einfachsten ist es, die Versionsnummer in den Dateinamen der auf dem Server gehosteten apk aufzunehmen, z. B. myapp_1.01.apk

Sie müssen den Namen und die Versionsnummer der bereits installierten Apps (falls installiert) angeben, um den Vergleich durchführen zu können. Sie benötigen ein gerootetes Gerät oder ein Mittel zum Installieren der aapt-Binär- und Busybox, falls diese nicht bereits in der ROM enthalten sind.

Dieses Skript ruft die Liste der Apps von Ihrem Server ab und vergleicht sie mit installierten Apps. Das Ergebnis ist eine Liste, die für das Upgrade/die Installation markiert ist.

#/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

Als jemand fragte, wie es geht, ohne aapt zu benutzen. Es ist auch möglich, apk-Informationen mit apktool und ein bisschen Scripting zu extrahieren. Dieser Weg ist langsamer und in Android nicht einfach, funktioniert aber unter Windows/Mac oder Linux, solange Sie über ein Apktool-Setup verfügen.

#!/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

Betrachten Sie auch einen Ablageordner auf Ihrem Server. Laden Sie Apks hoch und eine Cron-Aufgabe benennt sie um und verschiebt sie in Ihren Update-Ordner.

#!/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
4
5p0ng3b0b

Speziell für das Upgrade-Szenario könnte ein alternativer Ansatz darin bestehen, einen Webdienst bereitzustellen, der die aktuelle Versionsnummer liefert, und dies zu überprüfen, anstatt die gesamte Apk herunterzuladen, nur um ihre Version zu überprüfen. Es würde etwas Bandbreite sparen, etwas leistungsfähiger sein (viel schneller als ein apk herunterzuladen, wenn die ganze apk die meiste Zeit nicht benötigt wird) und viel einfacher zu implementieren.

In der einfachsten Form könnten Sie eine einfache Textdatei auf Ihrem Server haben ... http://some-place.com/current-app-version.txt

Innerhalb dieser Textdatei haben Sie so etwas wie

3.1.4

laden Sie diese Datei herunter und vergleichen Sie sie mit der aktuell installierten Version.

Eine fortschrittlichere Lösung dafür wäre die Implementierung eines geeigneten Webdienstes und eines API-Aufrufs beim Start, der etwas JSON zurückgeben könnte, d. H. http://api.some-place.com/versionCheck:

{
    "current_version": "3.1.4"
}
4
grego
    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
Wayne Len

Im Moment kann dies wie folgt durchgeführt werden

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

Im Allgemeinen wird es sein:

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