APK를 설치하지 않고 Android .apk 파일 VersionName 또는 VersionCode 가져 오기


184

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 서비스에 새 버전이 업로드되어 있는지 확인하고 장치에 설치 한 후 새 버전이 아닌 경우 설치하고 싶지 않습니다.



BTW, 나는 아무도 좋은 해결책이 파일을 다운로드하는 것입니다 생각하지 희망 첫 문장이 시사하는 것입니다 어느 -이 필요한지 여부를 확인합니다. 아마도 서버 에서 실행 되고 사용 가능한 버전 번호로 응답하는 코드를 원할 것 입니다.
ToolmakerSteve

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

aapt는 2.6M디스크 공간 에 대한 비용이 들며 , apk 파일을 구문 분석하는 파서를 작성하여 AXMLResource비용이 거의 들지 않습니다 52k. 참조 선언되지 않은 네임 스페이스와 자바 구문 분석 XML
크리스 Roofe에게

답변:


417

다음은 명령 줄에서 나를 위해 일했습니다.

aapt dump badging myapp.apk

참고 : aapt.exe는 build-toolsSDK 의 하위 폴더에 있습니다. 예를 들면 다음과 같습니다.

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

26
잘 작동합니다.이 정보 aapt는 정답으로 표시되어야합니다. 정보 는 SDK의 build-tools / XX 에 있습니다.
Quentin Klein

8
"<sdk_path> /build-tools/21.1.2"에서 찾았습니다
gmuhammad

1
Mac에서 Xamarin을 사용하면~/Library/Developer/Xamarin/android-sdk-macosx/build-tools/{version}
cscott530

뭐가 platformBuildVersionName이 명령을 사용할 때 인쇄되는 이며 왜 비어 있습니까?
Sevastyan Savanyuk

aapt dump badging %1 pauseapk를 끌어다 놓기 위한 bat 파일 을 만들 수 있습니다
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
응용 프로그램 을 설치하지 않고 어떻게 apk내용 읽을 수 있습니까? @PatrickCho
talha06

2
이것은 실제로 작동합니다. 그리고 당신은 그것을 설치할 필요가 없습니다. 장치의 저장소에 APK가 있고 패키지 경로를 패키지 관리자에게 제공하면됩니다. 실제로 패키지 정보를 반환합니다.
Daniel Zolnai

45

Android Studio 버전 2.2 이상 을 사용하는 경우 Android Studio 에서 Build Analyze APK를 사용한 다음 AndroidManifest.xml 파일을 선택하십시오.


7
OP는 그것을 얻는 방법을 물었다programmatically
forresthopkinsa

3
그는 이와 같은 도구가 Android Studio에 내장되어 있다는 것을 몰랐기 때문입니다. 그는 또한 APK를 설치하지 않고 물었다 .
vovahost

3
물론 그는이 질문이있을 때 Android Studio가 존재하지 않았기 때문에 그것을 알지 못했습니다. 또한, 그래도 문제가 해결되지는 않습니다. 문제 에서 언급 한대로 장치에서 IIS 서버의 업데이트 를 프로그래밍 방식으로 확인하기 를 원합니다 . Patrick Cho의 답변은 설치하지 않고 프로그래밍 방식으로 수행하는 방법을 설명합니다.
forresthopkinsa

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

결과적으로 버전 번호 만 반환하여 질문에 대답합니다. 하나......

이전에 언급 한 목표는 서버에있는 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="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 설정을 사용하는 한 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

서버의 드롭 폴더도 고려하십시오. 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

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

이제 이진 XML 데이터에서 APK 파일 버전을 성공적으로 검색 할 수 있습니다.

이 주제는 내 대답의 열쇠를 얻은 곳입니다 (리보 코드 버전도 추가했습니다). .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로 간주) 참고 :이 코드는 다음 주제에서 영감을 얻었습니다. Java에서 버전 문자열을 비교하는 효율적인 방법

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

이게 도움이 되길 바란다.


새로운 Gradle 또는 Android Studio로 업그레이드 했습니까? 여전히 작동합니까? Robio 코드는 더 이상 XML을 압축 해제하지 않습니다.
GR Envoy

4

업그레이드 시나리오의 경우 대체 방법은 현재 버전 번호를 제공하는 웹 서비스를 사용하고 전체 APK를 다운로드하는 대신 버전을 확인하는 것입니다. 그것은 약간의 대역폭을 절약하고, 약간 더 성능이 좋으며 (전체 apk가 거의 필요하지 않으면 apk보다 훨씬 빠릅니다) 구현하기가 훨씬 간단합니다.

가장 간단한 형태로 서버에 간단한 텍스트 파일을 가질 수 있습니다 ... http://some-place.com/current-app-version.txt

그 텍스트 파일 안에는 다음과 같은 것이 있습니다.

3.1.4

그런 다음 해당 파일을 다운로드하고 현재 설치된 버전을 확인하십시오.

그것에 대한 고급 솔루션을 구축하는 것은 적절한 웹 서비스를 구현하고 시작할 때 json을 반환 할 수있는 API 호출을 갖는 것입니다 http://api.some-place.com/versionCheck.

{
    "current_version": "3.1.4"
}

당신은 올바른 길을 가고 있습니다-파일을 다운로드하지 말고, 버전을 얻으십시오. 텍스트 파일을 수동으로 만드는 것은 좋지 않습니다. 실제 apk 파일과 일치하지 않기에는 너무 쉽습니다. 대신, 스크립트 (다른 ​​답변 중 하나를 사용하는)를 작성하여 apk 내부를 살펴보고 파일 또는 데이터베이스에 저장 한 버전을 확인한 후 논의한 방법으로 검색하십시오.
ToolmakerSteve

예,이 시나리오에서는 최신 버전 번호가 공개적으로 액세스 할 수있는 곳이면 APK와 전혀 일치하지 않아도됩니다.
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
이것은 질문에 대한 답변이 아닙니다. 실행중인 앱 내에서 일부 버전 정보를 가져 와서 표시하는 코드입니다. 문제는 app을 설치하지 않고 APK 파일에서이 정보를 얻는 방법 입니다.
ToolmakerSteve

이것은 .apk 파일이 아닌 이미 설치된 응용 프로그램에만 해당됩니다.
Rhusfer
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.