获取App版本号时,使用Java上传apk文件。

访客 187 0

Java上传apk文件并获取版本号

记录一个小优化。

之前做的apk版本更新,是在网页后台中上传apk文件,然后手动输入apk版本号以及更新内容。虽然在填写版本号时做了验证,只能输入数字和小数点,并且第一位不能为小数点等等限制,同时还有一个判断,查询数据库中是否有相同版本的apk。
获取App版本号时,使用Java上传apk文件。-第1张图片-谷歌商店上架
虽然看起来差不多,该限制的都限制的,该判断的也判断了,但是总觉得好像不太妥。如果我上传的apk版本是1.5,而我在上传手动输入版本号时记错了,写了个1.6。那么用户更新的是名为1.6版本的apk,安装时却发现应用版本是1.5的。虽然听起来没什么太大的影响,但这确实是个隐患。

那么,我们是否可以在上传apk时就获取到apk的版本信息呢?对于做过Android开发的朋友来说,应该知道apk在打包前版本等信息是写在AndroidManifest.xml中的。因此,我们只需要解压apk,并找到这个文件,就能读取其中的字段和属性了。

现在,我将隆重介绍今天的特邀嘉宾——AXMLPrinter2

以下是对该段话的改写: 官方介绍:AXMLPrinter2.jar是一款强大的工具,用于分析APK文件并提取其中的包名、版本号和图标。它能够将安卓编译过的二进制XML文件反编译为明文输出,并保存下来。作为APK反编译修改过程中必备的工具之一,AXMLPrinter2可以帮助您查看apk安装包的权限、名称等信息,只需对androidmanifest.xml进行反编译即可轻松实现。其快速且易于使用的特点使得.XML文件能够顺利地被重新编译出来。”

在文章末尾我会附上AXMLPrinter2下载地址
获取App版本号时,使用Java上传apk文件。-第2张图片-谷歌商店上架

一旦下载完成,您可以将jar包添加到项目中。

接下来,我们将创建一个名为ApkUtil的工具类,并将方法代码放在其中。首先,我们需要对apk进行解压操作,然后找到其中的AndroidManifest.xml文件。

/**     * 获取apk信息     *     * @param apkPath     * @return     */    public static String[] getApkInfo(String apkPath) throws Exception {        // apk信息的返回结果        final String[] apkResult = new String[3];        ZipFile zipFile = null;        try {            // 获得一个解压文件对象            zipFile = new ZipFile(apkPath);            // 将解压文件对象转列举对象            final Enumeration enumeration = zipFile.entries();            ZipEntry zipEntry = null;            // 遍历列举对象元素            while (enumeration.hasMoreElements()) {                // 获得一个解压条目对象                zipEntry = (ZipEntry) enumeration.nextElement();                if (zipEntry.isDirectory()) {                 } else {                    // 获得名为AndroidManifest.xml的文件                    if ("AndroidManifest.xml".equalsIgnoreCase(zipEntry.getName())) {

找到这个文件之后,遍历里面的内容,找到版本号等相关信息

// 遍历文件中的内容
while (true) {
    final int type = parser.next();
    if (type == XmlPullParser.END_DOCUMENT) {
        break;
    }
    switch (type) {
        // 满足条件开始遍历内容提取需要的信息
        case XmlPullParser.START_TAG: {
            for (int i = 0; i != parser.getAttributeCount(); ++i) {
                if (package.equals(parser.getAttributeName(i))) { // 包名
                    apkResult[0] = parser.getAttributeValue(i);
                }
            }
            break;
        }
    }
} 

以下是完整的ApkUtil:

import android.content.res.AXmlResourceParser;import android.util.TypedValue;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.xmlpull.v1.XmlPullParser; import java.io.IOException;import java.util.Enumeration;import java.util.zip.ZipEntry;import java.util.zip.ZipFile;public class ApkUtil {    private static final Logger LOGGER = LoggerFactory.getLogger(ApkUtil.class);     private static final float RADIX_MULTS[] = {0.00390625F, 3.051758E-005F, 1.192093E-007F, 4.656613E-010F};     private static final String DIMENSION_UNITS[] = {"px", "dip", "sp", "pt", "in", "mm", "", ""};     private static final String FRACTION_UNITS[] = {"%", "%p", "", "", "", "", "", ""};     /**     * 获取apk信息     *     * @param apkPath     * @return     */    public static String[] getApkInfo(String apkPath) throws Exception {        // apk信息的返回结果        final String[] apkResult = new String[3];        ZipFile zipFile = null;        try {            // 获得一个解压文件对象            zipFile = new ZipFile(apkPath);            // 将解压文件对象转列举对象            final Enumeration enumeration = zipFile.entries();            ZipEntry zipEntry = null;            // 遍历列举对象元素            while (enumeration.hasMoreElements()) {                // 获得一个解压条目对象                zipEntry = (ZipEntry) enumeration.nextElement();                if (zipEntry.isDirectory()) {                 } else {                    // 获得名为AndroidManifest.xml的文件                    if ("AndroidManifest.xml".equalsIgnoreCase(zipEntry.getName())) {                        final AXmlResourceParser parser = new AXmlResourceParser();                        parser.open(zipFile.getInputStream(zipEntry));                        // 遍历文件里的内容                        while (true) {                            final int type = parser.next();                            if (type == XmlPullParser.END_DOCUMENT) {                                break;                            }                            switch (type) {                                // 满足条件开始遍历内容提取需要的信息                                case XmlPullParser.START_TAG: {                                    for (int i = 0; i != parser.getAttributeCount(); ++i) {                                        if ("package".equals(parser.getAttributeName(i))) {                                            apkResult[0] = ApkUtil.getAttributeValue(parser, i);                                        } else if ("versionCode".equals(parser.getAttributeName(i))) {                                            apkResult[1] = ApkUtil.getAttributeValue(parser, i);                                        } else if ("versionName".equals(parser.getAttributeName(i))) {                                            apkResult[2] = ApkUtil.getAttributeValue(parser, i);                                        }                                     }                                }                            }                        }                    }                 }            }        } finally {            if (zipFile != null) {                try {                    zipFile.close();                } catch (final IOException e) {                    LOGGER.error("Zipfile close fail.", e);                }            }        }         return apkResult;    }     private static String getAttributeValue(AXmlResourceParser parser, int index) {        final int type = parser.getAttributeValueType(index);        final int data = parser.getAttributeValueData(index);        if (type == TypedValue.TYPE_STRING) {            return parser.getAttributeValue(index);        }        if (type == TypedValue.TYPE_ATTRIBUTE) {            return String.format("?%s%08X", ApkUtil.getPackage(data), data);        }        if (type == TypedValue.TYPE_REFERENCE) {            return String.format("@%s%08X", ApkUtil.getPackage(data), data);        }        if (type == TypedValue.TYPE_FLOAT) {            return String.valueOf(Float.intBitsToFloat(data));        }        if (type == TypedValue.TYPE_INT_HEX) {            return String.format("0x%08X", data);        }        if (type == TypedValue.TYPE_INT_BOOLEAN) {            return data != 0 ? "true" : "false";        }        if (type == TypedValue.TYPE_DIMENSION) {            return Float.toString(ApkUtil.complexToFloat(data))                    + ApkUtil.DIMENSION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];        }        if (type == TypedValue.TYPE_FRACTION) {            return Float.toString(ApkUtil.complexToFloat(data))                    + ApkUtil.FRACTION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];        }        if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {            return String.format("#%08X", data);        }        if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) {            return String.valueOf(data);        }        return String.format("<0x%X, type 0x%02X>", data, type);    }     private static String getPackage(int id) {        if (id >>> 24 == 1) {            return "android:";        }        return "";    }     public static float complexToFloat(int complex) {        return (complex & 0xFFFFFF00) * ApkUtil.RADIX_MULTS[complex >> 4 & 3];    }}

给大佬们呈上AXMLPrinter2.jar 下载地址

最后感谢 Mr_EvanChen大佬 写的 ApkUtil,我只是个代码搬运渣渣

大佬的 原文链接

标签: 文件 版本号 对象 版本

发表评论 (已有0条评论)

还木有评论哦,快来抢沙发吧~