无法使用 Ant 从外部 jar 构建多个 Android dex 文件
Posted
技术标签:
【中文标题】无法使用 Ant 从外部 jar 构建多个 Android dex 文件【英文标题】:Can't build multiple Android dex files with Ant from external jars 【发布时间】:2013-04-17 09:30:48 【问题描述】:我正在开发一个需要多个库(用于 Facebook、Google Maps v2 和 Quickblox 等)的 android 应用,导致方法量溢出超过 64K 限制:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536
因为我不能没有这些库,所以我寻找方法限制错误的解决方案。我从 Android 开发者那里找到了一篇很受欢迎的博客文章,其中建议进行源代码划分。 (我正在谈论的博客条目可以在这里找到:http://android-developers.blogspot.com.es/2011/07/custom-class-loading-in-dalvik.html)。我一直在尝试这个解决方案,但没有成功。
我现在遇到的问题是,最多的代码不是在我的应用程序本身,而是在所需的库中,所以我必须将这些库分布在我必须在我的应用程序中加载的不同 dex 文件中。我对Ant的了解非常有限,我想知道的是我应该在我的build.xml文件中写什么让dex复制我想要的每个库:
<!-- Primary dex to include my source code and some libraries. -->
<copy todir="$out.classes.absolute.dir.1" >
<fileset dir="$out.classes.absolute.dir" >
...
</fileset>
</copy>
<!-- Secondary dex to include some other libraries. -->
<copy todir="$out.classes.absolute.dir.2" >
<fileset dir="$out.classes.absolute.dir" >
...
</fileset>
</copy>
任何帮助将不胜感激。提前致谢,问候!
【问题讨论】:
您找到解决方案了吗?我有完全相同的问题。 【参考方案1】:到目前为止,我听到的关于这个问题的最佳答案是在优化模式 (proguard-android-optimize.txt) 下使用带有 -dontobfuscate
标志的 ProGuard 从最终 APK 中删除未使用的类和方法(不混淆它们)。然后,您可以使用 ProGuard mapping.txt 帮助您从您使用的库 JAR 中删除未使用的类(我不知道有什么好的工具可以做到这一点)。不幸的是,我认为 ProGuard 中没有自动执行此操作的功能。
ProGuard 仅在 Eclipse 中执行导出时运行,而不是在执行运行方式 -> Android 应用程序时运行。这意味着它无助于避免调试构建的限制,除非您使用自定义构建过程。 ProGuard 的创建者建议使用其商业兄弟DexGuard,它将在 Eclipse 中运行调试和发布版本。
强烈建议在发布版本中使用 ProGuard,因为它会减少您的代码大小、提高性能(例如通过内联代码),并且还会混淆您的源代码。确保您对最终的 APK 进行了足够的测试,因为它将与调试版本有很大不同。不幸的是,ProGuard 本身并不足以解决我的问题,所以我删除了我的一个 JAR 依赖项作为一种解决方法。
我使用以下命令检查了依赖 JAR 中的方法数量:
dx --dex --output=temp.dex library.jar
cat temp.dex | head -c 92 | tail -c 4 | hexdump -e '1/4 "%d\n"'
我们最大的库的方法数量示例:
11222 guava-11.0.1.jar
10452 aws-android-sdk-1.5.0-core.jar
5761 org.restlet.jar
5129 protobuf-java-2.4.1.jar
2499 aws-android-sdk-1.5.0-s3.jar
2024 ormlite-core-4.41.jar
1145 gson-2.2.2.jar
1716 google-http-client-1.11.0-beta.jar
仅供参考,您可以使用 dexdump 检查 APK 中的方法数量(可以在 SDK build-tools
文件夹中找到,例如“Android Studio.app/sdk/build-tools/21.0.2/dexdump”) :
dexdump -f MyApp.apk | grep method_ids_size
method_ids_size : 64295
在我们的例子中,我们只使用 Guava 进行 YouTube 搜索,因此很容易消除这种依赖并给我们更多的喘息空间。
更新:我发现从大型 JAR 中去除未使用代码的最简单方法是在我的 Proguard 构建中使用 dex2jar,然后使用 JD-GUI 将最终 JAR 与特定输入 JAR 进行比较想修剪。然后我删除了我知道被 Proguard 删除的***包。这让我可以从 aws-android-sdk-1.5.0-core.jar 中删除 >8000 个方法。
【讨论】:
感谢分享。我可以知道如何从 jar 文件中删除不需要的包吗?由于 jar 文件本身是二进制形式。您是否使用 Java 文件形式的 JD-GUI 对它们进行反编译,然后将它们重新编译回 Jar? 使用“jar”工具解压缩和重新压缩。【参考方案2】:ProGuard 是一个源代码压缩工具,它会在打包您的应用程序时删除所有未使用/重复的类。因此,即使您使用所有这些外部 JAR,也不会 100% 使用其中的所有类,并且其中许多 JAR 内部可能有相同的类(例如 Log4J 等)。
Proguard is built into dex。但它默认不会被激活,你必须在发布模式下运行ant,你可能还需要在project.properties中注释掉一行。
最有可能的是,ProGuard 最终可能会删除您的应用程序中使用的某些类。如果在编译 ProGuard 的时候遇到class X not found
之类的错误,那么在proguard.cfg
中配置 ProGuard 你需要那个类:
-keep public class <full path to the class that you need>
查看 Android ProGuard 文档,看看启用 proguard 是否会减少 APK 中的(类和方法的)大小。
【讨论】:
以上是关于无法使用 Ant 从外部 jar 构建多个 Android dex 文件的主要内容,如果未能解决你的问题,请参考以下文章
如何引用公共目录(不是库)中的外部 jar 文件来使用 ant 构建 android 项目?
Ant 在 JDK9 上的 maven 构建期间无法创建 .pkg 文件