programing

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

telecom 2023. 9. 12. 19:51
반응형

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

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

명령 줄에서 다음이 나를 위해 작동했습니다.

aapt dump badging myapp.apk

참고: 앱.exe는 a에서 발견됩니다.build-toolsSDK의 하위 폴더입니다.예를 들어,

<sdk_path>/build-tools/23.0.2/aapt.exe
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();

Android Studio 버전 2.2 이상을 사용하는 경우 Android Studio에서 →를 사용한 후 AndroidManifest.xml 파일을 선택합니다.

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

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

앞에서 설명한 것처럼 apk를 다운로드하거나 설치하기 전에 서버에 설치된 apk보다 최신인지 확인하는 것이 목적입니다.가장 쉬운 방법은 서버에서 호스팅되는 apk의 파일 이름에 버전 번호를 포함하는 것입니다.myapp_1.01.apk

(설치된 경우) 이미 설치된 앱의 이름과 버전 번호를 설정해야 비교가 가능합니다.root에 아직 포함되지 않은 경우 rooted device 또는 aapt binary and 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

어떻게 하면 앱을 안 쓰고 할 수 있느냐고 물었더니.apk 도구와 약간의 스크립팅으로 apk 정보를 추출하는 것도 가능합니다.이 방법은 안드로이드에서는 느리고 간단하지 않지만 apktool 설정이 작동하는 한 window/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

서버의 드롭 폴더도 고려합니다.앱을 업로드하면 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

현재 이 작업은 다음과 같이 수행할 수 있습니다.

$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

이제 이진 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: 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;
}

버전 비교(System Package로 표시Tools.compareVersions in the frear snippet) 참고: 코드는 다음 항목에서 영감을 받았습니다: 자바에서 버전 문자열을 비교하는 효율적인 방법

/**
 * Compare 2 version strings and tell if the first is higher, equal or lower
 * Source: https://stackoverflow.com/questions/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;
}

도움이 되었으면 좋겠습니다.

  1. .apk 파일을 Android Studio로 끕니다.

  2. 그런 다음 AndroidManifest.xml 파일을 두 번 클릭합니다.

  3. 버전 코드 및 버전 이름 참조

enter image description here

업그레이드 시나리오의 경우, 현재 버전 번호를 전달하는 웹 서비스를 통해 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"
}

그것을 사용하는 것은 이제cmdline-tools:

$ apkanalyzer manifest version-code my_app.apk
1
$ apkanalyzer manifest version-name my_app.apk
1.2.3.4
    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();
    }

버전 코드와 버전 이름을 식별하는 더 간단한 방법이 있습니다.apk 분석기용 최신 apk를 Android studio로 드래그 앤 드롭하여 주십시오. 여기서는 아래와 같이 버전 코드와 버전 이름을 교차 확인할 수 있습니다.

코틀린:

var ver: String = packageManager.getPackageInfo(packageName, 0).versionName

언급URL : https://stackoverflow.com/questions/13469147/get-android-apk-file-versionname-or-versioncode-without-installing-apk

반응형