有没有一种方法可以获取jar文件中使用的方法数量?

33

我可以获得一个JAR文件中使用的所有方法的计数吗? 我的APK使用了某些外部JAR包,确切地说大约有一百个类。

我已经使用过像dex2jar JAD等反编译工具,但它们似乎只显示特定类文件中的方法。

有没有办法获取总数?


1
你想要定义这个数字还是使用这个数字? - Peter Lawrey
@Peter:根据目的,我可以使用方法声明或方法引用两种选项。 - freeky9
因此,您并不是在谈论程序运行时实际使用了多少。 - Peter Lawrey
12个回答

81

您可以将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的总方法引用计数将<=两个的总和。


2
这是我的答案:android-sdk-macosx/build-tools/17.0.0/dx - deepwinter
1
谢谢,根据您的回答,我编写了一个用于计算jar文件夹中方法数量的脚本:https://gist.github.com/toms972/c83504df2da1176a248a - Tom Susel
2
hexdump -s 88 -n 4 -e '1/4 "%d\n"' temp.dex - friederbluemle
1
当您已经组装了dex文件时,使用dx是完全可以的,但我遇到了一个情况,当我超过65k限制时,我无法组装dex文件以检查方法计数。问题仍然存在,如何直接从jar中获取方法计数而不需要中间dex。 - Gena Batsyan
1
@GenaBatsyan 这是一个很好的观点。我在这个答案中的目标是提供一种使用大多数开发人员可能已经在他们的机器上拥有的工具来解决问题的解决方案(至少,在安装了Android SDK的类Unix机器上)。然而,针对您所描述的情况,我刚刚添加了另一种备选答案,它使用dx和baksmali。 - JesusFreke
显示剩余2条评论

11

这个Gradle插件https://github.com/KeepSafe/dexcount-gradle-plugin会在编译后显示总方法数,并生成一个报告,其中包含每个包的方法计数。排序后的结果看起来像这样:

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

如果你运行这个程序,它会打印出依赖树。通过查看依赖关系可以很好地了解每个依赖项需要多少方法。


3

使用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

首先解压缩它(是的,AAR实际上是ZIP),然后像在JAR部分中展示的那样使用classes.jar

unzip mylib.aar -d mylib

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

dex-method-counts temp.dex


3

Cyvis 能够读取 .jar.class 文件,并显示每个方法的总方法数、圈复杂度和指令计数。其图形用户界面有些...轻便...但我已在Ubuntu上运行它并且它声称支持Windows。作为第一手信息源,看起来还不错,帮助确认一个库是否会给你带来麻烦。


我尝试过这个工具。如果它能对事物进行排序(包是随机排列的),并且您可以递归地查看包及其子包中类和方法的总数,那么它将非常有用。它不会显示整个项目的总方法数;只显示总包和类数。 - voxoid
该工具的其他问题包括:1)自2006年以来未更新。2)不会分解内部类,只会列出顶级类。例如,我的外部类有8个方法,但一个内部类可能还有50个未被提及的方法。 - Jesse Chisholm

2

如果您的方法已经超过了64k的限制,另一种方法是使用--multi-dex选项来运行dx命令,然后在dx生成的所有dex文件上使用baksmali的“列出方法”功能。接下来,您需要合并这些列表,对合并后的列表进行排序并删除任何重复项。剩余的方法数量将是总方法数。

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

注意:从baksmali v2.2开始才有“baksmali list methods”功能。 - JesusFreke

0

我刚刚写了一个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服务索引。


您可以使用 javap 的 -s 标志,并查找以 Signature: ( 开头的行,以避免在括号上的黑客攻击。 - TheRealNeo

0
如果您有源代码(或可以下载它),Sonar 将对其进行静态分析,就像这样。您还可以检查一堆其他复杂度指标,这可能对您正在尝试的内容有用。(告诉我们您正在尝试做什么可能会很好。;))

我猜测OP想知道哪些JAR文件值得花时间尝试减少方法计数,以便最终的APK保持在64K限制以下。 - Jesse Chisholm

0
  1. 使用带有-x参数的jar程序提取您的jar文件中的文件。

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

  3. 将方法计数相加。


奇怪,我好像给这个帖子点了踩(我不记得这么做了,是鼠标点错了吗?)如果你编辑了这篇帖子,我可以修改我的投票。很抱歉:( - powerj1984
1
@powerj1984 没什么大不了的 - 我有足够的积分来达到我的目的。但我已经进行了一个虚拟编辑,所以你可以把它整理一下。 - Patricia Shanahan

0

0
我根据@JesusFreke的答案为这个问题和另一个问题编写了一个脚本(https://dev59.com/2mEi5IYBdhLWcg3wRauf#21485222):
#!/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 status-bar-compat-release.aar 
Archive:  status-bar-compat-release.aar
  inflating: aarsize/classes.jar     
91

91 是你的 aar 文件的方法计数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接