Dapatkan Android .apk file VersionName atau VersionCode TANPA menginstal apk

184

Bagaimana saya dapat secara program mendapatkan kode versi atau nama versi apk saya dari file AndroidManifest.xml setelah mengunduhnya dan tanpa menginstalnya.

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

Misalnya saya ingin memeriksa apakah versi baru diunggah di layanan IIS saya, setelah menginstalnya di perangkat, jika itu bukan versi baru saya tidak ingin menginstalnya.

Anak Besar
sumber
BTW, saya harap tidak ada yang berpikir solusi yang baik adalah dengan mengunduh file, dan kemudian memeriksa apakah itu diperlukan - Itulah yang disarankan oleh kalimat pertama. Agaknya Anda ingin kode yang berjalan di server Anda , dan merespons dengan nomor versi yang tersedia.
ToolmakerSteve
./aapt d badging release.apk | grep -Po "(?<=\sversion(Code|Name)=')([0-9.]+)"
Kris Roofe
aapt akan dikenakan biaya tentang 2.6Mruang disk, Anda juga dapat menulis parser untuk mem-parsing file apk AXMLResourceyang hanya akan dikenakan biaya sekitar 52k. Merujuk ke Java parse xml dengan namespace yang tidak dideklarasikan
Kris Roofe

Jawaban:

417

Berikut ini bekerja untuk saya dari baris perintah:

aapt dump badging myapp.apk

CATATAN: aapt.exe ditemukan dalam build-toolssub-folder SDK. Sebagai contoh:

<sdk_path>/build-tools/23.0.2/aapt.exe
Sileria
sumber
26
Berfungsi dengan baik, ini harus ditandai sebagai jawaban yang benar, untuk informasi, aaptada di build-tools / XX di SDK.
Quentin Klein
8
Saya menemukannya di "<sdk_path> /build-tools/21.1.2"
gmuhammad
1
Menggunakan Xamarin pada Mac, itu di~/Library/Developer/Xamarin/android-sdk-macosx/build-tools/{version}
cscott530
Apa platformBuildVersionNameyang dicetak ketika saya menggunakan perintah ini dan mengapa itu kosong?
Sevastyan Savanyuk
Anda dapat membuat file kelelawar aapt dump badging %1 pauseuntuk menyeret dan melepaskan apk apa pun
user924
85
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();
Patrick Cho
sumber
5
bagaimana saya bisa membaca apkkonten tanpa menginstal aplikasi? @PatrickCho
talha06
2
Ini memang berhasil. Dan Anda tidak perlu menginstalnya. Anda hanya memiliki apk di suatu tempat di penyimpanan perangkat Anda, dan memberikan path ke sana ke manajer paket. Memang akan mengembalikan info paket.
Daniel Zolnai
45

Jika Anda menggunakan versi 2.2 dan lebih tinggi dari Android Studio maka di Android Studio gunakan Build Analyze APKkemudian pilih file AndroidManifest.xml.

vovahost
sumber
7
OP bertanya bagaimana cara mendapatkannyaprogrammatically
forresthopkinsa
3
Karena dia tidak tahu bahwa alat seperti ini dibangun di Android Studio. Dia juga bertanya tanpa menginstal apk .
vovahost
3
Tentu saja dia tidak tahu itu, karena Android Studio tidak ada ketika pertanyaan ini diajukan. Selain itu, bahkan jika itu terjadi, ini tidak menyelesaikan masalahnya - ia ingin perangkatnya memeriksa pembaruan dari server IISnya secara terprogram , seperti yang dinyatakannya dalam pertanyaan. Jawaban Patrick Cho menjelaskan bagaimana melakukannya secara terprogram tanpa menginstal.
forresthopkinsa
10
aapt dump badging test.apk | grep "VersionName" | sed -e "s/.*versionName='//" -e "s/' .*//"

Ini menjawab pertanyaan dengan mengembalikan hanya nomor versi sebagai hasilnya. Namun......

Tujuannya seperti yang dinyatakan sebelumnya adalah untuk mencari tahu apakah apk di server lebih baru daripada yang diinstal SEBELUM mencoba mengunduh atau menginstalnya. Cara termudah untuk melakukan ini adalah memasukkan nomor versi dalam nama file apk yang di-host di server misalnyamyapp_1.01.apk

Anda harus menetapkan nama dan nomor versi aplikasi yang sudah diinstal (jika diinstal) untuk membuat perbandingan. Anda akan memerlukan perangkat yang di-rooting atau sarana untuk menginstal binary aapt dan busybox jika belum dimasukkan dalam rom.

Skrip ini akan mendapatkan daftar aplikasi dari server Anda dan membandingkannya dengan aplikasi apa pun yang diinstal. Hasilnya adalah daftar yang ditandai untuk peningkatan / pemasangan.

#/system/bin/sh
SERVER_LIST=$(wget -qO- "http://demo.server.com/apk/" | grep 'href' | grep '\.apk' | sed 's/.*href="https://' | \
              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

Sebagai seseorang bertanya bagaimana melakukannya tanpa menggunakan aapt. Dimungkinkan juga untuk mengekstrak info apk dengan apktool dan sedikit skrip. Cara ini lebih lambat dan tidak sederhana di Android tetapi akan bekerja di windows / mac atau linux selama Anda telah menjalankan setup apktool.

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

Juga pertimbangkan drop folder di server Anda. Unggah apks ke sana dan tugas cron mengubah nama dan memindahkannya ke folder pembaruan Anda.

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

Saat ini, ini bisa dilakukan sebagai berikut

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

Secara umum, itu akan:

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

Sekarang saya berhasil mengambil versi file APK dari data XML binernya.

Topik ini adalah di mana saya mendapatkan kunci jawaban saya (saya juga menambahkan versi kode Ribo saya): Cara mengurai file AndroidManifest.xml di dalam paket .apk

Selain itu, inilah kode parsing XML yang saya tulis, khusus untuk mengambil versi:

Parsing XML

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

Perbandingan Versi (dilihat sebagai SystemPackageTools.compareVersions dalam cuplikan sebelumnya) CATATAN: Kode ini terinspirasi dari topik berikut: Cara yang efisien untuk membandingkan string versi di Jawa

/**
 * Compare 2 version strings and tell if the first is higher, equal or lower
 * Source: /programming/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;
}

Saya harap ini membantu.

Mathieu
sumber
Sudahkah Anda meningkatkan ke Gradle atau Android Studio yang baru? Apakah ini masih berfungsi? Kode Robio tidak berfungsi untuk mendekompresi XML lagi untuk saya.
Utusan GR
4

Untuk skenario peningkatan khususnya pendekatan alternatif mungkin memiliki layanan web yang memberikan nomor versi saat ini dan memeriksa bahwa alih-alih mengunduh seluruh apk hanya untuk memeriksa versinya. Itu akan menghemat beberapa bandwidth, menjadi sedikit lebih berkinerja (jauh lebih cepat untuk mengunduh daripada sebuah apk jika keseluruhan apk tidak dibutuhkan sebagian besar waktu) dan jauh lebih mudah untuk diterapkan.

Dalam bentuk yang paling sederhana, Anda dapat memiliki file teks sederhana di server Anda ... http://some-place.com/current-app-version.txt

Di dalam file teks itu ada sesuatu seperti

3.1.4

dan kemudian unduh file itu dan periksa versi yang saat ini diinstal.

Membangun solusi yang lebih maju untuk itu akan menerapkan layanan web yang tepat dan memiliki panggilan api saat peluncuran yang dapat mengembalikan beberapa json, yaitu http://api.some-place.com/versionCheck:

{
    "current_version": "3.1.4"
}
grego
sumber
Anda berada di jalur yang benar - jangan mengunduh file, hanya untuk mendapatkan versinya. Saya hanya ingin menyebutkan bahwa saya tidak akan merekomendasikan membuat file teks MANUAL - terlalu mudah untuk memilikinya tidak cocok dengan file apk yang sebenarnya. Alih-alih, tulis skrip (yang menggunakan salah satu jawaban lain) untuk melihat ke dalam apk untuk melihat apa versinya, menyimpannya dalam file atau database, untuk diambil dengan cara yang Anda diskusikan.
ToolmakerSteve
Ya dalam skenario ini masalahnya bukan bahwa itu harus cocok dengan APK sama sekali, hanya saja nomor versi terbaru adalah suatu tempat yang dapat diakses publik.
grego
1
    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();
    }
Wayne Len
sumber
10
Ini bukan jawaban untuk pertanyaan itu. Ini adalah kode yang, di dalam aplikasi yang berjalan, mendapatkan beberapa info versi, dan menampilkannya. Pertanyaannya adalah bagaimana cara mendapatkan informasi ini dari file APK, tanpa menginstal aplikasi .
ToolmakerSteve
Ini hanya untuk aplikasi yang sudah diinstal bukan untuk file .apk.
Rhusfer