Skip to content

Commit

Permalink
Document problems with building coroutines-using Android projects (#2288
Browse files Browse the repository at this point in the history
)

Added instructions to work around #2023 
Also, the answer to #2274 is now documented.

Co-authored-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
  • Loading branch information
dkhalanskyjb and qwwdfsad committed Oct 9, 2020
1 parent 20ca97a commit b82439e
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Expand Up @@ -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
Expand Down
92 changes: 92 additions & 0 deletions kotlinx-coroutines-debug/README.md
Expand Up @@ -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
Expand Down

0 comments on commit b82439e

Please sign in to comment.