概述: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. Visual Studio Code中文文档(一)-快速入门

    Visual Studio Code是一个轻量级但是十分强大的源代码编辑器,重要的是它在Windows, OS X 和Linux操作系统的桌面上均可运行.Visual Studio Code内置了对J ...

  2. Eclipse CDT Linux下内存分析 补记

    常用工具汇总 http://www.ibm.com/developerworks/cn/linux/l-cn-memleak/ 常用的内存分析工具 http://en.wikipedia.org/wi ...

  3. Java-包

    定义包用package关键字. 1:对类文件进行分类管理. 2:给类文件提供多层名称空间. 如果生成的包不在当前目录下,需要最好执行classpath,将包所在父目录定义到classpath变量中即可 ...

  4. css3制作3d旋转相册

    此处只是记录,解析可见原文:http://www.cnblogs.com/skyblue-li/p/6092799.html <!DOCTYPE html> <html xmlns= ...

  5. img转data

    http://blog.csdn.net/lwjok2007/article/details/50756273

  6. Beta冲刺第二天

    一.昨天的困难 没困难 二.今天进度 局部测试并修复出现的bug 1.林洋洋:修复登录页面显示问题,修复日程查询问题 2.黄腾达:修复创建协作开始时间和结束时间没做检验的问题 3.张合胜:修复页面内容 ...

  7. 2分钟读懂大数据框架Hadoop和Spark的异同

    转自:https://www.cnblogs.com/reed/p/7730313.html 谈到大数据,相信大家对Hadoop和Apache Spark这两个名字并不陌生.但我们往往对它们的理解只是 ...

  8. PHP的生命周期:

  9. Django 详解 信号Signal

    Django信号 Django中提供了“信号调度”,用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者. Model signals pre_init # ...

  10. T-SQL DISTINCT子句 去重复

    语法 以下是DISTINCT关键字的基本语法,用于删除重复记录. SELECT DISTINCT column1, column2,.....columnN FROM table_name WHERE ...