有没有一种方法来获取在一个jar文件中使用的数字方法的计数

我可以有一个jar文件中使用的所有方法的计数。 我的APK使用某些外部JARS,并且有几百个类的精确数量。

我已经使用了反编译器,如dex2jar JAD等等,但它们似乎都只在特定的类文件中显示方法。

有没有办法我可以得到总数?

您可以将jar转换为dex文件,然后将方法引用的数量从头文件中提取出来。 它被存储为一个无符号的小尾数整数,在偏移量88(0x58)。

dx --dex --output=temp.dex orig.jar cat temp.dex | head -c 92 | tail -c 4 | hexdump -e '1/4 "%d\n"' 

请记住,这是引用的唯一方法的数量,而不是方法引用的数量。 换句话说,如果一个特定的方法在dex文件中被引用了两次,那么它只会在头文件中计数一次。 而当你将这个jar文件导入你的apk文件时,这两个文件之间通用的方法引用被重复数据删除,所以最终合并的apk文件的引用计数总数将是<=这两个文件的总和。

这个gradle插件https://github.com/KeepSafe/dexcount-gradle-plugin会显示组装后的总方法数,并且会生成一个包含每个包的方法数的报告。; sorting后看起来像这样:

 30145 com 27704 org 20950 android 17140 org.spongycastle 16605 android.support 9760 com.google 8930 com.fasterxml.jackson 8930 com.fasterxml 8633 android.support.v4 7020 com.fasterxml.jackson.databind 6426 android.support.v7 5311 com.google.protobuf 4705 org.spongycastle.crypto ... 

结合gradle命令

 .\gradlew app:dependencies 

这将打印出依赖关系树,您将很好地了解哪个依赖关系需要多less个方法。

Cyvis可以读取.jar.class文件,并且将显示每个方法的总方法计数加周期复杂度和指令计数。 graphics用户界面有点…可移植…但我已经在Ubuntu上运行它,它说它在Windows上工作。 对于图书馆有多大可能会给您带来麻烦的信息来源,似乎相当不错。

使用http://github.com/mihaip/dex-method-counts来计算各种方法的数量(JAR,AAR,DEX,APK);

DEX或APK:

./dex-method-counts <your_file_path>.DEX./dex-method-counts <your_file_path>.APK

jar

就像上面显示的那样,从JAR制作一个DEX:

<your_path_to_android_buil_tools>/dx --dex --output=temp.dex orig.jar

接着

./dex-method-counts temp.dex

AAR

首先解压缩(是啊,它实际上是ZIP),然后使用classes.jar如上面显示在JAR部分

unzip mylib.aar -d mylib

dx --dex --output=temp.dex mylib/classes.jar

dex-method-counts temp.dex

对于已经超过了64k方法限制的情况,另一种方法是对dx使用–multi-dex选项,然后在dx生成的所有dex文件上使用baksmali的“列表方法”function。 接下来,您将组合这些列表,对组合列表进行sorting并删除任何重复项。 您留下的方法数将是总方法数。

 dx --dex --multi-dex --output=out orig.jar find out -name classes*.dex -exec baksmali list methods {} \; | sort | uniq | wc -l 

如果你有源代码(或者可以下载), Sonar会做这样的静态分析。 您还可以检查一些其他复杂度度量标准,这些度量标准可能对您正在尝试执行的操作有用。 (可能很高兴告诉我们你要做什么;))

  1. 使用jar程序和-x参数从jar文件中提取文件。

  2. 对每个.class文件应用一个反编译器以获取每个文件中的方法数量。

  3. 将方法计数加起来。

我只是写了一个python脚本来得到一个粗略的估计

 import re import subprocess import sys for jarfile in sys.argv[1:]: class_output = subprocess.check_output(['jar', 'tf', jarfile]) classes = [c.replace('/', '.') for c in re.findall(r'(.*)\.class', class_output)] methods = [] if classes: def_out = subprocess.check_output(['javap', '-classpath', jarfile] + classes) # This is pretty hacky: look for parentheses in the declaration line. num_methods = sum(1 for line in def_out if '(' in line) else: num_methods = 0 print '{} {} {}'.format(num_methods, len(classes), jarfile) 

我刚刚遇到了Android 64K方法的限制,而我的依赖项并没有被methodcount.com服务索引。

我写了一个基于@ JesusFreke回答这个问题和另一个问题的脚本( https://stackoverflow.com/a/21485222/6643139 ):

 #!/bin/bash unzip $1 classes.jar -d aarsize && dx --dex --output=aarsize/temp.dex aarsize/classes.jar && hexdump -s 88 -n 4 -e '1/4 "%d\n"' aarsize/temp.dex && rm -rf aarsize 

将其保存为文件名“aarsize”, chmod +x为它, aarsize your_aar_file输出aarsize your_aar_file

 $ aarsize status-bar-compat-release.aar Archive: status-bar-compat-release.aar inflating: aarsize/classes.jar 91 

91是你的aar文件的方法。

使用命令行解压缩JAR之后,应该可以这样工作:

 for f in *.class; do javap -c $(basename -s .class $f) | grep invoke | sed 's/.*Method\(.*\)/\1/g'; done | wc -l 
 (public|protected|private|static|\s) +[\w\<\>\[\]]+\s+(\w+) *\([^\)]*\) *(\{?|[^;]) 

在项目中使用CTRL+SHIFT+F 。 它帮助了我