17

我正在开发一个需要多个库(用于 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>

任何帮助将不胜感激。在此先感谢,亲切的问候!

4

2 回答 2

6

到目前为止,我听到的关于这个问题的最佳答案是在优化模式 (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 中的方法数量(您可以在 SDKbuild-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 个方法。

于 2013-05-27T04:22:42.093 回答
0

ProGuard是一个源代码压缩工具,它会在打包您的应用程序时删除任何未使用/重复的类。因此,即使您使用所有这些外部 JAR,也不会 100% 使用其中的所有类,并且这些 JAR 中的许多可能在其中包含相同的类(例如 Log4J 等)。

Proguard 内置于 dex中。但是默认情况下它不会被激活,你必须在发布模式下运行ant,你可能还需要在project.properties中注释掉一行。

最有可能的是,ProGuard 最终可能会删除您的应用程序中使用的一些类。如果在编译 ProGuard 时出现类似 的错误,请在需要该类的情况下class X not found配置 ProGuard :proguard.cfg

-keep public class <full path to the class that you need>

查看 Android ProGuard 文档,看看启用 proguard 是否会减少 APK 中的(类和方法的)大小。

于 2013-05-26T13:29:14.530 回答