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

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

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

代码:

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

  1. package com.apkutils;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.Closeable;
  5. import java.io.File;
  6. import java.io.FileInputStream;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.InputStreamReader;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. import java.util.Properties;
  13.  
  14. /**
  15. * apk工具类。封装了获取Apk信息的方法。
  16. *
  17. * @author @author tony
  18. *
  19. * <p>
  20. * <b>version description</b><br />
  21. * V0.2.1 修改程序名字为从路径中获得。
  22. * </p>
  23. */
  24. public class ApkUtil {
  25. public static final String VERSION_CODE = "versionCode";
  26. public static final String VERSION_NAME = "versionName";
  27. public static final String SDK_VERSION = "sdkVersion";
  28. public static final String TARGET_SDK_VERSION = "targetSdkVersion";
  29. public static final String USES_PERMISSION = "uses-permission";
  30. public static final String APPLICATION_LABEL = "application-label";
  31. public static final String APPLICATION_ICON = "application-icon";
  32. public static final String USES_FEATURE = "uses-feature";
  33. public static final String USES_IMPLIED_FEATURE = "uses-implied-feature";
  34. public static final String SUPPORTS_SCREENS = "supports-screens";
  35. public static final String SUPPORTS_ANY_DENSITY = "supports-any-density";
  36. public static final String DENSITIES = "densities";
  37. public static final String PACKAGE = "package";
  38. public static final String APPLICATION = "application:";
  39. public static final String LAUNCHABLE_ACTIVITY = "launchable-activity";
  40.  
  41. // api ---- os
  42. static Map<String, String> OSVersion = new HashMap<String, String>();
  43.  
  44. static {
  45. OSVersion.put("3", "1.5");
  46. OSVersion.put("4", "1.6");
  47. OSVersion.put("5", "2.0");
  48. OSVersion.put("6", "2.0.1");
  49. OSVersion.put("7", "2.1");
  50. OSVersion.put("8", "2.2");
  51. OSVersion.put("9", "2.3");
  52. OSVersion.put("10", "2.3.3");
  53. OSVersion.put("11", "3.0");
  54. OSVersion.put("12", "3.1");
  55. OSVersion.put("13", "3.2");
  56. OSVersion.put("14", "4.0");
  57. OSVersion.put("15", "4.0.3");
  58. OSVersion.put("16", "4.1.1");
  59. OSVersion.put("17", "4.2");
  60. OSVersion.put("18", "4.3");
  61. OSVersion.put("19", "4.4");
  62. }
  63.  
  64. private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";
  65. private static final String FEATURE_SPLIT_REGEX = "(:')|(',')|'";
  66. /**
  67. * aapt所在的目录。
  68. */
  69. private String mAaptPath = "D:\\App\\";//winOS
  70. //private String mAaptPath = ApkUtil.class.getClassLoader().getResource("").getPath();//linux
  71.  
  72. static String[] shellCommand;
  73. static String softName = "";
  74. static {
  75. shellCommand = new String[2];
  76. final String anOSName = System.getProperty("os.name");
  77. if (anOSName.toLowerCase().startsWith("windows")) {
  78. // Windows XP, Vista ...
  79. shellCommand[0] = "cmd";
  80. shellCommand[1] = "/C";
  81. softName = "aapt.exe";
  82. } else {
  83. // Unix, Linux ...
  84. shellCommand[0] = "/bin/sh";
  85. shellCommand[1] = "-c";
  86. softName = "aapt";
  87. }
  88. }
  89.  
  90. /***
  91. * apkPath
  92. */
  93. static String apkPath = "C:/Users/win7/Desktop/Android/baiduyinyue_49.apk";
  94.  
  95. /**
  96. * 返回一个apk程序的信息。
  97. *
  98. * @param apkPath
  99. * apk的路径。
  100. * @return apkInfo 一个Apk的信息。
  101. */
  102. public ApkInfo getApkInfo(String apkPath) throws Exception {
  103. String command = mAaptPath + softName + " d badging \"" + apkPath
  104. + "\"";
  105. Process process;
  106. try {
  107. process = Runtime.getRuntime().exec(
  108. new String[] {shellCommand[0], shellCommand[1], command});
  109. } catch (IOException e) {
  110. process = null;
  111. throw e;
  112. }
  113.  
  114. ApkInfo apkInfo = null;
  115. if(process != null){
  116. InputStream is = process.getInputStream();
  117. BufferedReader br = new BufferedReader(
  118. new InputStreamReader(is, "utf8"));
  119. String tmp = br.readLine();
  120. try {
  121. if (tmp == null || !tmp.startsWith("package")) {
  122. throw new Exception("参数不正确,无法正常解析APK包。输出结果为:\n" + tmp + "...");
  123. }
  124. apkInfo = new ApkInfo();
  125. do {
  126. setApkInfoProperty(apkInfo, tmp);
  127. } while ((tmp = br.readLine()) != null);
  128. } catch (Exception e) {
  129. throw e;
  130. } finally {
  131. process.destroy();
  132. closeIO(is);
  133. closeIO(br);
  134. }
  135. }
  136. return apkInfo;
  137. }
  138.  
  139. /**
  140. * 设置APK的属性信息。
  141. *
  142. * @param apkInfo
  143. * @param source
  144. */
  145. private void setApkInfoProperty(ApkInfo apkInfo, String source) {
  146. if (source.startsWith(PACKAGE)) {
  147. splitPackageInfo(apkInfo, source);
  148. } else if (source.startsWith(LAUNCHABLE_ACTIVITY)) {
  149. apkInfo.setLaunchableActivity(getPropertyInQuote(source));
  150. } else if (source.startsWith(SDK_VERSION)) {
  151. apkInfo.setSdkVersion(getPropertyInQuote(source));
  152. apkInfo.setMinOSVersion(OSVersion.get(getPropertyInQuote(source)));
  153. } else if (source.startsWith(TARGET_SDK_VERSION)) {
  154. apkInfo.setTargetSdkVersion(getPropertyInQuote(source));
  155. } else if (source.startsWith(USES_PERMISSION)) {
  156. apkInfo.addToUsesPermissions(getPropertyInQuote(source));
  157. } else if (source.startsWith(APPLICATION_LABEL)) {
  158. apkInfo.setApplicationLable(getPropertyInQuote(source));
  159. } else if (source.startsWith(APPLICATION_ICON)) {
  160. apkInfo.addToApplicationIcons(getKeyBeforeColon(source),
  161. getPropertyInQuote(source));
  162. } else if (source.startsWith(APPLICATION)) {
  163. String[] rs = source.split("( icon=')|'");
  164. apkInfo.setApplicationIcon(rs[rs.length - 1]);
  165. } else if (source.startsWith(USES_FEATURE)) {
  166. apkInfo.addToFeatures(getPropertyInQuote(source));
  167. } else if (source.startsWith(USES_IMPLIED_FEATURE)) {
  168. apkInfo.addToImpliedFeatures(getFeature(source));
  169. } else {
  170.  
  171. }
  172. try {
  173. apkInfo.setApkFileSize(getFileSizes(new File(apkPath)));
  174. } catch (Exception e) {
  175. e.printStackTrace();
  176. }
  177. }
  178.  
  179. private ImpliedFeature getFeature(String source) {
  180. String[] result = source.split(FEATURE_SPLIT_REGEX);
  181. ImpliedFeature impliedFeature = new ImpliedFeature(result[1], result[2]);
  182. return impliedFeature;
  183. }
  184.  
  185. /**
  186. * 返回出格式为name: 'value'中的value内容。
  187. *
  188. * @param source
  189. * @return
  190. */
  191. private String getPropertyInQuote(String source) {
  192. int index = source.indexOf("'") + 1;
  193. return source.substring(index, source.indexOf('\'', index));
  194. }
  195.  
  196. /**
  197. * 返回冒号前的属性名称
  198. *
  199. * @param source
  200. * @return
  201. */
  202. private String getKeyBeforeColon(String source) {
  203. return source.substring(0, source.indexOf(':'));
  204. }
  205.  
  206. /**
  207. * 分离出包名、版本等信息。
  208. *
  209. * @param apkInfo
  210. * @param packageSource
  211. */
  212. private void splitPackageInfo(ApkInfo apkInfo, String packageSource) {
  213. String[] packageInfo = packageSource.split(SPLIT_REGEX);
  214. apkInfo.setPackageName(packageInfo[2]);
  215. apkInfo.setVersionCode(packageInfo[4]);
  216. apkInfo.setVersionName(packageInfo[6]);
  217. }
  218.  
  219. /**
  220. * 释放资源。
  221. *
  222. * @param c
  223. * 将关闭的资源
  224. */
  225. private final void closeIO(Closeable c) {
  226. if (c != null) {
  227. try {
  228. c.close();
  229. } catch (IOException e) {
  230. e.printStackTrace();
  231. }
  232. }
  233. }
  234.  
  235. public static void main(String[] args) {
  236. try {
  237. ApkInfo apkInfo = new ApkUtil().getApkInfo(apkPath);
  238. System.out.println(apkInfo);
  239. IconUtil.extractFileFromApk(apkPath, apkInfo.getApplicationIcon(),
  240. "D:\\icon.png");
  241. } catch (Exception e) {
  242. e.printStackTrace();
  243. }
  244. }
  245.  
  246. public String getmAaptPath() {
  247. return mAaptPath;
  248. }
  249.  
  250. public void setmAaptPath(String mAaptPath) {
  251. this.mAaptPath = mAaptPath;
  252. }
  253.  
  254. // 取得文件大小
  255. public static long getFileSizes(File f) throws Exception {
  256. long s = 0;
  257. if (f.exists()) {
  258. FileInputStream fis = null;
  259. fis = new FileInputStream(f);
  260. s = fis.available();
  261. } else {
  262. System.out.println("文件不存在");
  263. }
  264. return s;
  265. }
  266. }

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

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

  1. package com.apkutils;
  2.  
  3. import java.io.BufferedInputStream;
  4. import java.io.BufferedOutputStream;
  5. import java.io.File;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.util.zip.ZipEntry;
  10. import java.util.zip.ZipFile;
  11.  
  12. /**
  13. * 通过ApkInfo 里的applicationIcon从APK里解压出icon图片并存放到磁盘上
  14. * @author @author tony
  15. */
  16. public class IconUtil {
  17.  
  18. /**
  19. * 从指定的apk文件里获取指定file的流
  20. * @param apkpath
  21. * @param fileName
  22. * @return
  23. */
  24. public static InputStream extractFileFromApk(String apkpath, String fileName) {
  25. try {
  26. ZipFile zFile = new ZipFile(apkpath);
  27. ZipEntry entry = zFile.getEntry(fileName);
  28. entry.getComment();
  29. entry.getCompressedSize();
  30. entry.getCrc();
  31. entry.isDirectory();
  32. entry.getSize();
  33. entry.getMethod();
  34. InputStream stream = zFile.getInputStream(entry);
  35. return stream;
  36. } catch (IOException e) {
  37. e.printStackTrace();
  38. }
  39. return null;
  40. }
  41.  
  42. public static void extractFileFromApk(String apkpath, String fileName, String outputPath) throws Exception {
  43. InputStream is = extractFileFromApk(apkpath, fileName);
  44.  
  45. File file = new File(outputPath);
  46. BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), 1024);
  47. byte[] b = new byte[1024];
  48. BufferedInputStream bis = new BufferedInputStream(is, 1024);
  49. while(bis.read(b) != -1){
  50. bos.write(b);
  51. }
  52. bos.flush();
  53. is.close();
  54. bis.close();
  55. bos.close();
  56. }
  57. }

这里没什么好说的,就是用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. 通过设置虚拟机(ubantu15.10)的分辨率达到全屏效果

    最近搭建了一个ubantu 15.10虚拟机,怎么折腾都不能全屏显示.虽然我已经点了,  还是无法达到真正的全屏. 查了一下,http://jingyan.baidu.com/article/0964 ...

  2. centos性能监控系列一:常用监控命令

    Linux系统出现问题时,我们不仅需要查看系统日志信息,而且还要使用大量的性能监测工具来判断究竟是哪一部分(内存.CPU.硬盘--)出了问题 下面就让我们了解一下这些常用的性能监控工具. 1.upti ...

  3. MySQL之ALTER

    1:删除列 ALTER TABLE [表名字] DROP [列名称] 2:增加列 ALTER TABLE [表名字] ADD [列名称] INT NOT NULL COMMENT '注释说明' 3:修 ...

  4. cd dirname $0

    这个命令的功能是返回脚本正在执行的目录. 可以根据这个目录来定位运行的程序的相对位置. 这样,对shell脚本里面的相对目录的路径代码就比较安全了.在任何一台服务器上面都可以安全执行.

  5. ThinkPHP 获取get post参数与I方法

    传统方式获取变量 $id = $_GET['id']; // 获取get变量 $name = $_POST['name']; // 获取post变量 $value = $_SESSION['var'] ...

  6. 烂泥:LVM学习之KVM利用LVM快照备份与恢复虚拟机

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 最近一段时间一直在学习有关LVM逻辑卷方面的知识,前几篇文章介绍了有关LVM的逻辑卷的基本相关知识,包括逻辑卷及卷组的扩容与缩小.今天我们再来介绍LVM ...

  7. 关于google电子地图跟卫星地图位置不重合

    再做项目时,用到了google地图的显示位置,就是在网页上插入事物在地图上的位置,点击卫星地图跟电子地图时发现不是重合,网上GOOGLE了下,说是加密的问题给偏移了500米左右,用google测量工具 ...

  8. leetcode抽风的解决办法

    添加hosts: 173.230.148.103 oj.leetcode.com173.230.148.103 leetcode.com

  9. 广搜+输出路径 POJ 3414 Pots

    POJ 3414 Pots Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13547   Accepted: 5718   ...

  10. 内网穿透利器 Ngrok 使用教程

    ngrok 服务可以分配给你一个域名让你本地的web项目提供给外网访问,特别适合向别人展示你本机的web demo 以及调试一些远程的API (比如微信公众号,企业号的开发) 下面开始教程 Step ...