Android Gradle Plugin 测试 apk 构建器是不是会自动对我的测试 apk 进行多重索引?如果是这样,为啥会产生“NoSuchMethodError”

Posted

技术标签:

【中文标题】Android Gradle Plugin 测试 apk 构建器是不是会自动对我的测试 apk 进行多重索引?如果是这样,为啥会产生“NoSuchMethodError”【英文标题】:Is Android Gradle Plugin test apk builder automatically multidexing my test apk? If so, why is this generating "NoSuchMethodError"Android Gradle Plugin 测试 apk 构建器是否会自动对我的测试 apk 进行多重索引?如果是这样,为什么会产生“NoSuchMethodError” 【发布时间】:2019-04-13 11:00:43 【问题描述】:

这一切都是从运行仪器测试时出现的这个错误开始的:

java.lang.NoSuchMethodError: No static method closeQuietly(Ljava/net/ServerSocket;)V in class Lokhttp3/internal/Util; or its super classes (declaration of 'okhttp3.internal.Util' appears in /data/app/com.example-vKdPJoTLl49ntRbZfsRBqQ==/base.apk!classes2.dex)
at okhttp3.mockwebserver.MockWebServer$2.execute(MockWebServer.java:333)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)

我查看了生成的 test.apk 以查看 dex 文件中存在/缺失的内容。

我注意到的第一件事是测试 apk 有两个 .dex 文件。为什么?我没有使用 multidex(而且 IIRC multidex 无论如何都不适用于测试 apk)。然后我将两个“引用方法计数”相加,果然我超过了 65k 限制。那么 AGP 是否可以自动对我的测试 apk 进行多重索引?

此外,我在 first dex 中看到了“缺失”方法。

为什么它被列为“参考”而不是“定义”方法?这不像框架提供的 OkHttp Util 类。

在最初的崩溃中,它说在classes2.dex 中找不到方法。为什么它在 classes2.dex 中查找?为什么不两者都看?

我将 everything 保留在我的测试 apk 中(使用 proguard 但保留所有内容)(也许这解释了 +65k ref 方法)。那么,为什么这首先会被剥离/拧紧。

更新:

事实证明,我的应用程序 .apk(而不是测试 .apk)需要这种方法。当我更新应用程序 apk 的 proguard 规则时,一切正常。我还是不知道为什么应用内需要这个类?

【问题讨论】:

【参考方案1】:

java.lang.NoSuchMethodError

okhttp3.internal.Util中没有静态方法closeQuietly(java.net.ServerSocket);

方法closeQuietly(java.net.ServerSocket) 可能未使用。

明确保留它:

-keep class okhttp3.internal.Util 
    public static void closeQuietly(java.net.ServerSocket);

【讨论】:

我不明白。我看到的崩溃不是意味着使用了该方法吗?如果它没有按照您的建议使用,那么保留它们将如何产生影响?为什么我要保留closeQuietly 方法的所有三个重载? @tir38 带有ServerSocket 的构造函数可能没有被includedescriptorclasses 保留,这就是为什么我的示例是一个应该明确保留一个构造函数的规则。【参考方案2】:

我不知道我怎么不知道这一点,但显然在 API 21+ 上默认启用了 multidex

https://developer.android.com/studio/build/multidex#mdex-on-l

因此,如果您的 minSdkVersion 为 21 或更高,则启用 multidex 默认情况下,不需要multidex支持库。

是的,这很正常。可能发生的情况是该类不在第一个 dex 文件中。

【讨论】:

以上是关于Android Gradle Plugin 测试 apk 构建器是不是会自动对我的测试 apk 进行多重索引?如果是这样,为啥会产生“NoSuchMethodError”的主要内容,如果未能解决你的问题,请参考以下文章

从精准化测试看ASM在Android中的强势插入-Plugin调试

gradle/gradle plugin/Android studio关系

Gradle之Android Gradle Plugin 主要 Task 分析

Android Studio Gradle Plugin开发入门指南

Android Studio Gradle Plugin开发入门指南

如何使用 Android Studio 运行单元测试