前段时间做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());
}
}
}
}
}