I'm switching an Android application from using Proguard's desugaring to the new R8 desugaring available in Android Gradle Build Plugin 4.0.0.
I've followed the steps as detailed in the official documentation to enable Java 8 library desugaring:
gradle.properties
projectJavaVersion = 1.8
android.useAndroidX=true
android.enableJetifier=true
app build.gradle
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
buildToolsVersion '29.0.2'
compileSdkVersion 29
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility projectJavaVersion
targetCompatibility projectJavaVersion
}
kotlinOptions {
jvmTarget = projectJavaVersion
}
defaultConfig {
multiDexEnabled true
minSdkVersion 19
targetSdkVersion 23
applicationId = 'com.example.app'
}
buildTypes {
release {
...
minifyEnabled true
}
debug {
debuggable true
minifyEnabled true
}
}
}
dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.0.10"
...
}
You can see that we're supporting API 19 as a minimum. There are no build errors (using Gradle 6.1.1), but there are the following warnings:
Warning in synthesized for lambda desugaring:
Type `j$.$r8$wrapper$java$util$function$Function$-V-WRP` was not found, it is required for default or static interface methods desugaring of `java.util.Comparator java.time.chrono.-$$Lambda$AbstractChronology$j22w8kHhJoqCd56hhLQK1G0VLFw.thenComparing($-vivified-$.java.util.function.Function)`
Warning in synthesized for lambda desugaring:
Type `j$.$r8$wrapper$java$util$function$ToLongFunction$-V-WRP` was not found, it is required for default or static interface methods desugaring of `java.util.Comparator java.time.chrono.-$$Lambda$AbstractChronology$j22w8kHhJoqCd56hhLQK1G0VLFw.thenComparingLong($-vivified-$.java.util.function.ToLongFunction)`
Warning in synthesized for lambda desugaring:
Type `j$.$r8$wrapper$java$util$function$ToDoubleFunction$-V-WRP` was not found, it is required for default or static interface methods desugaring of `java.util.Comparator java.time.chrono.-$$Lambda$AbstractChronology$j22w8kHhJoqCd56hhLQK1G0VLFw.thenComparingDouble($-vivified-$.java.util.function.ToDoubleFunction)`
Warning in synthesized for lambda desugaring:
Type `j$.$r8$wrapper$java$util$function$ToIntFunction$-V-WRP` was not found, it is required for default or static interface methods desugaring of `java.util.Comparator java.time.chrono.-$$Lambda$AbstractChronology$j22w8kHhJoqCd56hhLQK1G0VLFw.thenComparingInt($-vivified-$.java.util.function.ToIntFunction)`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/concurrent/ConcurrentHashMap$EntryIterator.class:
Type `j$.$r8$wrapper$java$util$function$Consumer$-V-WRP` was not found, it is required for default or static interface methods desugaring of `void java.util.concurrent.ConcurrentHashMap$EntryIterator.forEachRemaining($-vivified-$.java.util.function.Consumer)`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/concurrent/ConcurrentHashMap$CollectionView.class:
Type `j$.$r8$wrapper$java$util$stream$Stream$-WRP` was not found, it is required for default or static interface methods desugaring of `$-vivified-$.java.util.stream.Stream java.util.concurrent.ConcurrentHashMap$CollectionView.parallelStream()`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/concurrent/ConcurrentHashMap$CollectionView.class:
Type `j$.$r8$wrapper$java$util$Spliterator$-WRP` was not found, it is required for default or static interface methods desugaring of `$-vivified-$.java.util.Spliterator java.util.concurrent.ConcurrentHashMap$CollectionView.spliterator()`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/concurrent/ConcurrentHashMap$CollectionView.class:
Type `j$.$r8$wrapper$java$util$function$Predicate$-V-WRP` was not found, it is required for default or static interface methods desugaring of `boolean java.util.concurrent.ConcurrentHashMap$CollectionView.removeIf($-vivified-$.java.util.function.Predicate)`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/DesugarCollections$SynchronizedMap.class:
Type `j$.$r8$wrapper$java$util$function$BiFunction$-V-WRP` was not found, it is required for default or static interface methods desugaring of `void java.util.DesugarCollections$SynchronizedMap.replaceAll($-vivified-$.java.util.function.BiFunction)`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/DesugarCollections$SynchronizedMap.class:
Type `j$.$r8$wrapper$java$util$function$BiConsumer$-V-WRP` was not found, it is required for default or static interface methods desugaring of `void java.util.DesugarCollections$SynchronizedMap.forEach($-vivified-$.java.util.function.BiConsumer)`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/concurrent/ThreadLocalRandom.class:
Type `j$.$r8$wrapper$java$util$stream$IntStream$-WRP` was not found, it is required for default or static interface methods desugaring of `$-vivified-$.java.util.stream.IntStream java.util.concurrent.ThreadLocalRandom.ints()`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/concurrent/ThreadLocalRandom.class:
Type `j$.$r8$wrapper$java$util$stream$LongStream$-WRP` was not found, it is required for default or static interface methods desugaring of `$-vivified-$.java.util.stream.LongStream java.util.concurrent.ThreadLocalRandom.longs()`
Warning in /Users/username/.gradle/caches/modules-2/files-2.1/com.android.tools/desugar_jdk_libs/1.0.4/961afbdb3d41eebfb63b8c8ccdc97453b869964e/desugar_jdk_libs-1.0.4.jar:java/util/concurrent/ThreadLocalRandom.class:
Type `j$.$r8$wrapper$java$util$stream$DoubleStream$-WRP` was not found, it is required for default or static interface methods desugaring of `$-vivified-$.java.util.stream.DoubleStream java.util.concurrent.ThreadLocalRandom.doubles(long)`
Warning: Type `java.util.OptionalConversions` was not found, it is required for default or static interface methods desugaring of `java.util.OptionalLong j$.$r8$wrapper$java$util$stream$LongStream$-WRP.findAny()`
Warning: Type `java.util.LongSummaryStatisticsConversions` was not found, it is required for default or static interface methods desugaring of `java.util.LongSummaryStatistics j$.$r8$wrapper$java$util$stream$LongStream$-WRP.summaryStatistics()`
Warning: Type `java.util.IntSummaryStatisticsConversions` was not found, it is required for default or static interface methods desugaring of `java.util.IntSummaryStatistics j$.$r8$wrapper$java$util$stream$IntStream$-WRP.summaryStatistics()`
Warning: Type `java.util.DoubleSummaryStatisticsConversions` was not found, it is required for default or static interface methods desugaring of `java.util.DoubleSummaryStatistics j$.$r8$wrapper$java$util$stream$DoubleStream$-WRP.summaryStatistics()`
When I run the app, launching an activity with the following Optional in the code, the app crashes with
I/ApplicationBase: Testing Java 8
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.app.DEV, PID: 8265
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.NoClassDefFoundError: j$.util.Optional
at com.example.app.ApplicationBase.launch(ApplicationBase.java:251)
at com.example.app.LaunchTask.doInBackground(LaunchTask.java:19)
at com.example.app.LaunchTask.doInBackground(LaunchTask.java:6)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
ApplicationBase.java
import androidx.multidex.MultiDexApplication
import java.util.Optional;
public class ApplicationBase extends MultiDexApplication implements LaunchTask.Launcher {
@SuppressLint("NewApi")
@Override
public void launch() throws IOException {
IOHandler ioHandler = new AndroidAppIOHandler(getApplicationContext());
Logger.i(TAG, "Testing Java 8");
Optional.of("xyz").ifPresent(__ -> Logger.i(TAG, "Good"));
Logger.i(TAG, "Tested Java 8");
...
}
...
}
What am I missing?
After reading @sgjesse's answer, which seemed to identify a problem with just the launch()
method, we did some further investigation. I can confirm that MultiDex.install()
is being called before launch()
.
If I add an Optional
in AndroidAppIoHandler
, like this:
public AndroidAppIOHandler(Context context) {
this.context = context;
final Optional<Context> context1 = Optional.of(context);
Log.d("TESTMULTIDEX1", context1.getClass() + " " + context1.get().getClass() + " " + context1.toString());
}
then I see:
D/TESTMULTIDEX1( 2826): class j$.util.Optional class com.example.app.ApplicationBase Optional[com.example.app.ApplicationBase@9d006a00]
Which is called from the first line of launch()
.
If I add an Optional
to to the next line of the launch()
method, like so:
public void launch() throws IOException {
IOHandler ioHandler = new AndroidAppIOHandler(getApplicationContext());
final Optional<IOHandler> ioHandler1 = Optional.of(ioHandler);
...
then I see:
java.lang.NoClassDefFoundError: j$.util.Optional
on the same execution, after printing the other message above!
This was solved by upgrading to Android Gradle Build Plugin 4.2.0, where R8 desugars correctly.