react-native-braintree-xplat
react-native-braintree-xplat copied to clipboard
Drop in UI spins forever on Android
import React, { Component } from 'react';
import {
AppRegistry,
Text,
TouchableOpacity,
Platform,
View
} from 'react-native';
import BTClient from 'react-native-braintree-xplat';
export default class bt extends Component {
onPress() {
const token = "eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiIzZWRiNjBlZjZlMjFlYzQwYzRlZjgyMWJjYjViNzI4YjllYmE3NWM1ZDE4YzEzZjdjNTIxMTM0YWU1YTAyOGRifGNyZWF0ZWRfYXQ9MjAxNi0xMC0yMFQwMDoxNzoxMy44MjI0MTI2MzArMDAwMFx1MDAyNm1lcmNoYW50X2lkPTM0OHBrOWNnZjNiZ3l3MmJcdTAwMjZwdWJsaWNfa2V5PTJuMjQ3ZHY4OWJxOXZtcHIiLCJjb25maWdVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMvMzQ4cGs5Y2dmM2JneXcyYi9jbGllbnRfYXBpL3YxL2NvbmZpZ3VyYXRpb24iLCJjaGFsbGVuZ2VzIjpbXSwiZW52aXJvbm1lbnQiOiJzYW5kYm94IiwiY2xpZW50QXBpVXJsIjoiaHR0cHM6Ly9hcGkuc2FuZGJveC5icmFpbnRyZWVnYXRld2F5LmNvbTo0NDMvbWVyY2hhbnRzLzM0OHBrOWNnZjNiZ3l3MmIvY2xpZW50X2FwaSIsImFzc2V0c1VybCI6Imh0dHBzOi8vYXNzZXRzLmJyYWludHJlZWdhdGV3YXkuY29tIiwiYXV0aFVybCI6Imh0dHBzOi8vYXV0aC52ZW5tby5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tIiwiYW5hbHl0aWNzIjp7InVybCI6Imh0dHBzOi8vY2xpZW50LWFuYWx5dGljcy5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tLzM0OHBrOWNnZjNiZ3l3MmIifSwidGhyZWVEU2VjdXJlRW5hYmxlZCI6dHJ1ZSwicGF5cGFsRW5hYmxlZCI6dHJ1ZSwicGF5cGFsIjp7ImRpc3BsYXlOYW1lIjoiQWNtZSBXaWRnZXRzLCBMdGQuIChTYW5kYm94KSIsImNsaWVudElkIjpudWxsLCJwcml2YWN5VXJsIjoiaHR0cDovL2V4YW1wbGUuY29tL3BwIiwidXNlckFncmVlbWVudFVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbS90b3MiLCJiYXNlVXJsIjoiaHR0cHM6Ly9hc3NldHMuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJhc3NldHNVcmwiOiJodHRwczovL2NoZWNrb3V0LnBheXBhbC5jb20iLCJkaXJlY3RCYXNlVXJsIjpudWxsLCJhbGxvd0h0dHAiOnRydWUsImVudmlyb25tZW50Tm9OZXR3b3JrIjp0cnVlLCJlbnZpcm9ubWVudCI6Im9mZmxpbmUiLCJ1bnZldHRlZE1lcmNoYW50IjpmYWxzZSwiYnJhaW50cmVlQ2xpZW50SWQiOiJtYXN0ZXJjbGllbnQzIiwiYmlsbGluZ0FncmVlbWVudHNFbmFibGVkIjp0cnVlLCJtZXJjaGFudEFjY291bnRJZCI6ImFjbWV3aWRnZXRzbHRkc2FuZGJveCIsImN1cnJlbmN5SXNvQ29kZSI6IlVTRCJ9LCJjb2luYmFzZUVuYWJsZWQiOmZhbHNlLCJtZXJjaGFudElkIjoiMzQ4cGs5Y2dmM2JneXcyYiIsInZlbm1vIjoib2ZmIn0=";
BTClient.setup(token);
BTClient.showPaymentViewController()
.then(nonce => {
console.log(`Complete: ${nonce}`);
}).catch(err => {
console.log('err', err);
});
}
render() {
return (
<View >
<TouchableOpacity onPress={this.onPress.bind(this)}>
<Text>
Welcome to React Native!
</Text>
</TouchableOpacity>
</View>
);
}
}
AppRegistry.registerComponent('bt', () => bt);
I'm using the sample token on the braintree developers site. If I start a brand new app with the above code as my index.android.js
and click the button, the spinner will come up and never go away. If I click android back and then click the button again the drop in ui will appear.
I belive the reason for this is because the setup method is a promise. So what happens is that you are bringing up the payment view before setup has finished. Try waiting for setup to finish before bringing up the payment view.
On Thu, Nov 3, 2016 at 5:47 PM Stephen Horvath [email protected] wrote:
import React, { Component } from 'react'; import { AppRegistry, Text, TouchableOpacity, Platform, View } from 'react-native'; import BTClient from 'react-native-braintree-xplat';
export default class bt extends Component { onPress() { const token = "eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiIzZWRiNjBlZjZlMjFlYzQwYzRlZjgyMWJjYjViNzI4YjllYmE3NWM1ZDE4YzEzZjdjNTIxMTM0YWU1YTAyOGRifGNyZWF0ZWRfYXQ9MjAxNi0xMC0yMFQwMDoxNzoxMy44MjI0MTI2MzArMDAwMFx1MDAyNm1lcmNoYW50X2lkPTM0OHBrOWNnZjNiZ3l3MmJcdTAwMjZwdWJsaWNfa2V5PTJuMjQ3ZHY4OWJxOXZtcHIiLCJjb25maWdVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMvMzQ4cGs5Y2dmM2JneXcyYi9jbGllbnRfYXBpL3YxL2NvbmZpZ3VyYXRpb24iLCJjaGFsbGVuZ2VzIjpbXSwiZW52aXJvbm1lbnQiOiJzYW5kYm94IiwiY2xpZW50QXBpVXJsIjoiaHR0cHM6Ly9hcGkuc2FuZGJveC5icmFpbnRyZWVnYXRld2F5LmNvbTo0NDMvbWVyY2hhbnRzLzM0OHBrOWNnZjNiZ3l3MmIvY2xpZW50X2FwaSIsImFzc2V0c1VybCI6Imh0dHBzOi8vYXNzZXRzLmJyYWludHJlZWdhdGV3YXkuY29tIiwiYXV0aFVybCI6Imh0dHBzOi8vYXV0aC52ZW5tby5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tIiwiYW5hbHl0aWNzIjp7InVybCI6Imh0dHBzOi8vY2xpZW50LWFuYWx5dGljcy5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tLzM0OHBrOWNnZjNiZ3l3MmIifSwidGhyZWVEU2VjdXJlRW5hYmxlZCI6dHJ1ZSwicGF5cGFsRW5hYmxlZCI6dHJ1ZSwicGF5cGFsIjp7ImRpc3BsYXlOYW1lIjoiQWNtZSBXaWRnZXRzLCBMdGQuIChTYW5kYm94KSIsImNsaWVudElkIjpudWxsLCJwcml2YWN5VXJsIjoiaHR0cDovL2V4YW1wbGUuY29tL3BwIiwidXNlckFncmVlbWVudFVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbS90b3MiLCJiYXNlVXJsIjoiaHR0cHM6Ly9hc3NldHMuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJhc3NldHNVcmwiOiJodHRwczovL2NoZWNrb3V0LnBheXBhbC5jb20iLCJkaXJlY3RCYXNlVXJsIjpudWxsLCJhbGxvd0h0dHAiOnRydWUsImVudmlyb25tZW50Tm9OZXR3b3JrIjp0cnVlLCJlbnZpcm9ubWVudCI6Im9mZmxpbmUiLCJ1bnZldHRlZE1lcmNoYW50IjpmYWxzZSwiYnJhaW50cmVlQ2xpZW50SWQiOiJtYXN0ZXJjbGllbnQzIiwiYmlsbGluZ0FncmVlbWVudHNFbmFibGVkIjp0cnVlLCJtZXJjaGFudEFjY291bnRJZCI6ImFjbWV3aWRnZXRzbHRkc2FuZGJveCIsImN1cnJlbmN5SXNvQ29kZSI6IlVTRCJ9LCJjb2luYmFzZUVuYWJsZWQiOmZhbHNlLCJtZXJjaGFudElkIjoiMzQ4cGs5Y2dmM2JneXcyYiIsInZlbm1vIjoib2ZmIn0="; BTClient.setup(token); BTClient.showPaymentViewController() .then(nonce => { console.log(
Complete: ${nonce}
); }).catch(err => { console.log('err', err); }); }render() { return ( <View > <TouchableOpacity onPress={this.onPress.bind(this)}> <Text> Welcome to React Native! </Text> </TouchableOpacity> </View> ); } }
AppRegistry.registerComponent('bt', () => bt);
[image: image] https://cloud.githubusercontent.com/assets/645336/19975794/9845fe92-a1ed-11e6-9b98-7e9475667360.png
I'm using the sample token on the braintree developers https://developers.braintreepayments.com/start/hello-client/android/v2 site. If I start a brand new app with the above code as my index.android.js and click the button, the spinner will come up and never go away. If I click android back and then click the button again the drop in ui will appear.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/kraffslol/react-native-braintree-xplat/issues/21, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJScPt7oztbNe_x2tDUGuC2VX0iXdGnks5q6hApgaJpZM4Koo7_ .
onPress() {
const token = "eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiIzZWRiNjBlZjZlMjFlYzQwYzRlZjgyMWJjYjViNzI4YjllYmE3NWM1ZDE4YzEzZjdjNTIxMTM0YWU1YTAyOGRifGNyZWF0ZWRfYXQ9MjAxNi0xMC0yMFQwMDoxNzoxMy44MjI0MTI2MzArMDAwMFx1MDAyNm1lcmNoYW50X2lkPTM0OHBrOWNnZjNiZ3l3MmJcdTAwMjZwdWJsaWNfa2V5PTJuMjQ3ZHY4OWJxOXZtcHIiLCJjb25maWdVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMvMzQ4cGs5Y2dmM2JneXcyYi9jbGllbnRfYXBpL3YxL2NvbmZpZ3VyYXRpb24iLCJjaGFsbGVuZ2VzIjpbXSwiZW52aXJvbm1lbnQiOiJzYW5kYm94IiwiY2xpZW50QXBpVXJsIjoiaHR0cHM6Ly9hcGkuc2FuZGJveC5icmFpbnRyZWVnYXRld2F5LmNvbTo0NDMvbWVyY2hhbnRzLzM0OHBrOWNnZjNiZ3l3MmIvY2xpZW50X2FwaSIsImFzc2V0c1VybCI6Imh0dHBzOi8vYXNzZXRzLmJyYWludHJlZWdhdGV3YXkuY29tIiwiYXV0aFVybCI6Imh0dHBzOi8vYXV0aC52ZW5tby5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tIiwiYW5hbHl0aWNzIjp7InVybCI6Imh0dHBzOi8vY2xpZW50LWFuYWx5dGljcy5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tLzM0OHBrOWNnZjNiZ3l3MmIifSwidGhyZWVEU2VjdXJlRW5hYmxlZCI6dHJ1ZSwicGF5cGFsRW5hYmxlZCI6dHJ1ZSwicGF5cGFsIjp7ImRpc3BsYXlOYW1lIjoiQWNtZSBXaWRnZXRzLCBMdGQuIChTYW5kYm94KSIsImNsaWVudElkIjpudWxsLCJwcml2YWN5VXJsIjoiaHR0cDovL2V4YW1wbGUuY29tL3BwIiwidXNlckFncmVlbWVudFVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbS90b3MiLCJiYXNlVXJsIjoiaHR0cHM6Ly9hc3NldHMuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJhc3NldHNVcmwiOiJodHRwczovL2NoZWNrb3V0LnBheXBhbC5jb20iLCJkaXJlY3RCYXNlVXJsIjpudWxsLCJhbGxvd0h0dHAiOnRydWUsImVudmlyb25tZW50Tm9OZXR3b3JrIjp0cnVlLCJlbnZpcm9ubWVudCI6Im9mZmxpbmUiLCJ1bnZldHRlZE1lcmNoYW50IjpmYWxzZSwiYnJhaW50cmVlQ2xpZW50SWQiOiJtYXN0ZXJjbGllbnQzIiwiYmlsbGluZ0FncmVlbWVudHNFbmFibGVkIjp0cnVlLCJtZXJjaGFudEFjY291bnRJZCI6ImFjbWV3aWRnZXRzbHRkc2FuZGJveCIsImN1cnJlbmN5SXNvQ29kZSI6IlVTRCJ9LCJjb2luYmFzZUVuYWJsZWQiOmZhbHNlLCJtZXJjaGFudElkIjoiMzQ4cGs5Y2dmM2JneXcyYiIsInZlbm1vIjoib2ZmIn0=";
BTClient.setup(token)
.then(() => {
BTClient.showPaymentViewController()
.then(nonce => {
console.log(`Complete: ${nonce}`);
}).catch(err => {
console.log('err', err);
});
});
}
Like this? I tried above and still get the spinner forever. Or do you mean something different?
It does look like a timing issue. When I run the setup in componentDidMount
and then show the payment controller when clicking a button it loads fine. Unfortunately, I'm not able to do this except for a test. The design of this screen has two payment buttons with different prices. So I have to be able to generate a new token upon button click and then immediately go to the payment screen. So therefore I need to be able to wait for the setup to complete successfully before going to the payment screen. It does not look like the setup promise returns before it is actually complete and I end up with that neverending spinner.
Is there some other design that I could use that would allow me to have the two payment buttons and allow sufficient timing for the setup to complete?
I had better luck initializing BTClient in the main component, then passing BTClient as a prop to my child component that loads the payment form. Not sure if that's the best intended design, but I use the form in multiple components so it seemed okay to only initialize BTClient once.
Example:
var BTClient = require('react-native-braintree-xplat');
class myApp extends Component {
componentWillMount(){
//initialize BTClient when the app starts
const token = "eyJ2ZXJzaW9uIjoyLCJhd[...]m1vIjoib2ZmIn0=";
BTClient.setup(token).then((res) => {
console.log(res);
});
}
render(){
//pass BTClient as a prop to the child
return (<childComponent BTClient={BTClient} />
}
}
class childComponent extends Component {
...
onPressBuy(){
//BTClient will be ready by the time the user triggers the event
this.props.BTClient.showPaymentViewController().then((nonce) => {
console.log(`Complete: ${nonce}`);
}).catch((err) => {
console.log('err', err);
});
}
...
}
The issue for me is that I have two different purchase prices that the user could select. I suppose I could pre-fetch two different tokens, one for each price, and store them to be ready for when and if the user clicks the payment button. But that seems like a lot of work. The promise sounds like the best approach because it would allow me to wait for the client to make the request, get the appropriate token for the selected payment, then bring up the payment screen. So I really think the promise should be the thing that needs to be fixed.
Waiting for promise resolve worked for me. See below.
@kraffslol It would be very nice if the docs mentioned this at all. I likely would have spent hours diagnosing this if I didn't see this issue first.
export class PaymentTest extends Component {
props: Props
static displayName = 'PaymentTest'
_braintreeIsSetup = false
showPaymentFormAfterClientSetup = () => {
this._braintreeIsSetup = true
const options = {}
BTClient.showPaymentViewController(options).then((nonce) => {
console.log("showPaymentViewController Success", nonce)
this.props.handlePayment({
payment_method_nonce: nonce
})
})
.catch((error) => {
// TODO: Handle error.
console.log("showPaymentViewController Error", error)
})
}
showPaymentForm = () => {
const { data: { me: { braintree_client_token } } } = this.props
if (this._braintreeIsSetup) {
this.showPaymentFormAfterClientSetup()
} else if (Platform.OS === 'ios') {
BTClient.setupWithURLScheme(braintree_client_token, 'com.vydia.app-dev.payments').then(this.showPaymentFormAfterClientSetup)
} else {
BTClient.setup(braintree_client_token).then(this.showPaymentFormAfterClientSetup)
}
}
I succeeded in avoiding this issue by adding a 3000ms timeout after 'setup'
onClickTerms(clientToken, amount)
{
var self = this;
if (Platform.OS === 'ios') {
BTClient.setupWithURLScheme(clientToken, GLOBAL.url_scheme).then(() => {
this.showPaymentViewController(amount);
});
} else {
BTClient.setup(clientToken).then(() => {
this.showPaymentViewController(amount);
});
}
}
showPaymentViewController(amount)
{
var self = this;
setTimeout(() => {
BTClient.showPaymentViewController()
.then(function(nonce) {
//payment succeeded, pass nonce to server
})
.catch(function(err) {
//console.error(err);
});
}, 3000);
}
@asciiman @VansonLeung, we suddenly experienced this error. I checked into the bridge's Android dependencies and one entry was compile 'com.braintreepayments.api:braintree:2.+'
. I looked at the maven repo and there have been releases almost monthly. I went back through each release and found that it broke after 2.3.9. So I forked this repo to use that specific version.
The fix is available here: https://github.com/Vydia/react-native-braintree-xplat/commit/4fcfc68dc50583e8211daa42a7d276f79a93f993
Just change your package.json to read
"react-native-braintree-xplat": "[email protected]:Vydia/react-native-braintree-xplat.git#4fcfc68dc50583e8211daa42a7d276f79a93f993",
and you're good. However I don't want to use old versions of the Braintree repo, since according to their release notes they've fixed quite a few bugs.
@kraffslol we should probably hardcode Android dependencies so things like this won't suddenly happen. Granted it's more maintenance work but it's worth it for the users.