Java环境解析apk文件信息

Posted ✧*꧁一品堂.技术学习笔记꧂*✧.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java环境解析apk文件信息相关的知识,希望对你有一定的参考价值。

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



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

参考文献 :

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





内容来自:cnblogs:牛奶、不加糖

以上是关于Java环境解析apk文件信息的主要内容,如果未能解决你的问题,请参考以下文章

如何解析 .apk 包中的 AndroidManifest.xml 文件

Android 逆向Android 逆向方法 ( 静态逆向解析 | 函数调用分析 | 动态运行跟踪 | 运行日志分析 | 文件格式解析 | 敏感信息分析 | 网络信息监控 | 环境伪装模拟 )

关于ribo的代码来解析从apk到xml的信息

基于 jq 实现拖拽上传 APK 文件,js解析 APK 信息

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

解析apk,获取apk的详细信息