Android Gradle Build 插件 4.0.0 和 R8 脱糖在 API 19 上不起作用

Android Gradle Build Plugin 4.0.0 & R8 Desugaring not working on API 19

提问人:Fraser 提问时间:9/1/2020 最后编辑:Fraser 更新时间:4/11/2023 访问量:5738

问:

我正在将 Android 应用程序从使用 Proguard 的脱糖切换到 Android Gradle Build Plugin 4.0.0 中提供的新 R8 脱糖。

我已经按照官方文档中详述的步骤启用了 Java 8 库脱糖:

gradle.properties

projectJavaVersion = 1.8
android.useAndroidX=true
android.enableJetifier=true

应用 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"
    ...
}

您可以看到,我们至少支持 API 19。没有构建错误(使用 Gradle 6.1.1),但存在以下警告:

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()`

当我运行应用程序时,在代码中启动具有以下 Optional 的 Activity,应用程序崩溃并出现

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)

应用程序库:.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");
    ...
  }
  ...
}

我错过了什么?


在阅读了@sgjesse的答案后,我们做了一些进一步的调查,这似乎只是方法的问题。我可以确认之前正在调用。launch()MultiDex.install()launch()

如果我添加一个 ,如下所示:OptionalAndroidAppIoHandler

public AndroidAppIOHandler(Context context) {
  this.context = context;
  final Optional<Context> context1 = Optional.of(context);
  Log.d("TESTMULTIDEX1", context1.getClass() + "  " + context1.get().getClass() + " " + context1.toString());
}

然后我明白了:

D/TESTMULTIDEX1( 2826): class j$.util.Optional  class com.example.app.ApplicationBase Optional[com.example.app.ApplicationBase@9d006a00]

这是从 的第一行调用的。launch()

如果我在方法的下一行添加一个 to,如下所示:Optionallaunch()

public void launch() throws IOException {
  IOHandler ioHandler = new AndroidAppIOHandler(getApplicationContext());
  final Optional<IOHandler> ioHandler1 = Optional.of(ioHandler);
  ...

然后我明白了:

java.lang.NoClassDefFoundError: j$.util.Optional

在同一次执行中,打印完上面的另一条消息!

安卓 java-8 android-gradle-plugin android-r8 JDK-脱糖

评论

0赞 dev.bmax 9/1/2020
你试过用它吗?minifyEnabled false
0赞 Fraser 9/2/2020
同样的事情发生在 @dev.bmax 上minifyEnabled false
0赞 Daniil Popov 9/4/2020
我面临同样的问题。你找到答案了吗?
0赞 Fraser 9/7/2020
还没有答案,@DaniilPopov
1赞 sgjesse 9/7/2020
首先,仅在 API 级别为 19 的设备上崩溃吗?如果是这样,可能是在使用脱糖类型之前未调用 the。例如,作为 (在单独的 DEX 文件中调用,必须在不支持本机多 DEX(为 API 级别 21 添加)的设备上调用。在调用中,在 .如果在之前调用该方法,您将看到 .MultiDex.installjava.util.Optionalj$.util.OptionMultiDex.installMultiDexApplicationMultiDex.installattachBaseContextlaunchMultiDex.installNoClassDefFoundError

答:

0赞 sgjesse 9/8/2020 #1

如果仅在 API 级别为 19 的设备上看到崩溃,原因可能是在使用脱糖类型之前未调用 。MultiDex.install

的实现(在脱糖库中调用)位于单独的 DEX 文件中。在不支持本机 multi dex(在 API 级别 21 中添加)的设备上,必须先调用,然后才能使用脱糖类型。在调用中,在 .如果在之前调用该方法,您将看到 .java.util.Optionalj$.util.OptionalMultiDex.installMultiDexApplicationMultiDex.installattachBaseContextlaunchMultiDex.installNoClassDefFoundError

评论

0赞 Fraser 9/9/2020
嘿,请查看我对问题的补充 - 我们根据您的回答进行了一些调查,不幸的是,在启动方法之前调用了 Multidex.install。此外,我们还看到了一些奇怪的现象,如果 Optionals 在 API 19 中的不同对象中使用,则它们会起作用,但当它们直接用于 ...launchlaunch()
1赞 Daniil Popov 9/8/2020 #2

我遇到了一个非常相似的问题,就我而言,事实证明这是 Android Gradle 插件中的一个错误。长话短说,AGP 在不同的 DEX 文件中生成了一些相同的包装类,这些类在旧的 Android 版本上吹起了 Dalvik/ART。问题只出在调试版本上,因为 R8/ProGuard 在发布版本中对该类进行了重复数据删除。

该问题有一个解决方法

buildscript {

    repositories {
        maven {
            url "https://storage.googleapis.com/r8-releases/raw/master" // NOTICE 'master' here!
        }
    }

    dependencies {
        classpath 'com.android.tools:r8:f03be11f11b8405b69876d05337e917a5519e52a'  // Must be before the Gradle Plugin for Android.
        classpath 'com.android.tools.build:gradle:X.Y.Z'     // Your current AGP version.
     }
}

希望这对您有所帮助。

评论

0赞 Fraser 9/9/2020
不幸的是,这并不能解决问题,但无论如何都要感谢你!
0赞 Daniil Popov 9/9/2020
很抱歉听到这个:(
2赞 user3166372 3/23/2021 #3

我在旧版应用程序上遇到了同样的问题,它仍然支持 Android 4.1。在我创建了一个示例项目并尝试重现错误后,我发现了问题(或错误?

不幸的是,4.4 或更低版本的 Android 设备似乎无法使用任何 Java 8 类或接口,这些类或接口将被应用程序的 onCreate 方法中的 Core Library Desugaring 触及。

这似乎是一个奇怪的多重问题/错误。

我尝试了以下方法:

class CoreApplication : MultiDexApplication() {
    override fun attachBaseContext(base: Context?) {
        //adding the new GMS causes to many Methods in APK, therefore configure Application as MultiDex
        super.attachBaseContext(base)
        MultiDex.install(this)
    }

    override fun onCreate() {
        super.onCreate()
        Optional.of("TEst")
    }
}

这将导致您提到的崩溃:

03-22 18:36:09.231 657-657/com.plauzeware.CoreLibraryDesugeringCrashOnAndroidKitkat E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.plauzeware.CoreLibraryDesugeringCrashOnAndroidKitkat, PID: 657
    java.lang.NoClassDefFoundError: j$.util.Optional
        at com.plauzeware.corelibrarydesugeringcrashonandroidkitkat.CoreApplication.onCreate(Application.kt:17)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1030)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4409)
        at android.app.ActivityThread.access$1500(ActivityThread.java:139)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1270)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5086)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
        at dalvik.system.NativeStart.main(Native Method)

但是当我将对 Optional 的调用包装在帮助程序类中时

class Loader {
    companion object {
        fun load() {
            Optional.of("TEst")
        }
    }
}

并在我的 onCreate 函数中调用它

class CoreApplication : MultiDexApplication() {
    override fun attachBaseContext(base: Context?) {
        //adding the new GMS causes to many Methods in APK, therefore configure Application as MultiDex
        super.attachBaseContext(base)
        MultiDex.install(this)
    }

    override fun onCreate() {
        super.onCreate()
        Loader.load()
    }
}

它会起作用的。我认为这是一个错误,我将提交错误报告,并使用指向它的链接更新此答案。

因为多重问题也触及了基本接口,就像解决这些错误真的很痛苦一样。特别是因为我们仍然使用OrmLite,并且它将一直使用。IterableIterable

我已经添加了我的代码以参考我的 Github

更新:

这是错误报告的链接。

评论

1赞 Fraser 3/23/2021
谢谢,这是一个很好的解释。非常感谢您的时间和精力!
1赞 Fraser 11/8/2021 #4

通过升级到 Android Gradle Build 插件 4.2.0 解决了这个问题,其中 R8 可以正确脱糖。

1赞 Leonardo Sibela 4/11/2023 #5

我更新了与此表对应的版本com.android.tools.build:gradle