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

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

 获取到相应软件后,对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)