datatrans/android-sdk

Twint classname clash between Datatrans & Adyen

jschmid opened this issue · 8 comments

We are trying to include both Datatrans & Adyen SDKs, and name clashes prevent us to do so.

To Reproduce
Include ch.datatrans:android-sdk:3.6.1 and com.adyen.checkout:drop-in:5.6.0 in the same project.
Try to compile the project. You get an error:

Execution failed for task ':app:checkDebugDuplicateClasses'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
   > Duplicate class a.a found in modules android-sdk-3.6.1.aar -> android-sdk-3.6.1-runtime (ch.datatrans:android-sdk:3.6.1) and twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0)
     Duplicate class a.b found in modules android-sdk-3.6.1.aar -> android-sdk-3.6.1-runtime (ch.datatrans:android-sdk:3.6.1) and twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0)
     Duplicate class ch.twint.payment.sdk.Twint found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-7.0.0.aar -> twint-sdk-android-7.0.0-runtime (ch.twint.payment:twint-sdk-android:7.0.0)
     Duplicate class ch.twint.payment.sdk.TwintPayResult found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-7.0.0.aar -> twint-sdk-android-7.0.0-runtime (ch.twint.payment:twint-sdk-android:7.0.0)
     Duplicate class ch.twint.payment.sdk.exceptions.TwintCodeEmptyOrBlankException found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-7.0.0.aar -> twint-sdk-android-7.0.0-runtime (ch.twint.payment:twint-sdk-android:7.0.0)
     Duplicate class ch.twint.payment.sdk.exceptions.TwintException found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-7.0.0.aar -> twint-sdk-android-7.0.0-runtime (ch.twint.payment:twint-sdk-android:7.0.0)
     Duplicate class ch.twint.payment.sdk.exceptions.TwintMethodCalledBeforeOnCreateException found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-7.0.0.aar -> twint-sdk-android-7.0.0-runtime (ch.twint.payment:twint-sdk-android:7.0.0)
     Duplicate class ch.twint.payment.sdk.exceptions.TwintResultPendingException found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-7.0.0.aar -> twint-sdk-android-7.0.0-runtime (ch.twint.payment:twint-sdk-android:7.0.0)

Expected behavior

It is possible to include Datatrans & Adyen SDKs in the same project, and use Twint.

Additional context

I have a repro project that shows the issue: https://github.com/jschmid/AdyenDatatransClash
This is the default Android Studio project, with only the dependencies added.

If you take commit jschmid/AdyenDatatransClash@ae250c5, you will see that it does not compile.

A workaround is to exclude the Adyen Twint library: jschmid/AdyenDatatransClash@29b9085
Excluding the Twint SDK that your publish under your Jfrog does not work as you have other class name clashes jschmid/AdyenDatatransClash@e1e0169 This was reported here #22 but not acknowledged by Datatrans.

However this exclusion does not work for us as we want to use Twint on both platforms.


I went down the rabbit hole and found this:

  • twint-5.6.0.aar from Adyen bundles the Twint SDK (it seems, as we don't have access to the Twint SDK). There are classes with package name ch.twint.payment.sdk.
  • twint-sdk-android-7.0.0.aar from Datatrans also packages a similar Twint SDK. (Some classes are the same, some are different)

We kindly request that you find a way to not clash with Twint classes. If you are going to keep publishing the Twint SDK under your own Jfrog, one solution would be to repackage the SDK under your own package, using Proguard repackageclasses.

Similar request on Adyen: Adyen/adyen-android#1701

Hello @jschmid,

About the a.b classes, we will repackage our SDK in the next release.

About TWINT you should exclude ours or Adyen's, unless you want to use TWINT in both SDKs at same time.

The way you can exclude from us is very simple:

implementation("ch.datatrans:android-sdk:3.6.1") {
    exclude("ch.twint.payment", "twint-sdk-android")
}

Although, we advise you to exclude the oldest version, which in this case, is Adyen's.

Thanks @luiscosta for the reply.

We do want to use both SDKs as the same time, as we present a different PSP based on a remote configuration.

I don't think it's a good idea to exclude one or another Twint SDKs like that. We have no way to know if there are compatibility issues.
We also have no definitive way to know which one is the most recent. You mention that Datatrans publishes a more recent version of the SDK. Adyen contains a jar "TwintSdk-android-8.0.0.jar" in the SDK and Datatrans publishes an aar called "twint-sdk-android-7.0.0.aar". This is a guessing game really.

In the end Twint should publish a canonical library on their own Maven repository. But I guess everyone knows that already 🫠

I'm going on vacation. Handing over the topic to my colleague @gtomek.

@jschmid @gtomek, this approach is not theoretically feasible. If our SDK requires version X of a dependency, and another SDK requires version Y of the same dependency, then an app can't add both SDKs without clashes. It doesn't matter if these versions are hosted by us or in a central repository managed by TWINT – there still can be only one version in the app and if X and Y are incompatible it would not work.

In practice, TWINT SDK updates are relatively infrequent. So you might get lucky with both SDKs using the same TWINT version. But it is not a stable construct.

In release 3.7.0 you mention that this bug is fixed. That is not true.

You still use your own dependency published at https://datatrans.jfrog.io/ui/native/mobile-sdk/ch/twint/payment/twint-sdk-android/8.0.0/

I have updated my repro project with version 3.7.0. We still get the same name clashes:

Duplicate class ch.twint.payment.sdk.Twint found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-8.0.0.jar -> twint-sdk-android-8.0.0 (ch.twint.payment:twint-sdk-android:8.0.0)
Duplicate class ch.twint.payment.sdk.TwintPayResult found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-8.0.0.jar -> twint-sdk-android-8.0.0 (ch.twint.payment:twint-sdk-android:8.0.0)
Duplicate class ch.twint.payment.sdk.exceptions.TwintCodeEmptyOrBlankException found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-8.0.0.jar -> twint-sdk-android-8.0.0 (ch.twint.payment:twint-sdk-android:8.0.0)
Duplicate class ch.twint.payment.sdk.exceptions.TwintException found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-8.0.0.jar -> twint-sdk-android-8.0.0 (ch.twint.payment:twint-sdk-android:8.0.0)
Duplicate class ch.twint.payment.sdk.exceptions.TwintMethodCalledBeforeOnCreateException found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-8.0.0.jar -> twint-sdk-android-8.0.0 (ch.twint.payment:twint-sdk-android:8.0.0)
Duplicate class ch.twint.payment.sdk.exceptions.TwintResultPendingException found in modules twint-5.6.0.aar -> twint-5.6.0-runtime (com.adyen.checkout:twint:5.6.0) and twint-sdk-android-8.0.0.jar -> twint-sdk-android-8.0.0 (ch.twint.payment:twint-sdk-android:8.0.0)

The two issues are unrelated. Issue #22 is about the repackaging of our SDK classes. However, the TWINT SDK is an external dependency provided by TWINT and has nothing to do with that.

As mentioned before, your approach does not work in theory, no matter how the TWINT SDK is obtained. In practice you can just try to exclude one of the TWINT SDKs as shown by @luiscosta above. Currently this should work because Adyen and Datatrans are both using TWINT 8.0 (at the moment!).

For the record, I now tried to exclude one of the two Twint SDK, and it compiles fine. I have not tried running in though. We will not do that in prod as it is obviously too risky.

Let's wait for Twint to publish their own artifact now...

I know this won't fix the clashing Twint SDK version. One thing at a time... 🙂

As far as risk is concerned, it is the same thing whether Twint publishes the SDK itself or not. Both SDKs depend on TWINT 8.0 at the moment, so for the current payment SDK versions you can run it in prod if you want. Our SDK checks if TWINT is on the classpath to enable TWINT flows. If TWINT 8.0 is added to your app via Adyen it will automatically work for Datatrans.