获取Android .apk文件VersionName或VersionCode没有安装apk

Big*_*ild 171 android android-manifest apk

如何在下载后从AndroidManifest.xml文件以编程方式获取apk的版本代码或版本名称,而无需安装它.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xxx.xx.xxx"
    android:versionCode="1"
    android:versionName="1.1" >
Run Code Online (Sandbox Code Playgroud)

例如,我想检查是否在我的IIS服务上安装了新版本,然后将其安装在设备上,如果不是新版本我不想安装它.

Sil*_*ria 395

以下是从命令行为我工作的:

aapt dump badging myapp.apk
Run Code Online (Sandbox Code Playgroud)

注意:aapt.exe位于build-toolsSDK 的子文件夹中.例如:

<sdk_path>/build-tools/23.0.2/aapt.exe
Run Code Online (Sandbox Code Playgroud)

  • 工作正常,这应该被标记为正确答案,对于信息,`aapt`在sdk中的*build-tools/XX*中. (25认同)
  • 我在"<sdk_path> /build-tools/21.1.2"下找到了它 (8认同)

小智 81

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();
Run Code Online (Sandbox Code Playgroud)

  • 如何在不安装**应用程序的情况下阅读`apk`内容**?@PatrickCho (5认同)
  • 这确实有效.而且您不需要安装它.您只需在设备的存储空间中安装apk,并将其路径提供给包管理器.它确实会返回包信息. (2认同)
  • 这是最好的答案 (2认同)

vov*_*ost 43

如果您使用的是Android Studio 2.2及更高版本,则在Android Studio中使用→ 然后选择AndroidManifest.xml文件.Build Analyze APK

  • OP询问如何以"编程方式"获取它 (6认同)
  • 因为他不知道这样的工具是在Android Studio中构建的.他还问了*没有安装apk*. (3认同)
  • 当然他不知道,因为当问到这个问题时Android Studio不存在.此外,即使它确实如此,这也无法解决他的问题 - 他希望他的设备能够*以编程方式*检查来自他的IIS服务器的更新,正如他在问题中所述.Patrick Cho的回答解释了如何在不安装的情况下以编程方式进行. (3认同)

Ser*_*yUr 10

目前,这可以按如下方式完成

$ANDROID_HOME/build-tools/28.0.3/aapt dump badging /<path to>/<app name>.apk
Run Code Online (Sandbox Code Playgroud)

一般来说,它将是:

$ANDROID_HOME/build-tools/<version_of_build_tools>/aapt dump badging /<path to>/<app name>.apk
Run Code Online (Sandbox Code Playgroud)


5p0*_*b0b 7

aapt dump badging test.apk | grep "VersionName" | sed -e "s/.*versionName='//" -e "s/' .*//"
Run Code Online (Sandbox Code Playgroud)

这通过仅返回版本号来回答问题。然而......

如前所述,目标是在尝试下载或安装服务器之前,先确定服务器上的apk是否比已安装的apk更新。最简单的方法是在服务器上托管的apk的文件名中包含版本号,例如myapp_1.01.apk

您需要确定已经安装的应用程序的名称和版本号(如果已安装)以进行比较。如果ROM中尚未包含有root用户的设备,或者需要安装aapt二进制文件和busybox的方法。

该脚本将从您的服务器获取应用程序列表,并与所有已安装的应用程序进行比较。结果是标记为升级/安装的列表。

#/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
Run Code Online (Sandbox Code Playgroud)

正如有人问如何不使用aapt那样做。也可以使用apktool和一些脚本来提取apk信息。这种方法比较慢,并且在android中不简单,但是只要安装了apktool,就可以在Windows / mac或linux上使用。

#!/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
Run Code Online (Sandbox Code Playgroud)

还要考虑服务器上的放置文件夹。将apk上载到其中,然后cron任务会重命名并将其移至更新文件夹。

#!/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
Run Code Online (Sandbox Code Playgroud)


Aks*_*pra 6

  1. 将.apk文件拖入Android Studio

  2. 然后双击 AndroidManifest.xml 文件。

  3. 查看版本代码和版本名称

在此输入图像描述


Mat*_*ieu 5

现在,我可以从其二进制XML数据中成功检索APK文件的版本。

本主题是我找到答案的关键的地方(我还添加了Ribo代码的版本): 如何解析.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: /sf/ask/146846941/#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;
}
Run Code Online (Sandbox Code Playgroud)

版本比较(在先前的片段中作为SystemPackageTools.compareVersions)注:此代码的灵感来自以下主题: 在Java中比较版本字符串的有效方法

/**
 * Compare 2 version strings and tell if the first is higher, equal or lower
 * Source: /sf/ask/469136391/
 * 
 * @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;
}
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助。