现在的位置: 首页 > 综合 > 正文

从Android-Apk文件解析,谈用户体验!

2016年01月30日 ⁄ 综合 ⁄ 共 6119字 ⁄ 字号 评论关闭

一:场景分析


  首先来看一个糟糕的应用添加页面!

          

          只有亲自操作之后,才发现操作是有多么繁琐,用户体验极差。更重要的是手动

输入不但浪费了管理员的宝贵时间,而且手动输入的准确性很难保证。

          需要手动输入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");
}



抱歉!评论已关闭.