Summary
When I build my app for release build type any apollo request fails.
Version
2.4.5
Description
I am using apollo in multiplatform module. As mentioned, when I build my app for release build type every apollo request fails with following error:
No static method ofMillis(J)Lj$/time/Duration; in class Lj$/time/Duration; or its super classes (declaration of ‘j$.time.Duration’
I don't use java.time API in my project and as I can see there is usage of java.time.Duration in ApolloHttpNetworkTransport in apollo-runtime-kotlin-jvm. It is used to create OkHttpClient with particular connect/read timeouts.
Maybe it would be better to not use java.time APIs and use connectTimeout(timeout: Long, unit: TimeUnit) version of this method so there is no dependency on API that can potentially breake the app in runtime?
I tried to set isCoreLibraryDesugaringEnabled to true in compileOptions block for android with coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.1") declared in dependencies block but it did not help.
On the other side debug build of my app works fine, but I don't set minifyEnabled to true in release build type so there is no R8 optimisation involved.
Please let me know if there is such issue or point me in direction how I can fix this problem. Thanks in advance
Hi 👋 , thanks for reaching out!
I'd expect Duration.ofMillis to be available on all Android devices through desugaring: https://developer.android.com/studio/write/java8-support-table
Maybe it would be better to not use java.time APIs and use connectTimeout(timeout: Long, unit: TimeUnit) version of this method so there is no dependency on API that can potentially breake the app in runtime?
Duration.ofMillis is 6 years old and should be supported by Android so I'd prefer understanding the root cause before using even older APIs
On the other side debug build of my app works fine, but I don't set minifyEnabled to true in release build type so there is no R8 optimisation involved.
Can you ellaborate on that? Usually, you would set minifyEnabled=true only in release builds. If it works in debug and not in release (or the other way around), it would hint towards something's wrong with your Gradle configuration.
Hi!
One more thing to add:
Seems that D8 compiler doesn't "see" usage of specific method: java.time.Duration.ofMillis(L) from apollo-runtime-kotlin-jvm when performs rewriting to the $j packages. Here is a part of our dex:

If we manually put simple call to java.time.Duration.ofMillist(0L) within our own codebase this method will appear.
Could it be that D8 minifies before desugaring? That'd feel weird but it looks like it's what that's happening?
Another thing to consider: do you have Android library modules in addition to your application module? I'm not sure if it's possible to run D8 on library modules but if it is, it could explain this.
Can you ellaborate on that? Usually, you would set minifyEnabled=true only in release builds. If it works in debug and not in release (or the other way around), it would hint towards something's wrong with your Gradle configuration.
By this I mean that release and debug build types configuration is the same. No minification in both
Another thing to consider: do you have Android library modules in addition to your application module? I'm not sure if it's possible to run D8 on library modules but if it is, it could explain this.
Actually it is separate multiplatform module that is using apollo and we explicitly add isCoreLibraryDesugaringEnabled to true in its build.gradle.kts file.
We will look into possibility to run D8 on library modules though, thanks for advice
Actually it is separate multiplatform module that is using apollo and we explicitly add isCoreLibraryDesugaringEnabled to true in its build.gradle.kts file.
I would have expected all library modules to contribute java .class files that are all "assembled" in .dex files in the final application module. I'm not sure what running D8 in library modules would do.
Can you try configuring desugaring in your app module?
//app/build.gradle.kts
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.0.9")
}
Overall, I can see how this is a hassle. Removing calls to Duration.ofMillis is certainly worth it. Java7 will stay with us forever 😅
we also had desugaring enabled in app module this whole time.
Overall, I can see how this is a hassle. Removing calls to Duration.ofMillis is certainly worth it. Java7 will stay with us forever 😅
It would be very helpful! Thank you for such quick response.
See https://github.com/apollographql/apollo-android/pull/2767.
I'd still be interested to know how come the desugaring didn't work in your use case. If you can upload a small reproducer somewhere or if you end up finding the root cause, please post a follow up here.
Something else worth trying is bumping your Android Gradle Plugin version to 4.1+, maybe 4.2? Latest version might support more APIs
already have 4.1.1 version set for a long time :)
Looks like all isCoreLibraryDesugaringEnabled = true does in a library module is disable the Lint warning so activating it in the library module shouldn't change much (activating it in the app module is definitely required)
java.time.Duration was removed in https://github.com/apollographql/apollo-android/pull/2767