统计JAR包DEX文件中的方法数目

    前段时间做Android项目中,一直出现方法数超过65535的问题,如果混淆后代码中的方法数目没有超过65535,可以通过

在project.properties文件中加上一行dex.force.jumbo=true,解决这个问题。

  后来自己参考了网上的一些方法,写了个小工具用来统计JAR包和DEX文件中的方法数目。主要原理就是利用DEX的文件结构的文件头中有个method_ids_siz来统计方法数目。

现在分享出来,代码如下,直接拷贝编译成JAR包,然后控制台:java -jar XXX.jar file 就可以看到输出结果了。目前支持文件夹、JAR和DEX文件。

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test2 {

	private void test() {
	}

	private final static String JAR = "jar";
	private final static String DEX = "dex";
	private final static String DIR = "dir";
	private final static String UNKNOWN = "unknown";

	/**
	 * 根据扩展名获取文件类型
	 */
	public static String getFileType(String path) {
		String type = UNKNOWN;
		try {
			File file = new File(path);
			if (file.isDirectory()) {
				type = DIR;
			} else {
				if (getExtensionName(file.getName()).equalsIgnoreCase(DEX)) {
					type = DEX;
				} else if (getExtensionName(file.getName()).equalsIgnoreCase(
						JAR)) {
					type = JAR;
				}
			}
		} catch (Exception e) {
		}
		return type;

	}

	public static void main(String[] args) {

		if (args.length != 1) {
			System.out.println("Param Error");
		} else {
			String type = getFileType(args[0]);
			if (type.equalsIgnoreCase(DEX)) {
				resolveDex(args[0]);
			} else if (type.equalsIgnoreCase(JAR)) {
				resolveJar(args[0]);
			} else if (type.equalsIgnoreCase(DIR)) {
				resolveDir(args[0]);
			} else {
				System.err.println("Unknown File Type");
			}
		}
		System.out.println("解析结束");
	}

	/**
	 * 简单的获取扩展名,不完全准确。完全准确的话,可以根据文件流判断。
	 * @param filename
	 * @return
	 */
	public static String getExtensionName(String filename) {
		if ((filename != null) && (filename.length() > 0)) {
			int dot = filename.lastIndexOf('.');
			if ((dot > -1) && (dot < (filename.length() - 1))) {
				return filename.substring(dot + 1);
			}
		}
		return filename;
	}

	/**
	 * 处理dex文件
	 * 
	 * @param path
	 */
	public static void resolveDex(String path) {
		try {
			File file = new File(path);
			FileInputStream fis = new FileInputStream(file);
			byte[] bytes = new byte[1000];
			if (fis.read(bytes) != -1) {
				StringBuilder sb = new StringBuilder();
				for (int i = 91; i > 87; i--) {
					sb.append(Integer.toBinaryString(bytes[i] & 255));
				}
				System.out.println(file.getName() + " 方法数目 : "
						+ Integer.parseInt(sb.toString(), 2));
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 解析JAR
	 * 
	 * @param path
	 */
	public static void resolveJar(String filePath) {
		try {
			String path = System.getenv("dx");
			ProcessBuilder pb=new ProcessBuilder("dx.bat","--dex","--output=C://temp.dex",filePath);
			pb.directory(new File(path));
			pb.redirectErrorStream(true);
			Process p =pb.start();
			BufferedInputStream in = new BufferedInputStream(p.getInputStream());
			BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
			String lineStr;
			
			while ((lineStr = inBr.readLine()) != null) {
				// 获得命令执行后在控制台的输出信息
//					System.out.println(lineStr);// 打印输出信息
			}
		
			// 检查命令是否执行失败。
			if (p.waitFor() != 0) {
				if (p.exitValue() != 0){// p.exitValue()==0表示正常结束,1:非正常结束
					System.err.println(filePath+" 命令执行失败!");
					inBr.close();
					in.close();
					return;
				}
			}
			inBr.close();
			in.close();
			
			File originFile = new File(filePath);
			File file = new File("C://temp.dex");
			FileInputStream fis = new FileInputStream(file);
			byte[] bytes = new byte[1000];
			if (fis.read(bytes) != -1) {
				StringBuilder sb = new StringBuilder();
				for (int i = 91; i > 87; i--) {
					sb.append(String.format("%02x",(bytes[i] & 255)));
				}
				System.out.println(originFile.getAbsolutePath() + " 方法数目 : "
						+ Integer.parseInt(sb.toString(), 16));
			}
			file.deleteOnExit();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 递归处理文件目录
	 * @param path
	 */
	public static void resolveDir(String path){
		
		File file=new File(path);
		File[] fileList = file.listFiles();
		for(int i = 0 ; i < fileList.length ; i++){
			if(fileList[i].isDirectory()){
				resolveDir(fileList[i].getAbsolutePath());
			}else{
				if(getFileType(fileList[i].getAbsolutePath()).equalsIgnoreCase(DEX)){
					resolveDex(fileList[i].getAbsolutePath());
				}else if(getFileType(fileList[i].getAbsolutePath()).equalsIgnoreCase(JAR)){
					resolveJar(fileList[i].getAbsolutePath());
				}
				
			}
			
		}
	}
}

  

posted @ 2015-01-22 20:50  pzyoung  阅读(720)  评论(0编辑  收藏  举报