diff options
author | dkhalanskyjb <52952525+dkhalanskyjb@users.noreply.github.com> | 2020-10-09 12:01:05 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-09 12:01:05 +0300 |
commit | b82439e6b570249cfbd25622dc06cb0ec156c006 (patch) | |
tree | 9f53172b2dc5dcb03d2778227b96898dc1e92ad8 | |
parent | 20ca97ad47adc249c6211ad9d12e31f1074984d7 (diff) | |
download | kotlinx.coroutines-b82439e6b570249cfbd25622dc06cb0ec156c006.tar.gz |
Document problems with building coroutines-using Android projects (#2288)
Added instructions to work around #2023
Also, the answer to #2274 is now documented.
Co-authored-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
-rw-r--r-- | README.md | 11 | ||||
-rw-r--r-- | kotlinx-coroutines-debug/README.md | 92 |
2 files changed, 103 insertions, 0 deletions
@@ -176,6 +176,17 @@ threads are handled by Android runtime. R8 and ProGuard rules are bundled into the [`kotlinx-coroutines-android`](ui/kotlinx-coroutines-android) module. For more details see ["Optimization" section for Android](ui/kotlinx-coroutines-android/README.md#optimization). +#### Avoiding including the debug infrastructure in the resulting APK + +The `kotlinx-coroutines-core` artifact contains a resource file that is not required for the coroutines to operate +normally and is only used by the debugger. To exclude it at no loss of functionality, add the following snippet to the +`android` block in your gradle file for the application subproject: +```groovy +packagingOptions { + exclude "DebugProbesKt.bin" +} +``` + ### JS [Kotlin/JS](https://kotlinlang.org/docs/reference/js-overview.html) version of `kotlinx.coroutines` is published as diff --git a/kotlinx-coroutines-debug/README.md b/kotlinx-coroutines-debug/README.md index 7c4501ab..1278ed13 100644 --- a/kotlinx-coroutines-debug/README.md +++ b/kotlinx-coroutines-debug/README.md @@ -170,6 +170,98 @@ java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/Mana at kotlinx.coroutines.debug.DebugProbes.install(DebugProbes.kt:49) --> +#### Build failures due to duplicate resource files + +Building an Android project that depends on `kotlinx-coroutines-debug` (usually introduced by being a transitive +dependency of `kotlinx-coroutines-test`) may fail with `DuplicateRelativeFileException` for `META-INF/AL2.0`, +`META-INF/LGPL2.1`, or `win32-x86/attach_hotspot_windows.dll` when trying to merge the Android resource. + +The problem is that Android merges the resources of all its dependencies into a single directory and complains about +conflicts, but: +* `kotlinx-coroutines-debug` transitively depends on JNA and JNA-platform, both of which include license files in their + META-INF directories. Trying to merge these files leads to conflicts, which means that any Android project that + depends on JNA and JNA-platform will experience build failures. +* Additionally, `kotlinx-coroutines-debug` embeds `byte-buddy-agent` and `byte-buddy`, along with their resource files. + Then, if the project separately depends on `byte-buddy`, merging the resources of `kotlinx-coroutines-debug` with ones + from `byte-buddy` and `byte-buddy-agent` will lead to conflicts as the resource files are duplicated. + +One possible workaround for these issues is to add the following to the `android` block in your gradle file for the +application subproject: +```groovy + packagingOptions { + // for JNA and JNA-platform + exclude "META-INF/AL2.0" + exclude "META-INF/LGPL2.1" + // for byte-buddy + exclude "META-INF/licenses/ASM" + pickFirst "win32-x86-64/attach_hotspot_windows.dll" + pickFirst "win32-x86/attach_hotspot_windows.dll" + } +``` +This will cause the resource merge algorithm to exclude the problematic license files altogether and only leave a single +copy of the files needed for `byte-buddy-agent` to work. + +Alternatively, avoid depending on `kotlinx-coroutines-debug`. In particular, if the only reason why this library a +dependency of your project is that `kotlinx-coroutines-test` in turn depends on it, you may change your dependency on +`kotlinx.coroutines.test` to exclude `kotlinx-coroutines-debug`. For example, you could replace +```kotlin +androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version") +``` +with +```groovy +androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version") { + exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-debug" +} +``` +<!--- +Snippets of stacktraces for googling: + +org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugAndroidTestJavaResource'. + ... +Caused by: org.gradle.workers.intelrnal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade + ... +Caused by: com.android.builder.merge.DuplicateRelativeFileException: More than one file was found with OS independent path 'META-INF/AL2.0'. + at com.android.builder.merge.StreamMergeAlgorithms.lambda$acceptOnlyOne$2(StreamMergeAlgorithms.java:85) + at com.android.builder.merge.StreamMergeAlgorithms.lambda$select$3(StreamMergeAlgorithms.java:106) + at com.android.builder.merge.IncrementalFileMergerOutputs$1.create(IncrementalFileMergerOutputs.java:88) + at com.android.builder.merge.DelegateIncrementalFileMergerOutput.create(DelegateIncrementalFileMergerOutput.java:64) + at com.android.build.gradle.internal.tasks.MergeJavaResourcesDelegate$run$output$1.create(MergeJavaResourcesDelegate.kt:230) + at com.android.builder.merge.IncrementalFileMerger.updateChangedFile(IncrementalFileMerger.java:242) + at com.android.builder.merge.IncrementalFileMerger.mergeChangedInputs(IncrementalFileMerger.java:203) + at com.android.builder.merge.IncrementalFileMerger.merge(IncrementalFileMerger.java:80) + at com.android.build.gradle.internal.tasks.MergeJavaResourcesDelegate.run(MergeJavaResourcesDelegate.kt:276) + at com.android.build.gradle.internal.tasks.MergeJavaResRunnable.run(MergeJavaResRunnable.kt:81) + at com.android.build.gradle.internal.tasks.Workers$ActionFacade.run(Workers.kt:242) + at org.gradle.workers.internal.AdapterWorkAction.execute(AdapterWorkAction.java:50) + at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:50) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:63) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:59) + at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:98) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:59) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41) + at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416) + at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406) + at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) + at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) + at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) + at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102) + at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36) + at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:53) + at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$2(DefaultWorkerExecutor.java:200) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:215) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:131) + +Execution failed for task ':app:mergeStagingDebugAndroidTestJavaResource'. +Execution failed for task ':app:mergeDebugAndroidTestJavaResource'. +Execution failed for task ':app:mergeDebugTestJavaResource' + +More than one file was found with OS independent path 'META-INF/LGPL2.1' +More than one file was found with OS independent path 'win32-x86/attach_hotspot_windows.dll' +More than one file was found with OS independent path 'win32-x86-64/attach_hotspot_windows.dll' +--> <!--- MODULE kotlinx-coroutines-core --> <!--- INDEX kotlinx.coroutines --> [Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html |