Description
AdyenPaymentPackage.messageBus is a static companion getter that throws when _messageBus is null:
// AdyenPaymentPackage.kt:53
val messageBus: MessageBus
get() = _messageBus ?: throw IllegalStateException("AdyenCheckout MessageBus is not initialized")
_messageBus is only populated in createNativeModules() (via getOrCreateMessageBus), i.e. when the React Native bridge initializes. However, AdvancedCheckoutService is an Android bound DropInService that the OS can recreate after process death independently of the RN bridge. When it delivers a pending result it calls the throwing getter unconditionally:
// AdvancedCheckoutService.kt (identical in 2.9.1 and current 2.11.1)
override fun onAdditionalDetails(actionComponentData: ActionComponentData) {
AdyenPaymentPackage.messageBus.onAdditionalDetails(actionComponentData) // <-- throws if bus is null
}
So if Android kills the app process during a 3DS additional-details step (e.g. while the user is redirected to a bank app/browser), the restored DropInActivity rebinds the service and calls onAdditionalDetails before RN has re-initialized, and the app crashes.
Stack trace
java.lang.IllegalStateException
at com.adyenreactnativesdk.AdyenPaymentPackage$Companion.getMessageBus (AdyenPaymentPackage.kt:53)
at com.adyenreactnativesdk.component.dropin.AdvancedCheckoutService.onAdditionalDetails (AdvancedCheckoutService.kt:31)
at com.adyen.checkout.dropin.DropInService.requestDetailsCall (DropInService.kt:36)
at com.adyen.checkout.dropin.internal.ui.DropInActivity.requestDetailsCall (DropInActivity.kt:250)
at com.adyen.checkout.dropin.internal.ui.DropInActivity$serviceConnection$1.onServiceConnected (DropInActivity.kt:115)
at android.app.LoadedApk$ServiceDispatcher.doConnected (LoadedApk.java:2325)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run (LoadedApk.java:2362)
at android.os.Handler.handleCallback (Handler.java:959)
at android.os.Handler.dispatchMessage (Handler.java:100)
at android.os.Looper.loopOnce (Looper.java:257)
at android.os.Looper.loop (Looper.java:342)
at android.app.ActivityThread.main (ActivityThread.java:9638)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:619)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:929)
Steps to reproduce
- Start an advanced-flow card payment and reach a 3DS challenge/redirect (
onAdditionalDetails).
- While the app is backgrounded (e.g. redirected to a bank app/browser), force process death:
adb shell am kill <package>, or Developer Options → "Don't keep activities", or apply memory pressure.
- Return to the app. The OS restores
DropInActivity → rebinds the service → onAdditionalDetails fires before RN re-initializes → crash.
Expected behavior
The SDK should not crash when the message bus is unavailable after process death. It should dismiss the drop-in / surface a recoverable error so the user can retry.
Actual behavior
IllegalStateException: AdyenCheckout MessageBus is not initialized crashes the app.
Environment
@adyen/react-native: 2.9.1 — the offending code path is also present in 2.11.1 (verified against the 2.11.1 tag)
react-native: 0.79.6 (New Architecture / bridgeless)
- Platform: Android
- Flow: Advanced (
AdvancedCheckoutService)
Suggested fix
The SDK already exposes internal fun messageBusOrNull(): MessageBus?. The *CheckoutService callbacks (onAdditionalDetails, onSubmit, onBalanceCheck, onOrderRequest, …) could use it and, when null, dismiss via DropInServiceResult.Error(dismissDropIn = true) instead of dereferencing the throwing getter — for both AdvancedCheckoutService and SessionCheckoutService. This is the same "restore DropIn after app gets killed" scenario tracked in Adyen/adyen-android#151.
Description
AdyenPaymentPackage.messageBusis a static companion getter that throws when_messageBusis null:_messageBusis only populated increateNativeModules()(viagetOrCreateMessageBus), i.e. when the React Native bridge initializes. However,AdvancedCheckoutServiceis an Android boundDropInServicethat the OS can recreate after process death independently of the RN bridge. When it delivers a pending result it calls the throwing getter unconditionally:So if Android kills the app process during a 3DS additional-details step (e.g. while the user is redirected to a bank app/browser), the restored
DropInActivityrebinds the service and callsonAdditionalDetailsbefore RN has re-initialized, and the app crashes.Stack trace
Steps to reproduce
onAdditionalDetails).adb shell am kill <package>, or Developer Options → "Don't keep activities", or apply memory pressure.DropInActivity→ rebinds the service →onAdditionalDetailsfires before RN re-initializes → crash.Expected behavior
The SDK should not crash when the message bus is unavailable after process death. It should dismiss the drop-in / surface a recoverable error so the user can retry.
Actual behavior
IllegalStateException: AdyenCheckout MessageBus is not initializedcrashes the app.Environment
@adyen/react-native: 2.9.1 — the offending code path is also present in 2.11.1 (verified against the2.11.1tag)react-native: 0.79.6 (New Architecture / bridgeless)AdvancedCheckoutService)Suggested fix
The SDK already exposes
internal fun messageBusOrNull(): MessageBus?. The*CheckoutServicecallbacks (onAdditionalDetails,onSubmit,onBalanceCheck,onOrderRequest, …) could use it and, when null, dismiss viaDropInServiceResult.Error(dismissDropIn = true)instead of dereferencing the throwing getter — for bothAdvancedCheckoutServiceandSessionCheckoutService. This is the same "restore DropIn after app gets killed" scenario tracked in Adyen/adyen-android#151.