首页 > 代码库 > Java解析apk
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 apkPath103 * apk的路径。104 * @return apkInfo 一个Apk的信息。105 */106 public ApkInfo getApkInfo(String apkPath) throws Exception {107 String command = mAaptPath + softName + " d badging \"" + apkPath108 + "\"";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 apkInfo147 * @param source148 */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 source193 * @return194 */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 source204 * @return205 */206 private String getKeyBeforeColon(String source) {207 return source.substring(0, source.indexOf(‘:‘));208 }209 210 /**211 * 分离出包名、版本等信息。212 * 213 * @param apkInfo214 * @param packageSource215 */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 c227 * 将关闭的资源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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。