統計JAR包DEX文件中的方法數目

    前段時間作Android項目中,一直出現方法數超過65535的問題,若是混淆後代碼中的方法數目沒有超過65535,能夠經過java

在project.properties文件中加上一行dex.force.jumbo=true,解決這個問題。app

  後來本身參考了網上的一些方法,寫了個小工具用來統計JAR包和DEX文件中的方法數目。主要原理就是利用DEX的文件結構的文件頭中有個method_ids_siz來統計方法數目。工具

如今分享出來,代碼以下,直接拷貝編譯成JAR包,而後控制檯:java -jar XXX.jar file 就能夠看到輸出結果了。目前支持文件夾、JAR和DEX文件。ui

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());
				}
				
			}
			
		}
	}
}
相關文章
相關標籤/搜索