APK स्थापित किए बिना Android .apk फ़ाइल वर्जननाम या वर्जनकोड प्राप्त करें


183

मैं इसे डाउनलोड करने के बाद और इसे स्थापित किए बिना प्रोग्रामेटिक रूप से एंड्रॉइड मैनइफेस्ट.एक्सएमएल फ़ाइल के संस्करण कोड या संस्करण का नाम कैसे प्राप्त कर सकता हूं।

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

उदाहरण के लिए, मैं यह देखना चाहता हूं कि क्या कोई नया संस्करण मेरी IIS सेवा पर अपलोड किया गया है, इसे डिवाइस पर स्थापित करने के बाद, यदि यह नया संस्करण नहीं है तो मैं इसे स्थापित नहीं करना चाहता।



BTW, मुझे आशा है कि कोई भी नहीं सोचता है कि एक अच्छा समाधान फ़ाइल को डाउनलोड करना है, और फिर जांचें कि क्या इसकी आवश्यकता है - जो कि पहला वाक्य बताता है। संभवतः आप इसके बजाय अपने सर्वर पर चलने वाले कोड चाहते हैं , और उपलब्ध संस्करण संख्या के साथ प्रतिक्रिया करते हैं।
टूलमेकरसैट

./aapt d badging release.apk | grep -Po "(?<=\sversion(Code|Name)=')([0-9.]+)"
क्रिस रूफ

aapt में 2.6Mडिस्क स्थान के बारे में खर्च होगा , आप एपीके फ़ाइल को पार्स करने के लिए एक पार्सर भी लिख सकते हैं, AXMLResourceजिसके बारे में सिर्फ लागत होगी 52kअघोषित नाम स्थान के साथ जावा पार्स xml का
क्रिश रूपे सेप

जवाबों:


416

कमांड लाइन से मेरे लिए काम करने के बाद:

aapt dump badging myapp.apk

नोट: aapt.exe build-toolsSDK के उप-फ़ोल्डर में पाया जाता है । उदाहरण के लिए:

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

26
ठीक काम करता है, इसे सही उत्तर के रूप में चिह्नित किया जाना चाहिए, जानकारी के लिए, sdk aaptमें बिल्ड-टूल्स / XX में है।
क्वेंटिन क्लेन

8
मुझे यह "<sdk_path> /build-tools/21.1.2" के तहत मिला
gmuhammad

1
एक मैक पर Xamarin का उपयोग करना, यह में था~/Library/Developer/Xamarin/android-sdk-macosx/build-tools/{version}
cscott530

platformBuildVersionNameजब मैं इस कमांड का उपयोग करता हूं तो यह क्या प्रिंट होता है और यह खाली क्यों है?
सेवस्तन सवणुक

आप aapt dump badging %1 pauseकिसी भी
एपीके को

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
मैं एप्लिकेशन इंस्टॉल किए बिनाapk सामग्री कैसे पढ़ सकता हूं ? @PatrickCho
ताल्हा 6

2
यह वास्तव में काम करता है। और आपको इसे स्थापित करने की आवश्यकता नहीं है। आपके पास अपने डिवाइस के स्टोरेज पर बस कहीं एक एपीके है, और पैकेज मैनेजर को इसे पथ की आपूर्ति करें। यह वास्तव में पैकेज की जानकारी लौटाएगा।
डैनियल ज़ोलनई

45

आप उपयोग कर रहे हैं संस्करण 2.2 और इसके बाद के संस्करण के एंड्रॉयड स्टूडियो एंड्रॉयड स्टूडियो उपयोग में तो Build Analyze APKतो AndroidManifest.xml फ़ाइल का चयन करें।


7
ओपी ने पूछा कि इसे कैसे प्राप्त किया जाएprogrammatically
forresthopkinsa

3
क्योंकि उन्हें नहीं पता था कि इस तरह का एक उपकरण एंड्रॉइड स्टूडियो में बनाया गया है। उन्होंने एपीके इंस्टॉल किए बिना भी पूछा ।
वोवहॉस्ट

3
बेशक वह यह नहीं जानता था, क्योंकि यह सवाल पूछे जाने पर Android Studio मौजूद नहीं था। इसके अतिरिक्त, भले ही ऐसा किया हो, इससे उसकी समस्या का समाधान नहीं होता है - वह चाहता है कि उसका डिवाइस अपने IIS सर्वर से अपडेट के लिए प्रोग्रामेटिक रूप से जांच करे, जैसा कि उसने सवाल में कहा था। पैट्रिक चो का जवाब बताता है कि बिना प्रोग्राम किए इसे कैसे इंस्टॉल किया जाए।
forresthopkinsa

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

यह परिणाम के रूप में केवल संस्करण संख्या वापस करके प्रश्न का उत्तर देता है। तथापि......

पहले बताए गए लक्ष्य को यह पता लगाना चाहिए कि सर्वर पर एपीके डाउनलोड किए गए या इसे स्थापित करने के प्रयास में स्थापित एक से नया है या नहीं। ऐसा करने का सबसे आसान तरीका सर्वर पर होस्ट किए गए एपीके के फ़ाइलनाम में संस्करण संख्या शामिल हैmyapp_1.01.apk

तुलना करने के लिए आपको पहले से इंस्टॉल किए गए एप्लिकेशन (यदि यह स्थापित है) का नाम और संस्करण संख्या स्थापित करने की आवश्यकता होगी। यदि आपको पहले से ही रोम में शामिल नहीं किया गया है, तो आपको रूट डिवाइस या aapt बाइनरी और बिजीबॉक्स को स्थापित करने के साधन की आवश्यकता होगी।

यह स्क्रिप्ट आपके सर्वर से ऐप्स की सूची प्राप्त करेगी और किसी भी इंस्टॉल किए गए ऐप से तुलना करेगी। परिणाम उन्नयन / स्थापना के लिए चिह्नित की गई सूची है।

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

जैसा कि किसी ने पूछा कि बिना aapt का उपयोग कैसे करें। Apktool के साथ apk जानकारी और स्क्रिप्टिंग का एक सा निकालने के लिए भी संभव है। यह तरीका धीमा है और एंड्रॉइड में सरल नहीं है, लेकिन जब तक आपके पास काम कर रहे 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

अपने सर्वर पर एक ड्रॉप फ़ोल्डर पर भी विचार करें। इसे अपलोड करें और एक क्रोन कार्य का नाम बदलकर उन्हें आपके अपडेट फ़ोल्डर में ले जाता है।

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

फिलहाल, यह निम्नानुसार किया जा सकता है

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

सामान्य में, यह होगा:

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

5

मैं अब इसके बाइनरी एक्सएमएल डेटा से एपीके फ़ाइल के संस्करण को सफलतापूर्वक पुनर्प्राप्त कर सकता हूं।

यह विषय वह है जहां मुझे मेरे उत्तर की कुंजी मिली (मैंने अपने रिबो के कोड का संस्करण भी जोड़ा): कैसे एक .apk पैकेज के अंदर AndroidManifest.xml फ़ाइल पार्स करें।

इसके अतिरिक्त, यहाँ XML पार्सिंग कोड मैंने लिखा है, विशेष रूप से संस्करण लाने के लिए:

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

संस्करण तुलना (पिछले स्निपेट में SystemPackageTools.compareVersions के रूप में देखा गया) नोट: यह कोड निम्नलिखित विषय से प्रेरित है: जावा में संस्करण स्ट्रिंग की तुलना करने का कुशल तरीका

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

आशा है कि ये आपकी मदद करेगा।


क्या आपने नए ग्रेडल या एंड्रॉइड स्टूडियो में अपग्रेड किया है? क्या यह अभी भी काम करता है? रोबियो कोड अब मेरे लिए XML को डिकम्प्रेस करने का काम नहीं करता है।
जीआर

4

अपग्रेड परिदृश्य के लिए विशेष रूप से एक वैकल्पिक दृष्टिकोण एक वेब सेवा हो सकती है जो वर्तमान संस्करण संख्या को वितरित करती है और यह जांचती है कि इसके संस्करण को जांचने के लिए केवल संपूर्ण एपीके डाउनलोड करने के बजाय। यह कुछ बैंडविड्थ को बचाएगा, थोड़ा अधिक परफ़ॉर्मेंट होगा (एक apk की तुलना में डाउनलोड करने के लिए बहुत तेज़ है अगर पूरे एपीके को अधिकांश समय की आवश्यकता नहीं है) और लागू करने के लिए बहुत सरल है।

सबसे सरल रूप में आप अपने सर्वर पर एक साधारण पाठ फ़ाइल रख सकते हैं ... http://some-place.com/current-app-version.txt

उस पाठ फ़ाइल के अंदर कुछ ऐसा है

3.1.4

और फिर उस फ़ाइल को डाउनलोड करें और वर्तमान में स्थापित संस्करण के खिलाफ जांच करें।

एक और अधिक उन्नत समाधान का निर्माण करना एक उचित वेब सेवा को लागू करना और लॉन्च के समय एक एपि कॉल करना होगा जो कुछ जोन्स लौटा सकता है, अर्थात http://api.some-place.com/versionCheck:

{
    "current_version": "3.1.4"
}

आप सही रास्ते पर हैं - फ़ाइल डाउनलोड नहीं करनी चाहिए, बस उसका संस्करण प्राप्त करना है। मैं केवल यह उल्लेख करना चाहता हूं कि मैं पाठ फ़ाइल को बनाने की अनुशंसा नहीं करूंगा - बहुत आसान है कि यह वास्तविक एपीके फ़ाइल से मेल न खाए। इसके बजाय, एक स्क्रिप्ट लिखें (जो अन्य उत्तरों में से किसी एक का उपयोग करता है) एपीके के अंदर देखने के लिए देखें कि इसका संस्करण क्या है, जिसे फ़ाइल या डेटाबेस में संग्रहीत करते हुए, आपके द्वारा चर्चा किए जाने वाले साधनों द्वारा प्राप्त किया जा सकता है।
टूलमेकर

इस परिदृश्य में हाँ यह मामला नहीं है कि इसे एपीके से मेल खाना चाहिए, बस यह कि नवीनतम संस्करण संख्या कहीं सार्वजनिक रूप से सुलभ है।
ग्रिगो

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
यह सवाल का जवाब नहीं है। यह वह कोड होता है, जो एक रनिंग ऐप के अंदर, कुछ संस्करण जानकारी प्राप्त करता है, और इसे प्रदर्शित करता है। सवाल यह है कि ऐप इंस्टॉल किए बिना , एपीके फ़ाइल से यह जानकारी कैसे प्राप्त की जाए ।
टूलमेकरसेव

यह केवल एक .apk फ़ाइल के लिए पहले से इंस्टॉल किए गए एप्लिकेशन के लिए है।
1919
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.