stripe / stripe-terminal-android

Stripe Terminal Android SDK
https://stripe.dev/stripe-terminal-android/
Other
93 stars 45 forks source link

App crashes during the discovery for local mobile (TTP) #504

Closed TatsuUkraine closed 1 month ago

TatsuUkraine commented 1 month ago

Summary

Android app fails with the exception during the local mobile reader discovery process

Code to reproduce

Android version

Android 14

Impacted devices (Android devices or readers)

Pixel 6-8, Galaxy S*, overall it seems there are quite a lot different devices are affected

SDK version

Able to reproduce with 3.8.0 and 3.9.2

With 3.7.x all works fine

Other information

          Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: DiscoveryException(message: Contactless transaction failed com.stripe.core.aidlrpc.AidlRpcException: Service never connected., details: com.stripe.stripeterminal.external.models.TerminalException: Contactless transaction failed com.stripe.core.aidlrpc.AidlRpcException: Service never connected.
    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter.callAidlWithExceptionConverted(CotsAdapter.kt:689)
    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter.access$callAidlWithExceptionConverted(CotsAdapter.kt:86)
    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter$DiscoverReadersOperation.execute(CotsAdapter.kt:702)
    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter$DiscoverReadersOperation.execute(CotsAdapter.kt:697)
    at com.stripe.stripeterminal.internal.common.adapter.CotsAdapter.discoverReaders(CotsAdapter.kt:513)
    at com.stripe.stripeterminal.internal.common.adapter.ProxyAdapter.discoverReaders(ProxyAdapter.kt:249)
    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$DiscoverReadersOperation.executeIfNotCanceled(TerminalSession.kt:2292)
    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$CancelableOperation.execute(TerminalSession.kt:1272)
    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$ExternalOperation.run$terminalsession_release(TerminalSession.kt:1228)
    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession.enqueueOperation$lambda$6(TerminalSession.kt:1042)
    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession.$r8$lambda$9_FdDGpM1BaifeFRjKBBfCCLP6o(Unknown Source:0)
    at com.stripe.stripeterminal.internal.common.terminalsession.TerminalSession$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:487)
    at java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.<truncated: 146 chars>
sidhant-stripe commented 1 month ago

Hi @TatsuUkraine, thanks for reporting. What target SDK version are you using? We recommend that you use 34, and we are aware of an issue when using target SDK 35.

Are you able to reproduce this error on a device you have access to? Any other errors from logcat would be helpful in diagnosing this issue.

TatsuUkraine commented 1 month ago

@sidhant-stripe hi, target sdk is set to 34 currently, as for more details, I will see what I can do. This issue can be reproduced only when you do do discovery with simulator off. Which means it can't be done in debug builds. But I will see what additional info I can get

TatsuUkraine commented 1 month ago

@sidhant-stripe

FATAL EXCEPTION: main
                                                                                                    Process: com.***.test:stripelocalmobile, PID: 7060
                                                                                                    java.lang.RuntimeException: Unable to bind to service com.stripe.cots.aidlservice.CotsService@1fda0a1 with Intent { act= cmp=com.***.test/com.stripe.cots.aidlservice.CotsService }: java.lang.ClassCastException: java.util.Optional cannot be cast to j$.util.Optional
                                                                                                        at android.app.ActivityThread.handleBindService(ActivityThread.java:4957)
                                                                                                        at android.app.ActivityThread.-$$Nest$mhandleBindService(Unknown Source:0)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2415)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:107)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:232)
                                                                                                        at android.os.Looper.loop(Looper.java:317)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8592)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)
                                                                                                    Caused by: java.lang.ClassCastException: java.util.Optional cannot be cast to j$.util.Optional
                                                                                                        at com.stripe.jvmcore.client.dagger.HttpClientBaseModule_ProvideHttpClientFactory.get(HttpClientBaseModule_ProvideHttpClientFactory.java:55)
                                                                                                        at com.stripe.jvmcore.client.dagger.HttpClientBaseModule_ProvideHttpClientFactory.get(HttpClientBaseModule_ProvideHttpClientFactory.java:17)
                                                                                                        at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
                                                                                                        at com.s.x.BuildS23328.Billing(:49)
                                                                                                        at com.s.x.BuildS23328.get(:14)
                                                                                                        at com.s.x.BillingP11527.Dashboard(:36)
                                                                                                        at com.s.x.BillingP11527.get(:13)
                                                                                                        at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
                                                                                                        at com.s.x.DashboardU11264.Build(:42)
                                                                                                        at com.s.x.DashboardU11264.get(:14)
                                                                                                        at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
                                                                                                        at com.s.af.DashboardV16708.Dashboard(:61)
                                                                                                        at com.s.af.DashboardV16708.get(:17)
                                                                                                        at com.s.s.BuildR26798.Dashboard(:42)
                                                                                                        at com.s.s.BuildR26798.get(:14)
                                                                                                        at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
                                                                                                        at com.s.s.BillingG22511.Build(:37)
                                                                                                        at com.s.s.BillingG22511.get(:13)
                                                                                                        at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
                                                                                                        at com.s.s.ConnectW16626.Billing(:42)
                                                                                                        at com.s.s.ConnectW16626.get(:14)
                                                                                                        at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
                                                                                                        at com.s.u.experienceP17930$BuildX25728.Billing(:719)
                                                                                                        at com.stripe.cots.aidlservice.CotsService$AsF16.invokeSuspend(:96)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
                                                                                                        at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:111)
                                                                                                        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:811)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:715)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:702)
TatsuUkraine commented 1 month ago

Here is our app Gradle config

android {
    compileSdk 34
    ndkVersion "25.1.8937393"

    compileOptions {
        coreLibraryDesugaringEnabled true

        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = '17'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        ...
        minSdkVersion 26
        targetSdkVersion 34

   ....
    }
}

dependencies {
    ...
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2'
}

And Gradle for plugin that contains terminal sdk we have this

android {
    if (project.android.hasProperty('namespace')) {
        namespace 'com.stripe_terminal.stripe_terminal_sdk_android'
    }

    compileSdkVersion 34

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    defaultConfig {
        minSdkVersion 26
    }
}

def terminalAndroidSdkVersion = "3.8.0"
dependencies {
    implementation "com.stripe:stripeterminal:$terminalAndroidSdkVersion"
    implementation "com.stripe:stripeterminal-localmobile:$terminalAndroidSdkVersion"
}
TatsuUkraine commented 1 month ago

so far it looks to me that the main issue here is that stripe terminal SDK conflicts with desugar_jdk_libs v1.2.2, where the support of Optional class was introduced, which leads to class conflicts in the stripe terminal sdk

sidhant-stripe commented 1 month ago

Thanks for the additional info! Does it work without desugaring? My understanding is that desugaring is not necessary if your minSdk is set to 26. Would that be an option for you?

TatsuUkraine commented 1 month ago

It's required for a different third-party package, at least according to its docs

TatsuUkraine commented 1 month ago

@sidhant-stripe For now I did update desugaring sdk up to v2.1.2, which it seems fixed runtime exceptions on stripe terminal sdk. But I'm not 100% sure that it was right solution though)

TatsuUkraine commented 1 month ago

But you may be right, that with our min sdk we actually no need desugaring 🤔

sidhant-stripe commented 1 month ago

Thanks for the update. Sounds like this issue is resolved, please feel free to open a new one with any further issues!