Closed TheArchitect123 closed 4 weeks ago
@sarahkoop
Hi @TheArchitect123 - Can you share a screen recording of the behavior your a seeing? Are you calling tokenize
from within an Android activity or fragment (it's unclear from the code snippet provided)?
Your integration may be a good candidate to use the manual browser switching pattern which allows you to control delivery of the browser switch result and doesn't encapsulate management of the result via the activity lifecycle. This requires you to call parseBrowserSwitchResult on resume of your app.
Hi @sarahkoop, I'm calling the tokenize method from a fragment. I'm using Google's Navigation Library to manage fragment transactions within a single Core Activity (Single activity Architecture).
I'm using both Manual Configuration (on devices that can receive intents from Paypal), but the default is to use Paypal tokenisation via function call directly (which is what the Samsung device does).
Here's the expected behaviour (when tested against a Google Pixel Device), which uses Manual Configuration. https://drive.google.com/file/d/1vrZW4IhxuLHoT-QOHoT-k28_8GvhrEju/view?usp=sharing
And here's the behaviour when running against my Samsung S21. It just cancels the Paypal request, and gets stuck. https://drive.google.com/file/d/1YgKvxDskRDyyp_O5LhRYIMRjNZFQWzaE/view?usp=sharing
Based on the code snippet provided, it does not look like you are using the manual browser switching integration. Our docs for this are somewhat confusing, and we are working to simplify the integration patterns in the next major version. I think there could be unexpected behavior when mixing both integration patterns - so we would recommend only using the manual pattern if it's required for your architecture.
For manual integration you should use PayPalClient(BraintreeClient)
and call tokenizePayPalAccount(FragmentActivity, PayPalRequest, PayPalFlowStartedCallback)
without use of a PayPalListener
. You must also call parseBrowserSwitchResult
and onBrowserSwitchResult
to receive results.
@sarahkoop
The manual documentation is a bit outdated (https://github.com/braintree/braintree_android/blob/main/v4.9.0%2B_MIGRATION_GUIDE.md#manual-browser-switching-for-browser-based-flows)
I'm using the latest stable 4.47.0, and it doesn't have a tokenizePayPalRequest with only a request as a parameter.
Here's an example of what I'm doing with my activity (I'm now using Manual Configuration Only). It still doesn't work for Samsung Devices. The activity just freezes now
class MainActivity : AppCompatActivity{
lateinit var payPalClient : PayPalClient
override fun onResume() {
super.onResume()
payPalClient.parseBrowserSwitchResult(this, intent)?.let {
handleBrowserSwitchResult(it)
}
}
override fun onNewIntent(newIntent: Intent?) {
super.onNewIntent(newIntent)
intent = newIntent
payPalClient.parseBrowserSwitchResult(this, newIntent)?.let {
handleBrowserSwitchResult(it)
}
}
private fun handleBrowserSwitchResult(result: BrowserSwitchResult) {
payPalClient.onBrowserSwitchResult(result) { payPalAccountNonce, error ->
payPalAccountNonce?.let {
lifecycleScope.launch {
// process PayPal results
// it.payerId,
// it.string
}
} ?: error?.let {
// handle error
}
}
// clear pending request to guard against additional browser switch result invocations
payPalClient.clearActiveBrowserSwitchRequests(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// paypal configuration
val brainTreeClient =
BraintreeClient(
this,
"braintree_token"
)
payPalClient =
PayPalClient(this, brainTreeClient)
val browserSwitchResult =
PayPalService.payPalClient.parseBrowserSwitchResult(this, intent)
if (browserSwitchResult != null) {
// process kill scenario
handleBrowserSwitchResult(browserSwitchResult)
}
}
}
Hi @sarahkoop,
Do you have any updates on this issue? My company's deploying our product in the next couple of weeks, and we need this issue resolved ASAP. Thank you.
Can you try adding some delay before launching web payment? onResume lifecycle dependency may cause user canceled problem. @TheArchitect123
It doesn't work unfortunately @ahmet12 , but thanks for the suggestion.
I found these logs as well @sarahkoop
PayPalClient.java com.braintreepayments.api.PayPalClient onBrowserSwitchResult 416 null E PayPalClient.java com.braintreepayments.api.PayPalClient deliverBrowserSwitchResultToListener 351 null E PayPalClient.java com.braintreepayments.api.PayPalClient onBrowserSwitchResult 346 null E PayPalLifeCycleObserver.java com.braintreepayments.api.PayPalLifecycleObserver$1 run 75 null E Handler.java android.os.Handler handleCallback 958 null E Handler.java android.os.Handler dispatchMessage 99 null E Looper.java android.os.Looper loopOnce 230 null E Looper.java android.os.Looper loop 319 null E ActivityThread.java android.app.ActivityThread main 8893 null E Method.java java.lang.reflect.Method invoke -2 null E RuntimeInit.java com.android.internal.os.RuntimeInit$MethodAndArgsCaller run 608 null E ZygoteInit.java com.android.internal.os.ZygoteInit main 1103 null E PAYPAL RESULT : kotlin.Unit null
I've FINALLY FOUND IT!!!
Turns out it was my local antivirus the whole time. I'm closing this issue.
SurfaceFlinger: id=310592 createSurf, flag=44004, com.antivirus/com.avast.android.one.base.ui.scamprotection.scan.UrlScanActivity$_23967#310592 06-24 00:43:22.097 1656 5305 D WindowManager: makeSurface duration=1 name=com.antivirus/com.avast.android.one.base.ui.scamprotection.scan.UrlScanActivity$_23967
Hey @TheArchitect123 thanks for closing this. Out of curiosity, what antivirus software are you using? We're offering support for app links in the near future, and I have a feeling that will fix this issue without having to turn off the antivirus program. It'd be nice to be able to reproduce on our end so we can verify the potential fix.
@sshropshire AVG antivirus
@TheArchitect123 thanks!
Braintree SDK Version
4.47.0
Environment
Sandbox
Android Version & Device
Samsung S21 (Android 14)
Braintree dependencies
com.braintreepayments.api:paypal:4.47.0
Describe the bug
Currently I have a service that opens a PayPal activity, which allows users to onboard their PayPal wallet into my company's app.
When invoking the above, onPayPalFailure gets triggered, and I get the following error. error = {UserCanceledException@38573} com.braintreepayments.api.UserCanceledException: User canceled PayPal. isExplicitCancelation = false isExplicitCancelation {boolean} backtrace = {Object[13]@38579} 0 = {long[24]@38658} [481158122528, 481158122080, 481158122496, 468213704320, 1898905344, 1898905408, 1898909864, 1898909832, 1901789312, 1901576224, 1900247616, 1903048448, 127, 5, 8, 65, 2, 4, 185, 83, 107, 4294967295, 11, 334] 1 = {Class@30537} "class com.braintreepayments.api.PayPalClient" 2 = {Class@30537} "class com.braintreepayments.api.PayPalClient" 3 = {Class@30537} "class com.braintreepayments.api.PayPalClient" 4 = {Class@38563} "class com.braintreepayments.api.PayPalLifecycleObserver$1" 5 = {Class@1259} "class android.os.Handler" 6 = {Class@1259} "class android.os.Handler" 7 = {Class@16545} "class android.os.Looper" 8 = {Class@16545} "class android.os.Looper" 9 = {Class@7695} "class android.app.ActivityThread" 10 = {Class@10634} "class java.lang.reflect.Method" 11 = {Class@11255} "class com.android.internal.os.RuntimeInit$MethodAndArgsCaller" 12 = {Class@1339} "class com.android.internal.os.ZygoteInit" cause = null detailMessage = "User canceled PayPal." stackTrace = {StackTraceElement[12]@38584} 0 = {StackTraceElement@38586} "com.braintreepayments.api.PayPalClient.onBrowserSwitchResult(PayPalClient.java:416)" declaringClass = "com.braintreepayments.api.PayPalClient" fileName = "PayPalClient.java" lineNumber = 416 methodName = "onBrowserSwitchResult" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 1 = {StackTraceElement@38587} "com.braintreepayments.api.PayPalClient.deliverBrowserSwitchResultToListener(PayPalClient.java:351)" declaringClass = "com.braintreepayments.api.PayPalClient" fileName = "PayPalClient.java" lineNumber = 351 methodName = "deliverBrowserSwitchResultToListener" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 2 = {StackTraceElement@38588} "com.braintreepayments.api.PayPalClient.onBrowserSwitchResult(PayPalClient.java:346)" declaringClass = "com.braintreepayments.api.PayPalClient" fileName = "PayPalClient.java" lineNumber = 346 methodName = "onBrowserSwitchResult" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 3 = {StackTraceElement@38589} "com.braintreepayments.api.PayPalLifecycleObserver$1.run(PayPalLifeCycleObserver.java:75)" declaringClass = "com.braintreepayments.api.PayPalLifecycleObserver$1" fileName = "PayPalLifeCycleObserver.java" lineNumber = 75 methodName = "run" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 4 = {StackTraceElement@38590} "android.os.Handler.handleCallback(Handler.java:958)" declaringClass = "android.os.Handler" fileName = "Handler.java" lineNumber = 958 methodName = "handleCallback" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 5 = {StackTraceElement@38591} "android.os.Handler.dispatchMessage(Handler.java:99)" declaringClass = "android.os.Handler" fileName = "Handler.java" lineNumber = 99 methodName = "dispatchMessage" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 6 = {StackTraceElement@38592} "android.os.Looper.loopOnce(Looper.java:230)" declaringClass = "android.os.Looper" fileName = "Looper.java" lineNumber = 230 methodName = "loopOnce" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 7 = {StackTraceElement@38593} "android.os.Looper.loop(Looper.java:319)" declaringClass = "android.os.Looper" fileName = "Looper.java" lineNumber = 319 methodName = "loop" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 8 = {StackTraceElement@38594} "android.app.ActivityThread.main(ActivityThread.java:8893)" declaringClass = "android.app.ActivityThread" fileName = "ActivityThread.java" lineNumber = 8893 methodName = "main" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 9 = {StackTraceElement@38595} "java.lang.reflect.Method.invoke(Native Method)" declaringClass = "java.lang.reflect.Method" fileName = "Method.java" lineNumber = -2 methodName = "invoke" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 10 = {StackTraceElement@38596} "com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)" declaringClass = "com.android.internal.os.RuntimeInit$MethodAndArgsCaller" fileName = "RuntimeInit.java" lineNumber = 608 methodName = "run" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 11 = {StackTraceElement@38597} "com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)" declaringClass = "com.android.internal.os.ZygoteInit" fileName = "ZygoteInit.java" lineNumber = 1103 methodName = "main" shadow$klass = {Class@12900} "class java.lang.StackTraceElement" shadow$monitor = 0 suppressedExceptions = {Collections$EmptyList@38582} size = 0 shadow$klass = {Class@38506} "class com.braintreepayments.api.UserCanceledException" shadow$monitor = 0
To reproduce
Follow the steps above and run on a Samsung S21 (or an Android device that doesn't require managing responses via Activity Lifecycles)
Expected behavior
That PayPal activity opens up successfully on all Android devices, and users can add their PayPal wallets without issues.
Screenshots
No response