APK yüklemeden Android .apk dosyasını VersionName veya VersionCode'u indirin


184

AndroidManifest.xml dosyasından indirdikten sonra ve yüklemeden programlı olarak apk'nin sürüm kodunu veya sürüm adını nasıl alabilirim?

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

Örneğin, IIS hizmetime yeni bir sürümün yüklenip yüklenmediğini kontrol etmek istiyorum, cihaza yükledikten sonra, yeni bir sürüm değilse yüklemek istemiyorum.



BTW, umarım kimse iyi bir çözümün dosyayı indirmek olduğunu düşünür ve sonra gerekli olup olmadığını kontrol eder - İlk cümlenin önerdiği şey budur. Muhtemelen bunun yerine sunucunuzda çalışan ve mevcut sürüm numarasıyla yanıt veren bir kod istersiniz .
ToolmakerSteve

./aapt d badging release.apk | grep -Po "(?<=\sversion(Code|Name)=')([0-9.]+)"
Kris Roofe

aapt 2.6Mdisk alanı hakkında mal olacak, ayrıca AXMLResourcesadece maliyet olacak apk dosyasını ayrıştırmak için bir ayrıştırıcı yazabilirsiniz 52k. Belirtilmemiş ad alanı
dosyasına

Yanıtlar:


417

Aşağıdaki komut satırından benim için çalıştı:

aapt dump badging myapp.apk

NOT: aapt.exe, SDK'nın bir build-toolsalt klasöründe bulunur. Örneğin:

<sdk_path>/build-tools/23.0.2/aapt.exe

26
Cezası Works, bu doğru cevap olarak işaretlenmesi gereken, bilgi için aaptise XX / birikmesi araçlar sdk.
Quentin Klein

8
Bunu "<sdk_path> /build-tools/21.1.2" altında buldum
gmuhammad

1
Bir Mac'te Xamarin kullanarak, oldu~/Library/Developer/Xamarin/android-sdk-macosx/build-tools/{version}
cscott530

Ne platformBuildVersionNameben bu komutu kullandığınızda baskılı alır ve neden boş?
Sevastyan Savanyuk

aapt dump badging %1 pauseherhangi bir apk sürüklemek için yarasa dosyası oluşturabilirsiniz
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();

5
uygulamayı yüklemedenapk içeriği nasıl okuyabilirim ? @PatrickCho
talha06

2
Bu gerçekten işe yarıyor. Ve yüklemenize gerek yok. Cihazınızın depolama alanında bir yerde bir apk'niz var ve bunun yolunu paket yöneticisine sağlıyor. Gerçekten paket bilgilerini iade edecektir.
Daniel Zolnai

45

Android Studio 2.2 ve sonraki sürümlerini kullanıyorsanız , Android Studio'daBuild Analyze APKseçeneğini kullanın ve ardından AndroidManifest.xml dosyasını seçin.


7
OP nasıl edileceğini sorduprogrammatically
forresthopkinsa

3
Çünkü böyle bir aracın Android Studio'da oluşturulduğunu bilmiyordu. Ayrıca apk yüklemeden istedi .
vovahost

3
Elbette bunu bilmiyordu, çünkü bu soru sorulduğunda Android Studio yoktu. Ayrıca, bile, bu onun sorunu çözmez - o onun cihaz istiyor programlı o sorunuzu belirtildiği gibi, onun IIS sunucusundan güncellemeleri kontrol edin. Patrick Cho'nun cevabı, kurulum yapmadan programlı olarak nasıl yapılacağını açıklıyor.
forresthopkinsa

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

Bu, sonuç olarak yalnızca sürüm numarasını döndürerek soruyu cevaplar. Ancak......

Daha önce belirtildiği gibi, sunucudaki apk'nin indirmeye veya yüklemeye çalışmadan ÖNCE yüklü olandan daha yeni olup olmadığını bulmak olmalıdır. Bunu yapmanın en kolay yolu, sunucuda barındırılan apk'nin dosya adındaki sürüm numarasını içerir.myapp_1.01.apk

Karşılaştırma yapmak için önceden yüklenmiş uygulamaların (yüklüyse) adını ve sürüm numarasını belirlemeniz gerekir. Köklü bir cihaza veya rom'a henüz dahil edilmemişlerse, aapt ikili ve meşgul kutusunu kurma araçlarına ihtiyacınız olacaktır.

Bu komut dosyası, sunucunuzdaki uygulamaların listesini alır ve yüklü uygulamalarla karşılaştırır. Sonuç, yükseltme / yükleme için işaretlenen bir listedir.

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

Birinin aapt kullanmadan nasıl yapılacağını sorduğu gibi. Ayrıca apktool ve biraz komut dosyasıyla apk bilgilerini ayıklamak da mümkündür. Bu şekilde android daha yavaş ve basit değil, ancak çalışan apktool kurulumuna sahip olduğunuz sürece windows / mac veya linux üzerinde çalışacaktır.

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

Ayrıca sunucunuzdaki bir açılan klasörü de göz önünde bulundurun. Apks yükleyin ve bir cron görevi yeniden adlandırır ve güncelleme klasörünüze taşır.

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

8

Şu anda, bu aşağıdaki gibi yapılabilir

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

Genel olarak:

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

5

Artık bir APK dosyasının sürümünü ikili XML verilerinden başarıyla alabilirim.

Bu konu benim cevabımın anahtarını aldım (Ribo'nun kodunun versiyonunu da ekledim): Bir .apk paketi içinde AndroidManifest.xml dosyasını ayrıştırma

Ayrıca, özellikle sürümü getirmek için yazdığım XML ayrıştırma kodu:

XML Ayrıştırma

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

Sürüm Karşılaştırması (önceki snippet'te SystemPackageTools.compareVersions olarak görülür) NOT: Bu kod aşağıdaki konudan esinlenmiştir: Java'daki sürüm dizelerini karşılaştırmanın etkili yolu

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

Umarım bu yardımcı olur.


Yeni Gradle veya Android Studio sürümüne geçtiniz mi? Bu hala çalışıyor mu? Robio kodu artık XML'i açmak için çalışmıyor.
GR Envoy

4

Yükseltme senaryosu için özellikle alternatif bir yaklaşım, geçerli sürüm numarasını sağlayan bir web hizmetine sahip olmak ve tüm sürümünü indirmek yerine sadece sürümünü kontrol etmek için kontrol etmek olabilir. Biraz bant genişliği kaydeder, biraz daha performans gösterir (tüm apk çoğu zaman gerekli değilse bir apk'den çok daha hızlı) ve uygulanması çok daha basittir.

En basit biçimde, sunucunuzda basit bir metin dosyası olabilir ... http://some-place.com/current-app-version.txt

Bu metin dosyasının içinde şöyle bir şey var:

3.1.4

ve sonra o dosyayı indirin ve şu anda yüklü olan sürümü kontrol edin.

Bunun için daha gelişmiş bir çözüm oluşturmak, uygun bir web hizmeti uygulamak ve açılışta bazı jsonları döndürebilecek bir api çağrısı yapmak olacaktır, yani http://api.some-place.com/versionCheck:

{
    "current_version": "3.1.4"
}

Doğru yoldasınız - sadece sürümünü indirmek için dosya indirmemelisiniz. Sadece metin dosyasını manuel olarak oluşturmayı önermediğimi belirtmek istiyorum - gerçek apk dosyasıyla eşleşmeyecek kadar kolay. Bunun yerine, sürümünün ne olduğunu görmek için apk'nin içine bakmak için bir komut dosyası (diğer cevaplardan birini kullanan) yazın, bunu dosya veya veritabanında saklayarak tartıştığınız yollarla alın.
ToolmakerSteve

Evet, bu senaryoda durum, APK ile hiç eşleşmesi gerekmiyor, sadece en son sürüm numarasının herkes tarafından erişilebilir bir yerde olması.
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();
    }

10
Bu sorunun cevabı değil. Bu, çalışan bir uygulamanın içinde bazı sürüm bilgilerini alan ve görüntüleyen koddur. Soru, bu bilgileri uygulamayı yüklemeden bir APK dosyasından nasıl alacağınızdır .
ToolmakerSteve

Bu yalnızca .apk dosyası için yüklü olmayan uygulama içindir.
Rhusfer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.