Any Payment gateway in React Native using Webview (No need for Java / Native Module)
React Native developers who are not familiar with Java, face many difficulties in developing native modules. This article will show you how to integrate any payment gateway into your application without using any additional plugin. Here, we will integrate one such payment gateway — PayU money.
This solution works for both Android as well as iOS
Pre Requisite: Payment Gateway account, ReactNative, knowledge of PHP would be the cherry on the top.
1. Configure my_payuform_on_my_server.php
This file is required for setting up a gateway on the web, which will then be called from the react-native webview module. It contains the checkout form consisting of the payment gateway’s fields(in this case, key, hash, txnid, amount, email, etc). Refer to PayU money web SDK for more details.
Why the HTML body is display: none?
Because we don’t want this to be visible on the app.
What we will do with this form?
We will pass react-native checkout form data to this HTML form(Step 2) and auto submit it on load after which the payment detail form is shown generally.
<?php$MERCHANT_KEY = "XXXXXX";
$SALT = "YYYYYY";
// Merchant Key and Salt as provided by Payu.// For Sandbox Mode
// $PAYU_BASE_URL = "https://sandboxsecure.payu.in";// For Production Mode
$PAYU_BASE_URL = "https://secure.payu.in"; $action = '';$posted = array();
if (!empty($_POST)) {
foreach ($_POST as $key => $value) {
$posted[$key] = $value;
}
}$formError = 0;if (empty($posted['txnid'])) {
// Generate random transaction id
$txnid = substr(hash('sha256', mt_rand() . microtime()), 0, 20);
} else {
$txnid = $posted['txnid'];
}
$hash = '';
// Hash Sequence
$hashSequence = "key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5|udf6|udf7|udf8|udf9|udf10";
if (empty($posted['hash']) && sizeof($posted) > 0) {
if (
empty($posted['key'])
|| empty($posted['txnid'])
|| empty($posted['amount'])
|| empty($posted['firstname'])
|| empty($posted['email'])
|| empty($posted['phone'])
|| empty($posted['productinfo'])
|| empty($posted['surl'])
|| empty($posted['furl'])
|| empty($posted['service_provider'])
) {
$formError = 1;
} else {
$hashVarsSeq = explode('|', $hashSequence);
$hash_string = '';
foreach ($hashVarsSeq as $hash_var) {
$hash_string .= isset($posted[$hash_var]) ? $posted[$hash_var] : '';
$hash_string .= '|';
} $hash_string .= $SALT; $hash = strtolower(hash('sha512', $hash_string));
$action = $PAYU_BASE_URL . '/_payment';
}
} elseif (!empty($posted['hash'])) {
$hash = $posted['hash'];
$action = $PAYU_BASE_URL . '/_payment';
}//log
file_put_contents('logs.txt', date('Y-m-d H:i:s') . ' :payu_popup data:' . PHP_EOL . json_encode(array_map('utf8_encode', $posted)) . PHP_EOL . '---------------------' . PHP_EOL, FILE_APPEND);
?><html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script>
var hash = '<?php echo $hash ?>'; function submitPayuForm() {
if (hash == '') {
return;
}
var payuForm = document.forms.payuForm;
payuForm.submit();
}
</script>
</head><body onload="submitPayuForm()" style="display:none">
<h2>PayU Form</h2>
<br />
<?php if ($formError) { ?> <span style="color:red">Please fill all mandatory fields.</span>
<br />
<br />
<?php } ?>
<form action="<?php echo $action; ?>" method="post" name="payuForm">
<input type="hidden" name="key" value="<?php echo $MERCHANT_KEY ?>" />
<input type="hidden" name="hash" value="<?php echo $hash ?>" />
<input type="hidden" name="txnid" value="<?php echo $txnid ?>" />
<table>
<tr>
<td><b>Mandatory Parameters</b></td>
</tr>
<tr>
<td>Amount: </td>
<td><input name="amount" id="amount" value="<?php echo (empty($posted['amount'])) ? '' : $posted['amount'] ?>" /></td>
<td>First Name: </td>
<td><input name="firstname" id="firstname" value="<?php echo (empty($posted['firstname'])) ? '' : $posted['firstname']; ?>" /></td>
</tr>
<tr>
<td>Email: </td>
<td><input name="email" id="email" value="<?php echo (empty($posted['email'])) ? '' : $posted['email']; ?>" /></td>
<td>Phone: </td>
<td><input name="phone" id="phone" value="<?php echo (empty($posted['phone'])) ? '' : $posted['phone']; ?>" /></td>
</tr>
<tr>
<td>Product Info: </td>
<td colspan="3"><textarea id="productinfo" name="productinfo"><?php echo (empty($posted['productinfo'])) ? '' : $posted['productinfo'] ?></textarea></td>
</tr>
<tr>
<td>Success URI: </td>
<td colspan="3"><input type="hidden" name="surl" value="my_success.php" size="64" /></td>
</tr>
<tr>
<td>Failure URI: </td>
<td colspan="3"><input type="hidden" name="furl" value="my_failure.php" size="64" /></td>
</tr> <tr>
<td colspan="3"><input type="hidden" name="service_provider" value="payu_paisa" size="64" /></td>
</tr> <tr>
<td><b>Optional Parameters</b></td>
</tr>
<tr>
<td>Last Name: </td>
<td><input name="lastname" id="lastname" value="<?php echo (empty($posted['lastname'])) ? '' : $posted['lastname']; ?>" /></td>
<td>Cancel URI: </td>
<td><input name="curl" value="my_failure.php" /></td>
</tr>
<tr>
<td>Address1: </td>
<td><input name="address1" id="address1" value="<?php echo (empty($posted['address1'])) ? '' : $posted['address1']; ?>" /></td>
<td>Address2: </td>
<td><input name="address2" id="address2" value="<?php echo (empty($posted['address2'])) ? '' : $posted['address2']; ?>" /></td>
</tr>
<tr>
<td>City: </td>
<td><input name="city" id="city" value="<?php echo (empty($posted['city'])) ? '' : $posted['city']; ?>" /></td>
<td>State: </td>
<td><input name="state" id="state" value="<?php echo (empty($posted['state'])) ? '' : $posted['state']; ?>" /></td>
</tr>
<tr>
<td>Country: </td>
<td><input name="country" value="<?php echo (empty($posted['country'])) ? '' : $posted['country']; ?>" /></td>
<td>Zipcode: </td>
<td><input name="zipcode" value="<?php echo (empty($posted['zipcode'])) ? '' : $posted['zipcode']; ?>" /></td>
</tr>
<tr>
<td>UDF1: </td>
<td><input name="udf1" value="<?php echo (empty($posted['udf1'])) ? '' : $posted['udf1']; ?>" /></td>
<td>UDF2: </td>
<td><input name="udf2" value="<?php echo (empty($posted['udf2'])) ? '' : $posted['udf2']; ?>" /></td>
</tr>
<tr>
<td>UDF3: </td>
<td><input name="udf3" value="<?php echo (empty($posted['udf3'])) ? '' : $posted['udf3']; ?>" /></td>
<td>UDF4: </td>
<td><input name="udf4" value="<?php echo (empty($posted['udf4'])) ? '' : $posted['udf4']; ?>" /></td>
</tr>
<tr>
<td>UDF5: </td>
<td><input name="udf5" value="<?php echo (empty($posted['udf5'])) ? '' : $posted['udf5']; ?>" /></td>
<td>PG: </td>
<td><input name="pg" value="<?php echo (empty($posted['pg'])) ? '' : $posted['pg']; ?>" /></td>
</tr>
<tr>
<?php if (!$hash) { ?>
<td colspan="4"><input type="submit" value="Submit" /></td>
<?php } ?>
</tr>
</table>
</form>
</body></html>
This will be uploaded on a server. www.example.com/my_payuform_on_my_server.php
2. My React Native PayUMoney component
When we click on the pay now button from the checkout page of the app, this component will bind the checkout form data to the file created above. It will open modal containing hidden form(my_payuform_on_my_server.php
). The form will automatically get filled using injectedJavaScript={runFirst}
and will get auto-submitted on load.
import React from 'react';
import {StyleSheet, View, Modal} from 'react-native';
import {Button, Text} from 'native-base';
import {WebView} from 'react-native-webview';
import styles from './styles';
class PayUMoney extends React.Component {
constructor(props) {
super(props);
this.myWebView;
this.state = {
response: '',
};
}
render() {
const {
visible,
getMagicResponse,
paymentOptions: {amount, productinfo, firstname, lastname, email, phone},
} = this.props;
const runFirst = `
document.getElementById("amount").value = '${amount}';
document.getElementById("firstname").value = '${firstname}';
document.getElementById("lastname").value = '${lastname}';
document.getElementById("email").value = '${email}';
document.getElementById("phone").value = '${phone}';
document.getElementById("productinfo").value = '${productinfo}';
setTimeout(() => {
document.forms.payuForm.submit();
}, 200);
`;
return (
<Modal
animationType={'slide'}
visible={visible}
onRequestClose={() => {}}>
<View style={styles.modalView}>
<WebView
ref={el => (this.myWebView = el)}
startInLoadingState={true}
useWebKit={false}
javaScriptEnabled={true}
domStorageEnabled={true}
scalesPageToFit={true}
automaticallyAdjustContentInsets={true}
injectedJavaScript={runFirst}
onMessage={event => {
let response = JSON.parse(event.nativeEvent.data);
getMagicResponse(response);
}}
source={{
uri: 'http://www.example.com/my_payuform_on_my_server.php',
}}
/>
</View>
</Modal>
);
}
}
export default PayUMoney;
3. success.php file
(failure.php file also be the same as this).
Configure the return URL to this file in the PayU admin setting. Url will be something like www.example.com/success.php. window.ReactNativeWebView.postMessage(success_response)
will send data from browser(webview) to React Native environment and onMessage
will capture the response and forward it togetMagicResponse
function(Step 2).
<?php$returnArray = [];
$returnArray['status'] = $_POST['status'];
$returnArray['txnid'] = $_POST['txnid'];
$returnArray['amount'] = $_POST['amount'];
$returnArray['firstname'] = $_POST['firstname'];
$returnArray['addedon'] = $_POST['addedon'];
$returnArray['productinfo'] = $_POST['productinfo'];
$returnArray['lastname'] = $_POST['lastname'];
$returnArray['email'] = $_POST['email'];
$returnArray['phone'] = $_POST['phone'];$success_response = json_encode(array_map('utf8_encode', $returnArray));?><script>
var success_response = '<?php echo $success_response; ?>';
window.ReactNativeWebView.postMessage(success_response);
</script>
4. Include our PayUMoney component (Optional)
The functionalities of this component can be a part of the PayUMoney component itself. But it is highly recommended to create a separate component for best practices. This component is used to handle the response of the payment gateway. getMagicResponse
is passed to the payUMoney component as a prop. You can see it in step 2.
getMagicResponse(resp) {
//console.log(resp);
if (resp.status === 'success') {
//do whatever u want
}
}render(){
PayUModalVisibility && (
<PayUMoney
visible={PayUModalVisibility}
onCloseModal={() =>
this.setState({PayUModalVisibility: false, billingData: []})
}
getMagicResponse={magicResponse =>
this.getMagicResponse(magicResponse)
}
paymentOptions={onlineObj}
/>
)}
Voila!
Almost all the payment gateways follow the same structure.
Reference:
https://developer.payumoney.com/payumoney-php-integration-guide/