一:场景分析
首先来看一个糟糕的应用添加页面!
只有亲自操作之后,才发现操作是有多么繁琐,用户体验极差。更重要的是手动
输入不但浪费了管理员的宝贵时间,而且手动输入的准确性很难保证。
需要手动输入apk的大小,排列序号手动输入,这用户体验简直是坑人!应该程序计算。
其实上传apk文件的同时,可以解析apk文件,从apk中可以拿到版本号码,版本
名称,包名,权限, 支持的android平台最低版本号,支持的SDK版,建议的SDK版
本,应用程序名,程序的图标等一系列信息。
应用类型表示:是公司应用,还是其他应用。也是不需要手动输入的,因为通过
apk的包名就可以区分了!如果包名以"com.XX.A"开头,就表示是公司A的应用,反
之,就表示其他第三方的应用!
apk名称也是不需要输入的,因为通过apk的applicationLable应用程序名就可以
获取。
下图为简化之后的操作:
下面是java解析apk的工具类:
测试输出信息如下:
java解析apk的工具类:
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import com.saving.platform.util.PropertiesUtil;
import com.saving.platform.util.apk.bean.ApkInfo;
import com.saving.platform.util.apk.bean.ImpliedFeature;
/**
* @author lyl
* @version 1.0
*/
public class ApkUtil {
public static final String VERSION_CODE = "versionCode";
public static final String VERSION_NAME = "versionName";
public static final String SDK_VERSION = "sdkVersion";
public static final String TARGET_SDK_VERSION = "targetSdkVersion";
public static final String USES_PERMISSION = "uses-permission";
public static final String APPLICATION_LABEL = "application-label";
public static final String APPLICATION_ICON = "application-icon";
public static final String USES_FEATURE = "uses-feature";
public static final String USES_IMPLIED_FEATURE = "uses-implied-feature";
public static final String SUPPORTS_SCREENS = "supports-screens";
public static final String SUPPORTS_ANY_DENSITY = "supports-any-density";
public static final String DENSITIES = "densities";
public static final String PACKAGE = "package";
public static final String APPLICATION = "application:";
public static final String LAUNCHABLE_ACTIVITY = "launchable-activity";
private ProcessBuilder mBuilder;
private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";
private static final String FEATURE_SPLIT_REGEX = "(:')|(',')|'";
/**
* aapt所在的目录。
*/
private String mAaptPath = "apk/aapt";
public ApkUtil() {
mBuilder = new ProcessBuilder();
mBuilder.redirectErrorStream(true);
}
/**
* 返回一个apk程序的信息。
*
* @param apkPath
* apk的路径。
* @return apkInfo 一个Apk的信息。
*/
public ApkInfo getApkInfo(String apkPath) throws Exception {
String aaptDir = PropertiesUtil.getProperty("sysconfig.properties", "aaptDir");
aaptDir = aaptDir +"/aapt";
Process process = mBuilder.command(aaptDir, "d", "badging", apkPath).start();
InputStream is = null;
is = process.getInputStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(is, "utf8"));
String tmp = br.readLine();
try {
if (tmp == null || !tmp.startsWith("package")) {
throw new Exception("参数不正确,无法正常解析APK包。输出结果为:\n" + tmp + "...");
}
ApkInfo apkInfo = new ApkInfo();
do {
setApkInfoProperty(apkInfo, tmp);
} while ((tmp = br.readLine()) != null);
return apkInfo;
} catch (Exception e) {
throw e;
} finally {
process.destroy();
closeIO(is);
closeIO(br);
}
}
/**
* 设置APK的属性信息。
*
* @param apkInfo
* @param source
*/
private void setApkInfoProperty(ApkInfo apkInfo, String source) {
if (source.startsWith(PACKAGE)) {
splitPackageInfo(apkInfo, source);
} else if(source.startsWith(LAUNCHABLE_ACTIVITY)){
apkInfo.setLaunchableActivity(getPropertyInQuote(source));
} else if (source.startsWith(SDK_VERSION)) {
apkInfo.setSdkVersion(getPropertyInQuote(source));
} else if (source.startsWith(TARGET_SDK_VERSION)) {
apkInfo.setTargetSdkVersion(getPropertyInQuote(source));
} else if (source.startsWith(USES_PERMISSION)) {
apkInfo.addToUsesPermissions(getPropertyInQuote(source));
} else if (source.startsWith(APPLICATION_LABEL)) {
apkInfo.setApplicationLable(getPropertyInQuote(source));
} else if (source.startsWith(APPLICATION_ICON)) {
apkInfo.addToApplicationIcons(getKeyBeforeColon(source),
getPropertyInQuote(source));
} else if (source.startsWith(APPLICATION)) {
String[] rs = source.split("( icon=')|'");
apkInfo.setApplicationIcon(rs[rs.length - 1]);
} else if (source.startsWith(USES_FEATURE)) {
apkInfo.addToFeatures(getPropertyInQuote(source));
} else if (source.startsWith(USES_IMPLIED_FEATURE)) {
apkInfo.addToImpliedFeatures(getFeature(source));
} else {
// System.out.println(source);
}
}
private ImpliedFeature getFeature(String source) {
String[] result = source.split(FEATURE_SPLIT_REGEX);
ImpliedFeature impliedFeature = new ImpliedFeature(result[1], result[2]);
return impliedFeature;
}
/**
* 返回出格式为name: 'value'中的value内容。
*
* @param source
* @return
*/
private String getPropertyInQuote(String source) {
int index = source.indexOf("'") + 1;
return source.substring(index, source.indexOf('\'', index));
}
/**
* 返回冒号前的属性名称
*
* @param source
* @return
*/
private String getKeyBeforeColon(String source) {
return source.substring(0, source.indexOf(':'));
}
/**
* 分离出包名、版本等信息。
*
* @param apkInfo
* @param packageSource
*/
private void splitPackageInfo(ApkInfo apkInfo, String packageSource) {
String[] packageInfo = packageSource.split(SPLIT_REGEX);
apkInfo.setPackageName(packageInfo[2]);
apkInfo.setVersionCode(packageInfo[4]);
apkInfo.setVersionName(packageInfo[6]);
}
/**
* 释放资源。
*
* @param c
* 将关闭的资源
*/
private final void closeIO(Closeable c) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
try {
String demo = "D:/test.apk";
// if (args.length > 0) {
// if(args[0].equals("-version") || args[0].equals("-v")){
// System.out.println("ApkUtil -by Geek_Soledad");
// System.out.println("Version:" + Version.getVersion());
// return;
// }
// demo = args[0];
// }
ApkInfo apkInfo = new ApkUtil().getApkInfo(demo);
System.out.println(apkInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getmAaptPath() {
return mAaptPath;
}
public void setmAaptPath(String mAaptPath) {
this.mAaptPath = mAaptPath;
}
}
获取apk文件的大小:
1:从apk的文件流,转化为byte数组
/**
* 数据流转byte数组
*
* @param fileInputStream
* @return
*/
public static byte[] getByteByInputStream(InputStream fileInputStream) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read = 0;
byte[] bytes = new byte[1024];
try {
while ((read = fileInputStream.read(bytes)) != -1) {
if (baos.size() > 16 * 1024 * 1024 - 1) {
throw new RuntimeException("file size is larger than 16M");
}
baos.write(bytes, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] array0 = baos.toByteArray();
return array0;
}
2:将byte字节转化为KB或者MB
public static String bytes2kb(long bytes) {
BigDecimal filesize = new BigDecimal(bytes);
BigDecimal megabyte = new BigDecimal(1024 * 1024);
float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP)
.floatValue();
// if (returnValue > 1)
return (returnValue + "MB");
// BigDecimal kilobyte = new BigDecimal(1024);
// returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP)
// .floatValue();
// return (returnValue + "KB");
}