#cynaed_unexpected
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/1446323377760501830
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Hi there ๐ please give me a moment to catch up, i will get back to you shortly!
Hello @grizzled mason, sure thanks!
Hi @waxen dagger do you have a screen recording of the reported behaviour?
Also, we do not have official support for the Flutter SDK. We recommend using our React Native SDK: https://docs.stripe.com/terminal/payments/setup-reader/tap-to-pay?terminal-sdk-platform=react-native
Let me get it.
As for this yeah I understand this that's why we used Kotlin for doing Stripe, we used MethodChannel to have a bridge between flutter and kotlin
Apologies for this, it seems the person that has the video is currently unavailable, so I can't send you anything right now. but would it be possible for us to review the code or would this be on other thread?
I'll gladly send the snippets if it could help
Hi @waxen dagger I'm also an engineer from Stripe. Can you share with me the code snippet?
super.configureFlutterEngine(flutterEngine)
Log.d("MyFloDebug", "Android Bundle ID of myFlo_Staging: ${androidBundleId}")
MethodChannel(flutterEngine.dartExecutor.binaryMessenger,"${androidBundleId}/nfc").setMethodCallHandler { call, result ->
if (call.method == "stripeTapToPay") {
println("------------------------------------------------- KOTLIN -------------------------------------------------")
val systemId = call.argument<String>("systemId")!!
val paymentIntentId = call.argument<String>("paymentIntentId")!!
val locPermission = call.argument<Boolean>("locPermission")
val jobId = call.argument<Int>("jobId")!!
// storing result
pendingFlutterResult = result
// Location Id
val locationid = call.argument<String>("locID")
val liveMode: Boolean = call.argument<Boolean>("liveMode") ?: false
GlobalStuff2.vGTLocID = locationid
GlobalStuff2.vGTJobID = jobId
initializeTerminal(paymentIntentId)
val terminal = Terminal.getInstance()
if (terminal.connectedReader != null) {
Log.d("TerminalCheck", "Connected reader: ${terminal.connectedReader!!.label}")
} else {
onDiscoverReaders(liveMode)
}
} else {
result.notImplemented()
}
}
}```
fun initializeTerminal(paymentIntentId: String){
val logLevel = LogLevel.VERBOSE
val tokenProvider = TokenProvider();
val listener = object : TerminalListener {
override fun onConnectionStatusChange(status: ConnectionStatus) {
println("[CONNECTION STATUS CHANGE]: $status");
}
override fun onPaymentStatusChange(status: PaymentStatus) {
println("[PAYMENT STATUS CHANGE]: $status");
if(status == PaymentStatus.READY && !firstTime && !hasStartedTapToPay){
firstTime = true;
hasStartedTapToPay = true
val intent = Intent(this@MainActivity, TapToPayActivity::class.java)
intent.putExtra("paymentIntentId", paymentIntentId)
startActivityForResult(intent, 1234)
}
}
}
if (!Terminal.isInitialized()) {
Terminal.initTerminal(applicationContext, logLevel, tokenProvider, listener)
}
val terminal = Terminal.getInstance()
println("STATUS IN INITIALIZATION ${terminal.paymentStatus}")
if(terminal.paymentStatus == PaymentStatus.READY){
val intent = Intent(this@MainActivity, TapToPayActivity::class.java)
intent.putExtra("paymentIntentId", paymentIntentId)
startActivityForResult(intent, 1234)
}
}```
MY suspicion falls in the initializeTerminal function which calls TapToPay Activity.
What does this TapToPayActivity do?
TapToPayActivity.kt
super.onCreate(savedInstanceState)
if (isRunning) {
Log.w("TapToPay", "TapToPayActivity already running, ignoring duplicate")
finish()
return
}
isRunning = true
setContentView(R.layout.activity_tap_to_pay)
val paymentIntentId = intent.getStringExtra("paymentIntentId") ?: ""
val terminal = Terminal.getInstance()
terminal.retrievePaymentIntent(
paymentIntentId, // your PaymentIntent ID from backend
object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
if(paymentIntent.status == PaymentIntentStatus.SUCCEEDED){
val resultIntent = Intent()
resultIntent.putExtra("payment_intent_id", paymentIntent.id)
setResult(Activity.RESULT_OK, resultIntent)
finish()
return
}
activePaymentIntent = paymentIntent
collectAndConfirm(paymentIntent) // continue with collect + confirm flow
}
override fun onFailure(e: TerminalException) {
Log.e("TapToPay", "Retrieve PaymentIntent failed: ${e.message}")
setResult(Activity.RESULT_CANCELED)
finish()
}
}
)
}```
private fun collectAndConfirm(paymentIntent: PaymentIntent) {
val terminal = Terminal.getInstance()
terminal.collectPaymentMethod(paymentIntent, object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
terminal.confirmPaymentIntent(paymentIntent, object : PaymentIntentCallback {
override fun onSuccess(paymentIntent: PaymentIntent) {
Log.d("TapToPay", "Payment success")
activePaymentIntent = null
val resultIntent = Intent()
resultIntent.putExtra("payment_intent_id", paymentIntent.id)
setResult(Activity.RESULT_OK, resultIntent)
finish()
}
override fun onFailure(e: TerminalException) {
Log.e("TapToPay", "Payment confirm failed: ${e.message}")
setResult(Activity.RESULT_CANCELED)
finish()
}
})
}
override fun onFailure(e: TerminalException) {
Log.e("TapToPay", "Payment method failed: ${e.message}")
setResult(Activity.RESULT_CANCELED)
finish()
}
})
}
it handles the collect and confirm
Ok, do you want to put some logs around initializeTerminal and see if it's invoked more than once?
since this is the function that launches the TapToPayActivity and evntually the Tap to Pay screen.
The problem lies in the setup, the problem happens on Active Tab 5. The devs don't have a Active Tab 5 device on hand. It's only being used by the client. so we cannot pinpoint the problem, since the devs don't have that tablet and it's working properly for us.
Here's my suggestions: Add some logs in your application to determine if the Tap to Pay screen reapparing was caused by the initializeTerminal function, or something else.
Right now we don't have sufficifient information to determine the root cause and adding some logs will be helpful.