概述:Java解析apk文件,获取apk文件里的包名,版本号,图标文件等;

功能:可以提供给windows和linux平台使用;

原理:利用aapt.exe或者aapt这些anroid平台解析apk文件的工具,借用终端shell调用命令解析输出信息;

代码:

这里贴出一些关键代码,并给出代码注释,如下

 package com.apkutils;

 import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties; /**
* apk工具类。封装了获取Apk信息的方法。
*
* @author @author tony
*
* <p>
* <b>version description</b><br />
* V0.2.1 修改程序名字为从路径中获得。
* </p>
*/
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"; // api ---- os
static Map<String, String> OSVersion = new HashMap<String, String>(); static {
OSVersion.put("3", "1.5");
OSVersion.put("4", "1.6");
OSVersion.put("5", "2.0");
OSVersion.put("6", "2.0.1");
OSVersion.put("7", "2.1");
OSVersion.put("8", "2.2");
OSVersion.put("9", "2.3");
OSVersion.put("10", "2.3.3");
OSVersion.put("11", "3.0");
OSVersion.put("12", "3.1");
OSVersion.put("13", "3.2");
OSVersion.put("14", "4.0");
OSVersion.put("15", "4.0.3");
OSVersion.put("16", "4.1.1");
OSVersion.put("17", "4.2");
OSVersion.put("18", "4.3");
OSVersion.put("19", "4.4");
} private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";
private static final String FEATURE_SPLIT_REGEX = "(:')|(',')|'";
/**
* aapt所在的目录。
*/
private String mAaptPath = "D:\\App\\";//winOS
//private String mAaptPath = ApkUtil.class.getClassLoader().getResource("").getPath();//linux static String[] shellCommand;
static String softName = "";
static {
shellCommand = new String[2];
final String anOSName = System.getProperty("os.name");
if (anOSName.toLowerCase().startsWith("windows")) {
// Windows XP, Vista ...
shellCommand[0] = "cmd";
shellCommand[1] = "/C";
softName = "aapt.exe";
} else {
// Unix, Linux ...
shellCommand[0] = "/bin/sh";
shellCommand[1] = "-c";
softName = "aapt";
}
} /***
* apkPath
*/
static String apkPath = "C:/Users/win7/Desktop/Android/baiduyinyue_49.apk"; /**
* 返回一个apk程序的信息。
*
* @param apkPath
* apk的路径。
* @return apkInfo 一个Apk的信息。
*/
public ApkInfo getApkInfo(String apkPath) throws Exception {
String command = mAaptPath + softName + " d badging \"" + apkPath
+ "\"";
Process process;
try {
process = Runtime.getRuntime().exec(
new String[] {shellCommand[0], shellCommand[1], command});
} catch (IOException e) {
process = null;
throw e;
} ApkInfo apkInfo = null;
if(process != null){
InputStream 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 = new ApkInfo();
do {
setApkInfoProperty(apkInfo, tmp);
} while ((tmp = br.readLine()) != null);
} catch (Exception e) {
throw e;
} finally {
process.destroy();
closeIO(is);
closeIO(br);
}
}
return apkInfo;
} /**
* 设置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));
apkInfo.setMinOSVersion(OSVersion.get(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 { }
try {
apkInfo.setApkFileSize(getFileSizes(new File(apkPath)));
} catch (Exception e) {
e.printStackTrace();
}
} 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 {
ApkInfo apkInfo = new ApkUtil().getApkInfo(apkPath);
System.out.println(apkInfo);
IconUtil.extractFileFromApk(apkPath, apkInfo.getApplicationIcon(),
"D:\\icon.png");
} catch (Exception e) {
e.printStackTrace();
}
} public String getmAaptPath() {
return mAaptPath;
} public void setmAaptPath(String mAaptPath) {
this.mAaptPath = mAaptPath;
} // 取得文件大小
public static long getFileSizes(File f) throws Exception {
long s = 0;
if (f.exists()) {
FileInputStream fis = null;
fis = new FileInputStream(f);
s = fis.available();
} else {
System.out.println("文件不存在");
}
return s;
}
}

上面加上阴影的部分代码,我想基本都是很好理解的,获取当前运行的操作系统类型,适配上相应的指令和软件,这样可以跨平台操作,而不需要修改代码;

获取到相应软件后,对apk文件一行一行的进行解析,将相应的属性存到javaBean中,并将apk文件图片通过流的方式写出到文件系统中,

package com.apkutils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; /**
* 通过ApkInfo 里的applicationIcon从APK里解压出icon图片并存放到磁盘上
* @author @author tony
*/
public class IconUtil { /**
* 从指定的apk文件里获取指定file的流
* @param apkpath
* @param fileName
* @return
*/
public static InputStream extractFileFromApk(String apkpath, String fileName) {
try {
ZipFile zFile = new ZipFile(apkpath);
ZipEntry entry = zFile.getEntry(fileName);
entry.getComment();
entry.getCompressedSize();
entry.getCrc();
entry.isDirectory();
entry.getSize();
entry.getMethod();
InputStream stream = zFile.getInputStream(entry);
return stream;
} catch (IOException e) {
e.printStackTrace();
}
return null;
} public static void extractFileFromApk(String apkpath, String fileName, String outputPath) throws Exception {
InputStream is = extractFileFromApk(apkpath, fileName); File file = new File(outputPath);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), 1024);
byte[] b = new byte[1024];
BufferedInputStream bis = new BufferedInputStream(is, 1024);
while(bis.read(b) != -1){
bos.write(b);
}
bos.flush();
is.close();
bis.close();
bos.close();
}
}

这里没什么好说的,就是用JavaIO中zip的方式解析文件,并拿出图标写出到指定文件目录

参考文献 :

纯java从apk文件里获取包名、版本号、icon

Java环境解析apk文件信息的更多相关文章

  1. c# 借助cmd命令解析apk文件信息

    借助aapt.exe文件 aapt.exe 解析apk包信息cmd命令: aapt dump badging *.apkaapt d badging *.apk >1.txt(保存成1.txt文 ...

  2. JAVA简便解析json文件

    JAVA简便解析json文件 首先放上我要解析的json文件: { "resultcode":"200", "reason":"S ...

  3. Java jdom解析xml文件带冒号的属性

    Java jdom解析xml文件带冒号的属性 转载请标明出处: https://dujinyang.blog.csdn.net/article/details/99644824 本文出自:[奥特曼超人 ...

  4. c#调用aapt查看apk文件信息功能实现

    第一篇随笔就此开始. 1. 起源 思路源自于项目开发过程中.需要确认apk文件版本以验证其功能差异以便于定位问题,于是度娘,得到APK信息查看器(APK-info)这个工具,其版本号为0.2.它能显示 ...

  5. 【Android】获取手机中已安装apk文件信息(PackageInfo、ResolveInfo)(应用图片、应用名、包名等)

    众所周知,通过PackageManager可以获取手机端已安装的apk文件的信息,具体代码如下 PackageManager packageManager = this.getPackageManag ...

  6. java opencsv解析csv文件

    记一次使用opencsv解析csv文件时碰到的坑 最近在开发过程中需要解析csv文件,公司用的解析工具是opencsv,在根据opencsv的官方文档去解析时发现csv文件中含有繁体字,使用其自带的C ...

  7. Java(Android)解析KML文件

    參考自:http://blog.csdn.net/yyywyr/article/details/38359049 http://blog.csdn.net/warrenwyf/article/deta ...

  8. 获取手机中已安装apk文件信息(PackageInfo、ResolveInfo)(应用图片、应用名、包名等)

    众所周知,通过PackageManager可以获取手机端已安装的apk文件的信息,具体代码如下: PackageManager packageManager = this.getPackageMana ...

  9. python解析json文件信息到csv中

    json格式多种多样,本代码着重看函数部分 import json, csv, os import pandas as pd josns_root = 'jsons' csvs_root = 'csv ...

随机推荐

  1. JDBC增删查改(使用配置文件)

    JDBCDemo2.java package com.zhangbz.jdbc; import java.sql.Connection; import java.sql.ResultSet; impo ...

  2. iOS网络-06-监听Iphone的网络状态

    使用系统的方法来监听网络状态 系统的方法是通过通知机制来实现网络状态的监听 实现网络状态监听的步骤 定义Reachability类型的成员变量来保存网络的状态 @property (nonatomic ...

  3. CFString​Transform

    Mattt Thompson撰写. Ricky Tan翻译. 发布于2012年8月6日关于一种语言好不好用,你只需要衡量以下两种指标: API 的统一性String 类的实现质量NSString 是基 ...

  4. 给你的Mr.Right画张择偶地图像

    爱一个人就算做不到爱他的全部,至少也应该尊重他的真实,而不是苛求他变成你想要的样子. 娶妻当娶郭芙蓉,经典语录.我是郭芙蓉,我不会武功,我来自江湖,我与众不同.再苦再累,就当自己是二百五,再难再险,就 ...

  5. CSS中vw和vh单位的使用

    vw——viewpoint width,视窗宽度,1vw等于视窗宽度的1%: vh——viewpoint height,视窗高度,1vh等于视窗高度的1%:例子:http://tutorialzine ...

  6. 烂泥:kvm安装windows系统蓝屏

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 最近一直在学习有关KVM的知识,实验一直是在虚拟机VM中进行的.今天刚好公司有一台空闲的服务器,直接拿来安装centos.kvm等等,然后相关的配置. ...

  7. Java + eclipse + awt 编写锻炼打字小软件(未完成)

    进入前界面: import java.awt.*; public class Welcome extends JFrame implements Runnable{ Thread t; private ...

  8. KEIL与ADS1.2共存

    出现的问题: 原来电脑已经安装了ADS1.2.现在安装keil5编译一个32位新唐单片机程序时,出现了如下错误: Error: L6411E: No compatible library exists ...

  9. SQL Server 2005中更改sa的用户名和密码

    修改数据库SA账号名称的代码如下:  代码如下: Alter LOGIN sa DISABLE Alter LOGIN sa WITH NAME = [systemAccount] "sys ...

  10. Oracle 性能维护一点

    大数据量表的维护原则 1.如果此表经常CRUD,最好的办法是定期收集统计信息传递给oracle优化器,提高性能.例如dbms_stats.gather_table_stats命令. 可以做在ETL中, ...