前段時間作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()); } } } } }