Java上传apk文件并获取版本号
记录一个小优化。
之前做的apk版本更新,是在网页后台中上传apk文件,然后手动输入apk版本号以及更新内容。虽然在填写版本号时做了验证,只能输入数字和小数点,并且第一位不能为小数点等等限制,同时还有一个判断,查询数据库中是否有相同版本的apk。
虽然看起来差不多,该限制的都限制的,该判断的也判断了,但是总觉得好像不太妥。如果我上传的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
下载地址
一旦下载完成,您可以将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,我只是个代码搬运渣渣大佬的 原文链接
还木有评论哦,快来抢沙发吧~