#harish-patel_error
1 messages ยท Page 1 of 1 (latest)
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1399818453472383016
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
hello! we're not familiar with olo pay and as such our ability to help troubleshoot issues with it may be limited. have you checked with olo pay directly yet?
you can see some examples of how PaymentConfiguration.init() should be called in our docs here:
https://docs.stripe.com/payments/accept-a-payment?platform=android#android-collect-payment-details
from the code snippet you shared (included below) it does look like PaymentConfiguration.init() is only called conditionally, is it possible that it's not being set for these customers?
try {
val publishableKey = Storage(context).getPublishableKey(environment)
IOloPayApiInitializer.environment = environment
if (publishableKey.isNullOrEmpty()) {
OloPayAPI.updatePublishableKey(context)
} else {
PaymentConfiguration.init(context, publishableKey)
}
} catch (e: Exception) {
// Swallow this... if setting the publishable key fails on init, the SDK will attempt
// to set it when creating a payment method, at which point an appropriate error
// will be generated
}```
It is called in the else loop.
companion object {
private const val JSON_TOKEN_KEY = "key"
internal suspend fun updatePublishableKey(context: Context) {
withContext(Dispatchers.IO) {
runCatching {
val url = context.getString(IOloPayApiInitializer.publishableKeyResource)
val response = java.net.URL(url).readText()
val json = JSONTokener(response).nextValue() as JSONObject
val publishableKey = json.getString(JSON_TOKEN_KEY)
Storage(context).setPublishableKey(IOloPayApiInitializer.environment, publishableKey)
PaymentConfiguration.init(context, publishableKey)
}
}
}
}
Hello
As solanum suggested above, have you tried talking to OloPay folks to see if this is a bug in their SDK?
Or do you own/develop the OloPay SDK?
We have many orders going successfully daily. But we do see this exception a lot. Could it be because we initialize OloPay SDK durin startup initializer / MainActivity.onCreate.
Coul this get stale fore some reason after a long time?
I have contacted Olo support as well
Maybe? We're not familiar with OloPay SDK since it's third-party so we can't know how they're wrapping Stripe SDK
This is something you'd need to work out with Olo support unfortunately
We have no visiblity into their integration
intermittent failures are the main reason for this issue.
I have looked both source code snippets. I believe your devs may want to look at how they are using ready callback. It is I believe Android sartActivity forResult type of issue.
Hmm I checked internally and I'm not seeing many instances of this error being reported when integrated with our own SDK directly.
I suspect this is likely a bug within OloPay's wrapper that's calling some function from the SDK without properly initializing OR some reference getting cleaned up when it's not supposed to..
If Olo support pushes back OR provides more actionable details about how this could be some edge case/bug w/ Stripe's SDK, we'd love to dig. You can also re-open the Github issue in that case.
Right now though, all things point to this being an OloPay issue
This is confusing part. Here is the crash log. As you can see it is coming from another Stripe SDK UI thread.
Fatal Exception: java.lang.IllegalStateException: PaymentConfiguration was not initialized. Call PaymentConfiguration.init().
at com.stripe.android.PaymentConfiguration$Companion.loadInstance(PaymentConfiguration.java:78)
at com.stripe.android.PaymentConfiguration$Companion.getInstance(PaymentConfiguration.java:70)
at com.stripe.android.view.CardWidgetViewModel$Factory.create$lambda$1(CardWidgetViewModel.java:84)
at com.stripe.android.view.CardWidgetViewModel.determineCbcEligibility(CardWidgetViewModel.kt:58)
at com.stripe.android.view.CardWidgetViewModel.access$determineCbcEligibility(CardWidgetViewModel.kt:29)
at com.stripe.android.view.CardWidgetViewModel$getEligibility$1.invokeSuspend(CardWidgetViewModel.kt:53)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:124)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:89)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.java:586)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:820)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:717)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:704)
The only thing I can think of is that most implementations are doig the .init() call just prior to doig the checkout. Whereas we are usimg Olo's Startup Initializer and this .init() call is made there.
Yeah but PaymentConfiguration doesn't rely on any tokens/objects that are invalidated in short time. For example: https://docs.stripe.com/payments/accept-a-payment?platform=android#android-collect-payment-details:~:text=publishable key using-,PaymentConfiguration,-and store the
Like you'd pass activity context and publishable key to the initializer. So it's possible that the context they're calling this function from is getting cleared out at some point (when activity gets destroyed), in which case you'd need to call this initializer again.
I will ask Olo support. But one thing looking at how we initialize OLO is using Android's Initializer class.
So, Android must be passing the Application context here.
AndroidManifest.xml:
...
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="com.mobile.potbelly.startup.AppStartupInitializer"
android:value="androidx.startup" />
class AppStartupInitializer : Initializer<Unit> {
override fun create(context: Context) {}
override fun dependencies(): List<Class<out Initializer<*>>> =
listOf(
KoinStartupInitializer::class.java,
OloPayStartupInitializer::class.java,
BrazeStartupInitializer::class.java,
)
}
class OloPayStartupInitializer : Initializer<Unit> {
override fun create(context: Context) {
runBlocking {
initialize(context) {
BaseViewModel.paymentInitializationFailed = false
}
}
}
private fun initialize(context: Context, callback: () -> Unit) {
val buildConfigProvider = BuildConfigProviderImpl()
OloPayApiInitializer().setup(
context = context,
environment = if (buildConfigProvider.isProductionReleaseBuild) OloPayEnvironment.Production else OloPayEnvironment.Test,
object : InitCompleteCallback {
override fun onComplete() {
callback()
}
})
}
override fun dependencies(): List<Class<out Initializer<*>>> =
listOf(
KoinStartupInitializer::class.java,
)
}
Yup, sounds about right
So, what Stripe SDK is this CardWidgetViewModel part of? Essentially, here is the second thread.
On MainActivity.onCreate(), we start this flow:
onCreate() {
call googlePaySetup()
}
Here is the code for that.
private fun googlePaySetup() {
try {
// Init launcher
BaseViewModel.paymentInitializationFailed = false
googlePayLauncher = GooglePayLauncher(
activity = this,
config = GooglePayConfig(
environment = if (buildConfigProvider.isProductionReleaseBuild) {
GooglePayEnvironment.Production
} else {
GooglePayEnvironment.Test
},
companyName = resources.getString(R.string.app_name),
),
)
googlePayLauncher?.readyCallback = GooglePayReadyCallback { isReady ->
isGooglePayReady.value = isReady
}
CoroutineScope(Dispatchers.IO).launch {
BaseViewModel.googlePay.collect {
googlePayLauncher?.resultCallback = it.resultCallback
if (googlePayLauncher?.isReady == true) {
googlePayLauncher?.present(
(it.amount * 100).toInt(),
checkoutStatus = it.status,
)
}
}
}
} catch (e: Exception) {
BaseViewModel.paymentInitializationFailed = true
PotbellyAnalytics.logErrorEvent(
errorType = "GooglePaySetupError",
errorMessage = "Error: ${e.message}",
apiErrorMessage = e.message ?: e.localizedMessage,
)
}
}
This GooglePayLauncher must be calling the CardWidgetViewModel thread which causes this Exception.
It's part of stripe-android > payments-core
https://github.com/stripe/stripe-android/blob/6bc8b26b112cfc08fb407496b4056195c3365240/payments-core/src/main/java/com/stripe/android/view/CardWidgetViewModel.kt#L4
My team on discord won't be deeply familiar with how the SDK is wired up behind the scenes unfortunately as we mostly investigate integration patterns and help with best practices.
While, we'd love to help - If you were integrated directly via Stripe's SDK then we'd have a better idea of your integration pattern.
We're not familiar with Olo's SDK wrapper so I'd recommend waiting on what Olo Support says about this first. Once they provide some actionable information, we'd love to take a deeper look.
OR if you can, you can try to reproduce the issue with Stripe's SDK directly and see if you see reoccurrence of the said error. If you do manage to reproduce it with our SDK, we'll reach out to our Android team and have them take a look..
Thank you so much for your support. I am waiting for Olo support reply.
NP! Happy to help ๐
I'll close this thread for now as I need to step away but feel free to re-open if you have further questions!