datatrans / android-sdk

Accept payments on your Android apps: Our mobile SDKs support your entire payment and registration process and simplify the integration of any payment method in your mobile apps.
Other
6 stars 0 forks source link

Twint classname clash between Datatrans & Adyen #25

Open jschmid opened 1 month ago

jschmid commented 1 month ago

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 https://github.com/jschmid/AdyenDatatransClash/commit/ae250c504d71f77f5cf7a1fa8c4fe5d1ba2b9473, you will see that it does not compile.

A workaround is to exclude the Adyen Twint library: https://github.com/jschmid/AdyenDatatransClash/commit/29b908538fa1124d5fae8c7c27cb8bcbb8d98875 Excluding the Twint SDK that your publish under your Jfrog does not work as you have other class name clashes https://github.com/jschmid/AdyenDatatransClash/commit/e1e0169695278cef947b093a33ea59812a544abe This was reported here https://github.com/datatrans/android-sdk/issues/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:

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: https://github.com/Adyen/adyen-android/issues/1701

luiscosta commented 1 month ago

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.

jschmid commented 1 month ago

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 🫠

jschmid commented 1 month ago

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

bacherma commented 1 month ago

@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.

jschmid commented 1 week ago

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)
bacherma commented 1 day ago

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!).

jschmid commented 1 day ago

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... 🙂

bacherma commented 1 day ago

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.