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解析apk

时间: 2024-08-27 00:48:43

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 ja

完整版java读取apk、ipa包名、版本名、版本号等信息

有时候,我们上传apk或者是ipa文件的时候,是需要读取到里面的一些信息的,比如软件的包名,以及其版本信息等.在网上搜索了一下资料 , 找了很多版本,对于apk文件的版本号,一直读取不到,在这里,笔者自己总结了,读取apk.ipa文件的一些代码,大家可以参考下,去其糟粕,取其精华.以便适用于自己的需求. 下面会提供源码给大家,我用的开发工具是eclipse,直接导入就可以,jar包也是我已经下载好的,大家可以免积分拿去.本来里面是有2个apk.2个ipa文件提供测试的,但是由于文件太大,上传不了

nodejs解析apk

项目再github上的目录:https://github.com/chen2009277025/nodejs_apkTool nodejs无可厚非是新兴的后端语言,因为他的开发语言是javascript,javascript语言的自身优势,让nodejs迅速的火遍大江南北. 很多的nodejs的开发插件如雨后春笋般的涌现出来,比如文件操作的fs,解决数据库链接的各种中间件,mysql.mongoose等等. 但是目前我还没有发现关于nodejs解析apk的,这个需求并不是很大众,但是对于有些项目

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

简洁:不超过5个java文件 依赖:仅依赖aapt.exe 支持:仅限windows 功能:用纯java获取apk文集里的包名,版本号,图标文件[可获取到流直接保存到文件系统] 原理:比较上一篇文章里通过反编译然后解析AndroidManifest.xml的方式,此种方式更加简单,通过模拟执行aapt截取cmd输出并整理获取信息. 附件为源码,test/demo 为演示,output下为编译后的jar文件. 参考开源项目: http://code.google.com/p/cfuture09-a

通过上传的APK文件,解析APK文件内容,获取应用权限包名等

通过上传的APK文件,解析APK文件内容,获取应用权限包名等 1工具导入: 下载aapt.exe反编译执行程序,放入Java工程资源文件夹下(具体路径自己可定义) 2编写ApkUtil类,获取apk文件信息 public class ApkUtil { public static final String VERSION_CODE = "versionCode"; public static final String VERSION_NAME = "versionName&q

JAVA解析XML之SAX方式

JAVA解析XML之SAX方式 SAX解析xml步骤 通过SAXParseFactory的静态newInstance()方法获取SAXParserFactory实例factory 通过SAXParserFactory实例的newSAXParser()方法返回SAXParser实例parser 创建一个类继承DefaultHandle,重写方法进行业务处理并创建这个类的实例handle 重写DefaultHandle类的方法 startElement方法用来遍历xml文件的开始标签; endEle

Java解析JSON对象

今天学习一下Java 解析 JSON 准备工作 参考文档 1) www.json.org 2 ) 参考公司其他人的代码(这个就不说了) 依赖jar包 1) org.json.jar 提供以下我的网盘链接 http://pan.baidu.com/s/1jG2zSwe 主要的类 JSON主要有两种结构 1)name/value 的集合 2)value 的集合,在大多数语言中的list,array等,这里的 value 个人觉得就是一个JSON,也就是说是JSON的集合 JAVA处理JSON的类 1

HexDump.java解析

从包名我们可以看出该类并没有对应用开发者开放,也就是说在google开放的Android API文档中并没有该类的相关介绍:好在Android系统源码是开源的,因此我在解决framework中问题的时候发现了这个工具类,由于工作原因一直没有回头在细细的领会这个工具类的精髓,因此今天花点时间对这个类进行全面的分析一遍,以备不时之需. 首先分析之前,我们需要了解该类使用来进行16禁止转换的,我之前也写过相关的工具类,但是去了解Google的精神还是有必要的. package com.android.

java解析xml的三种方法

java解析XML的三种方法 1.SAX事件解析 package com.wzh.sax; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; // public class Saxhandler extends DefaultHandler { @Override public void startDocument() throws