简体   繁体   中英

React-native open link in browser and return to app

I've developing an app in react-native that should communicate with a gateway for payments, after finishing the payment process (success or failure) I need to show an alert to user. For this purpose, I open a link in WebView and after that I get return's url with onNavigationStateChange and show success or failure message.

But, this flow for security issues must be done in a default device browser .

Current Code:

const BASEURL = 'https://gatewayURL/?ID=';
let Token = null;
let paymentAccepted = null;
let paymentFactorId = null;

class Gateway extends PureComponent {
  static propTypes = {
    dispatch: PropTypes.func,
    navigation: PropTypes.any,
  }

  componentWillMount() {
    this.props.dispatch(getPaymentStatus());
  }


  _onLoad(webViewState) {
    let url = webViewState.url.toString();
    let isResponseValid = url.includes('backFromGateway');
    if(isResponseValid){
      if(this.props.checkedPaymentStatus != 'checked' ){
        setTimeout(() => {
          this.props.dispatch(setPaymentStatus('checked'));

          let splitedURL = url.split("/");
          paymentFactorId = splitedURL[splitedURL.length -2];
          if(splitedURL[splitedURL.length - 1] === '0'){
            paymentAccepted = true;
            this.props.dispatch(setGatewayResponse('done', paymentFactorId));
          }
          else {
            paymentAccepted = false;
            this.props.dispatch(setGatewayResponse('rejected', paymentFactorId));
          }


          this.props.navigation.navigate('BackFromGateway', { title: '' })
        }, 1000);
      }
    }
  }


  render() {
    const { addNewOrderGatewayToken, checkedPaymentStatus } = this.props;
    token = addNewOrderGatewayToken;
    let view = null;
    if(checkedPaymentStatus !== 'checked'){
      view =  <WebView onNavigationStateChange={this._onLoad.bind(this)} style={styles.container} source={{ uri: `${BASEURL}${token}`  }}/>
    }
    else{
      view = <View></View>
    }

    return (
      <View style={styles.container}>
        {view}
      </View>      
    );
  }
}

Any idea?
Thanks

If you can make callbacks from the gateway website, then I recommend to use deep linking to handle flow between app and browser. Basically, your app will open the gateway website for payment, and depending on payment result, the website will make a callback to the app using its deep link. App then will listen to the link, take out necessary information and continue to proceed.

What you need to do is:

Set up deep linking in your app. You should follow the guide from official website ( here ) to enable it. Let pick a random URL here for linking, eg gatewaylistener

Set the necessary callbacks from gateway to your app. In your case, since you need to handle successful payment and failed payment, you can add 2 callbacks, eg gatewaylistener://success?id={paymentId} and gatewaylistener://error?id={paymentId}

Finally, you need to listen to web browser from the app. One way to do that is add listener right inside the component opening the gateway.

// setup
componentDidMount() {
  Linking.getInitialURL().then((url) => {
    if (url) {
      this.handleOpenURL(url)
    }
  }).catch(err => {})
  Linking.addEventListener('url', this.handleOpenURL)
}

componentWillUnmount() {
  Linking.removeEventListener('url', this.handleOpenURL)
}

// open your gateway
async openGateWay = () => {
  const { addNewOrderGatewayToken } = this.props
  const url = `${BASEURL}${addNewOrderGatewayToken}`
  const canOpen = await Linking.canOpenURL(url)
  if (canOpen) {
    this.props.dispatch(setPaymentStatus('checked'))
    Linking.openURL(url)
  }
}

// handle gateway callbacks
handleOpenURL = (url) => {
  if (isSucceedPayment(url)) { // your condition
    // handle success payment
  } else {
    // handle failure
  }
}

For authentication purposes, using a deep linking redirection for example, you can use an embedded browser with Chrome Custom Tabs from Android and SafariViewController from iOS, check the InAppBrowser component to support both platforms with the same code ( Linking is already used internally to detect the deep link redirection).

As you can see from the example folder, you can use a custom deep link configured from your app (AndroidManifest for Android and Info.plist for iOS) :

  getDeepLink (path = '') {
    const scheme = 'my-demo'
    const prefix = Platform.OS === 'android' ? `${scheme}://demo/` : `${scheme}://`
    return prefix + path
  }

  async tryDeepLinking () {
    const redirectToURL = `https://proyecto26.github.io/react-native-inappbrowser/`
    const redirectUrl = this.getDeepLink('home')
    const url = `${redirectToURL}?redirect_url=${encodeURIComponent(redirectUrl)}`
    try {
      if (await InAppBrowser.isAvailable()) {
        const result = await InAppBrowser.openAuth(url, redirectUrl)
        await this.sleep(800)
        Alert.alert('Response', JSON.stringify(result))
      } else {
        // You can use Linking directly for iOS < 9
      }
    } catch (error) {
      Alert.alert('Something’s wrong with the app :(')
    }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM