我正在开发一个需要多个库(用于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 Developers网站上找到了一篇很受欢迎的博客,其中推荐了一个源代码部门。(我所说的博客条目可以在这里找到:http://android-developers.blogspot.com.es/2011/07/custom-class-loading-in-dalvik.html)。我一直在尝试这个解决方案,但没有成功。
我现在的问题是,最大的代码量不是在我的应用程序本身,而是在所需的库中,所以我必须在我的应用程序中加载的不同索引文件中传播这些库。我对Ant的了解非常有限,我想知道的是我应该在我的build.xml文件中写什么,使索引复制我想要的每个库:
<!-- 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>
任何帮助将是真正的感激。提前感谢,致以亲切的问候!
到目前为止,我听到这个问题的最佳答案是使用ProGuard在优化模式(ProGuard -android-optimize.txt)与-dontobfuscate
标志从最终APK中删除未使用的类和方法(不混淆它们)。然后,您可以使用ProGuard mapping.txt来帮助您从使用的库jar中剥离未使用的类(我不知道有什么好工具可以做到这一点)。不幸的是,我不认为ProGuard中有一个功能可以自动做到这一点。
ProGuard仅在Eclipse中执行导出时运行,而不是在运行-> Android应用程序时运行。这意味着它不会帮助避免调试构建的限制,除非您使用自定义构建过程。ProGuard的创建者建议使用它的商业兄弟DexGuard,它将在Eclipse的调试和发布版本中运行。
强烈建议在发布版本中使用ProGuard,因为它可以减少代码大小,提高性能(例如通过内联代码),并且也会混淆您的源代码。确保你在最终的APK上做了足够的测试,因为它与调试的APK有很大的不同。不幸的是,ProGuard本身不足以解决我的问题,所以我删除了一个JAR依赖项作为变通方法。
我使用以下命令检查了依赖jar中的方法数量:
dx --dex --output=temp.dex library.jar
cat temp.dex | head -c 92 | tail -c 4 | hexdump -e '1/4 "%dn"'
我们最大的库的方法数量的例子:
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(您可以在SDK build-tools
文件夹中找到)检查APK中的方法数量。"Android Studio.app/sdk/构建工具/21.0.2/dexdump"):
dexdump -f MyApp.apk | grep method_ids_size
method_ids_size : 64295
在我们的例子中,我们只使用Guava来做YouTube搜索,所以很容易消除这种依赖,给我们更多的喘息空间。
Update:我发现从大型JAR中删除未使用代码的最简单方法是在Proguard构建中使用dex2jar,然后使用JD-GUI将最终JAR与我想要修剪的特定输入JAR进行比较。然后我删除我知道被Proguard删除的顶级软件包。这允许我从aws-android-sdk-1.5.0-core.jar中删除8000个方法。
ProGuard是一个源代码最小化工具,它会在打包应用程序时删除任何未使用的/重复的类。因此,即使您使用所有这些外部jar,您也不会100%使用其中的所有类,并且许多这些jar内部可能有相同的类(例如Log4J等)。
Proguard是内置在索引。但是默认情况下它不会被激活,您必须在发布模式下运行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中类和方法的大小