Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/221.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在不安装apk的情况下获取Android.apk文件VersionName或VersionCode_Android_Android Manifest_Apk - Fatal编程技术网

在不安装apk的情况下获取Android.apk文件VersionName或VersionCode

在不安装apk的情况下获取Android.apk文件VersionName或VersionCode,android,android-manifest,apk,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" > 例如,在设备上安装后,我想检查IIS服务上是否上

如何在下载AndroidManifest.xml文件后,在不安装它的情况下,以编程方式从该文件中获取apk的版本代码或版本名

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


例如,在设备上安装后,我想检查IIS服务上是否上载了新版本,如果不是新版本,我就不想安装它。

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

这个主题是我得到答案的关键(我还添加了我的Ribo代码版本):

此外,下面是我编写的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: 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;
}
版本比较(在前面的代码段中被视为SystemPackageTools.compareVersions) 注意:此代码的灵感来自以下主题:

/**
*比较两个版本字符串,判断第一个是更高、相等还是更低
*资料来源:https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java
* 
*@param ver1参考版本
*@param ver2比较版本
* 
*@如果ver1较高,则返回1;如果相等,则返回0;如果ver1较低,则返回-1
*/
公共静态最终整数比较(字符串ver1,字符串ver2){
字符串[]vals1=ver1.split(“\\”);
字符串[]vals2=ver2.split(“\\”);
int i=0;

而(i以下内容在命令行中对我有效:

aapt dump badging myapp.apk

注意:aapt.exe位于SDK的
构建工具
子文件夹中。例如:

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

对于升级场景,另一种方法可能是使用一个提供当前版本号的web服务并进行检查,而不是下载整个apk来检查其版本。这将节省一些带宽,提高性能(如果大部分时间不需要整个apk,则下载速度比apk快得多),而且实现起来更简单

以最简单的形式,您可以在服务器上有一个简单的文本文件…
http://some-place.com/current-app-version.txt

在该文本文件的内部有如下内容

3.1.4
然后下载该文件并对照当前安装的版本进行检查

为此构建一个更高级的解决方案将是实现一个适当的web服务,并在启动时有一个api调用,该调用可能返回一些json,即
http://api.some-place.com/versionCheck

{
    "current_version": "3.1.4"
}

如果您使用的是Android Studio 2.2及以上版本,则在Android Studio中使用Build→ 分析APK,然后选择AndroidManifest.xml文件。

目前,可以按如下方式进行操作

$ANDROID_HOME/build-tools/28.0.3/aapt dump badging /<path to>/<app name>.apk
$ANDROID_HOME/build tools/28.0.3/aapt dump-bading/.apk
一般来说,它将是:

$ANDROID_HOME/build-tools/<version_of_build_tools>/aapt dump badging /<path to>/<app name>.apk
$ANDROID_HOME/build tools//aapt dump-bading/.apk
这通过只返回版本号来回答问题。 然而

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

为了进行比较,您需要确定已安装(如果已安装)的应用程序的名称和版本号。如果rom中尚未包含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
正如有人问不使用aapt怎么做。 也可以使用apktool和一些脚本来提取apk信息。这种方法速度较慢,在安卓系统中并不简单,但只要有可用的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
!/bin/sh
APK=/path/to/your.APK
TMPDIR=/tmp/apktool
rm-f-R$TMPDIR
apktool d-q-f-s——强制清单-o$TMPDIR$APK
APK=$(基本名称$APK)
版本=$(目录$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/Kotlin:

var ver: String = packageManager.getPackageInfo(packageName, 0).versionName
使用该工具现在是
cmdline工具的一部分

$ apkanalyzer manifest version-code my_app.apk
1
$ apkanalyzer manifest version-name my_app.apk
1.2.3.4

顺便说一句,我希望没有人认为一个好的解决方案是下载该文件,然后检查是否需要它——这是第一句话所建议的。大概你会想要在你的服务器上运行的代码,并用可用的版本号响应。
/aapt d badding release.apk | grep-Po”(?aapt将花费大约
2.6M
磁盘空间,您还可以编写一个解析器,使用
AXMLResource
解析apk文件,这将花费大约
52k
。请参阅如何在不安装应用程序的情况下读取
apk
内容?@patrickcho这确实有效。您不需要安装它。您只需要一个apk设备存储器上的某个位置,并向软件包管理器提供指向该位置的路径。它确实会返回软件包信息。这是最好的答案。很好,这应该标记为正确答案,作为信息,
aapt
位于sdk中的build tools/XX中。我在“/build tools/21.1.2”下找到了它在Mac上使用Xamarin,它位于
~/Library/Developer/Xamarin/android sdk macosx/build tools/{version}
我使用此命令时打印的
platformBuildVersionName
是什么,为什么为空?您可以创建bat文件
aapt dump标签%1 pause
拖放任何APT这不是问题的答案。这是在运行的应用程序中获取一些版本信息并显示它的代码。问题是如何获取此信息来自APK文件,而不安装应用程序。这仅适用于已安装的应用程序,而不适用于.APK文件。您的做法是正确的-不应该下载该文件,只是为了获取其版本。我只想提及
#/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
#!/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
var ver: String = packageManager.getPackageInfo(packageName, 0).versionName
$ apkanalyzer manifest version-code my_app.apk
1
$ apkanalyzer manifest version-name my_app.apk
1.2.3.4