A React Native payment SDK supporting Cards, UPI, and Net Banking
Before starting integration, ensure the following are installed and configured:
- Node.js (>= 16.x)
- npm or yarn
- Watchman (macOS recommended)
- Xcode (latest) with Command Line Tools β required for iOS
- CocoaPods β run: sudo gem install cocoapods
- Android Studio with:
- Android SDK Platform 36
- Android SDK Build-Tools 36
- NDK 27.x
- CMake 3.22.x
- Java 17 (Recommended for RN 0.73+)
- Physical device or emulators for Android & iOS testing
- React Native CLI installed globally (optional)
npm install -g react-native-cli
A complete React Native SDK to integrate Jio Payment Gateway supporting Cards, UPI, and Net Banking.
This guide provides stepβbyβstep setup for Android and iOS including Metro config, Gradle config, permissions, Pods setup, and a sample implementation.
Latest Stable: 1.3.1
> Note: This version is automatically updated from package.json. No manual updates needed!
- β
Fixed Metro Bundler Module Resolution - Resolved index.js resolution errors
- β
Improved Package Structure - Added exports field for better module resolution
- β
React Native 0.82+ Compatibility - Full support for latest React Native versions
- β
Removed Invalid Types Reference - Fixed package.json structure
Installation:
``bash`
npm install jio-payment-sdk@1.3.1 --legacy-peer-deps
---
`bash`
npm install -g react-native-cli
---
`bash`
npx @react-native-community/cli init JioPGMerchantAppSample
or specify RN version:
`bash`
npx @react-native-community/cli init JioPGMerchantAppSample --version 0.73.6
For iOS builds, when asked:
``
Do you want to install CocoaPods now? β y
---
cd JioPGMerchantAppSample
npx react-native run-android
`$3
`
cd JioPGMerchantAppSample
npx react-native run-ios
`
or open:
`
ios/JioPGMerchantAppSample.xcworkspace
`---
π 4. Install SDK from NPM
Install the latest version of the SDK:
`bash
npm install jio-payment-sdk@latest --legacy-peer-deps
`Current Version:
1.3.1> Note: Use
--legacy-peer-deps flag to handle peer dependency conflicts with React Native 0.82+---
π 5. Update
package.json DependenciesAdd these inside
"dependencies":`json
"dependencies": {
"@react-navigation/native": "^6.1.6",
"@react-navigation/native-stack": "^6.9.12",
"axios": "^1.5.0",
"crypto-js": "^4.2.0",
"jio-payment-sdk": "^1.3.1",
"@babel/runtime": "^7.28.4",
"react-native-fast-image": "^8.6.3",
"react-native-gif": "^1.0.3",
"react-native-qrcode-svg": "^6.3.15",
"react-native-screens": "^4.13.1",
"react-native-svg": "^15.12.1",
"react-native-vector-icons": "^10.3.0",
"react-native-webview": "^13.15.0"
}
`> Important: Ensure you're using SDK version
1.3.1 or later for React Native 0.82+ compatibility.Then run:
`bash
npm install --legacy-peer-deps
`---
π 6. Install iOS Pods
`bash
cd ios
pod install
cd ..
`---
π 7. Clean Android Build
`bash
cd android
./gradlew clean
cd ..
`---
π 8. Update Android Build Config (
android/build.gradle)`
buildscript {
ext {
buildToolsVersion = "36.0.0"
minSdkVersion = 29
compileSdkVersion = 36
targetSdkVersion = 36
ndkVersion = "27.1.12297006"
kotlinVersion = "2.1.20"
FLIPPER_VERSION = "0.0.0"
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
}
}apply plugin: "com.facebook.react.rootproject"
`---
π 9. Android App Build Config (
android/app/build.gradle)Inside
android { ... }`
namespace "com.jiopgmerchantappsample"defaultConfig {
versionName "1.0"
externalNativeBuild {
cmake {
cppFlags "-Wno-deprecated-declarations"
}
}
}
lintOptions {
abortOnError false
checkReleaseBuilds false
}
`---
π 10. Add Android Permissions & Queries (
AndroidManifest.xml)`
`Inside
:`
android:usesCleartextTraffic="true"
`(Set
false for production)---
π 11. MainApplication.kt (Android)
Use:
`
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List =
PackageList(this).packages override fun getJSMainModuleName(): String = "index"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
override val reactHost: ReactHost
get() = getDefaultReactHost(applicationContext, reactNativeHost)
override fun onCreate() {
super.onCreate()
loadReactNative(this)
}
}
`---
π 12. Metro Configuration (
metro.config.js)`
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const path = require('path');const sdkPath = path.resolve(__dirname, 'node_modules/jio-payment-sdk');
const defaultConfig = getDefaultConfig(__dirname);
module.exports = mergeConfig(defaultConfig, {
resolver: {
sourceExts: [
...defaultConfig.resolver.sourceExts,
'ts','tsx','jsx','cjs',
],
extraNodeModules: {
react: path.resolve(__dirname, 'node_modules/react'),
'react-native': path.resolve(__dirname, 'node_modules/react-native'),
},
unstable_enablePackageExports: true,
},
transformer: {
unstable_allowRequireContext: true,
minifierConfig: {
keep_classnames: true,
keep_fnames: true,
mangle: false,
},
},
watchFolders: [sdkPath],
});
`---
π 13. Sample Integration (App.tsx)
Important: When the user cancels (e.g. taps back on the Checkout screen), the SDK calls
onError with error.message === 'CANCELLED' and optionally onRequestClose. The host app must unmount or hide the PaymentSDK (e.g. set showPayment to false) so the payment screen closes. Otherwise the back button will appear to do nothing.`tsx
import React, { useState } from 'react';
import {
View, Text, TouchableOpacity, ScrollView, StyleSheet, StatusBar
} from 'react-native';
import { SafeAreaProvider, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { PaymentSDK, PaymentMode, EnvironmentType, CANCELLED_ERROR_MESSAGE } from 'jio-payment-sdk';function App() {
return (
);
}
function AppContent() {
const [showPayment, setShowPayment] = useState(false);
const [successResponse, setSuccessResponse] = useState(null);
const priceSummary = {
subtotal: 100,
tax: 18,
total: 118,
};
const onSuccess = data => setSuccessResponse(data);
const onError = err => {
setSuccessResponse(err);
// Close payment UI when user cancels (e.g. back on Checkout)
if (err?.message === CANCELLED_ERROR_MESSAGE) {
setShowPayment(false);
}
};
const onRequestClose = () => setShowPayment(false);
const onTimeout = data => setSuccessResponse(data);
if (showPayment) {
const txn_no =
TXN_NO_${Date.now()};
return (
amount={priceSummary.total}
merchantId="JP3000000666666"
aggregatorId="JP4000000765432"
customerName="John Doe"
customerEmail="john.doe@example.com"
merchantName="Jio Payment Demo"
merchantImage="https://yourlogo.png"
merchantTransactionNumber={txn_no}
onSuccess={onSuccess}
onError={onError}
onRequestClose={onRequestClose}
secretKey="your_secret_key"
environment={EnvironmentType.UAT}
//Below are optional parameters
// customerMobileNumber='9875431234'
// themePrimaryColor="#FF6B6B"
// themeSecondaryColor="#FF6B6B"
// allowedPaymentModes={[PaymentMode.CARD, PaymentMode.UPI, PaymentMode.NETBANKING]}
/>
);
}
return (
setShowPayment(true)}>
Proceed to Payment
Callback Response:
{JSON.stringify(successResponse)}
);
}
export default App;
`$3
-
onError(error) β When the user cancels (e.g. back on Checkout), the SDK calls this with error.message === 'CANCELLED'. The host should unmount or hide the PaymentSDK so the screen closes.
- onRequestClose() β Called when the user requests to close the payment flow (e.g. back on Checkout). Implement this to set your "show payment" state to false so the SDK is unmounted. Using both onError (check for CANCELLED) and onRequestClose ensures the back button works regardless of integration style.---
π 14. Starting Metro
`
npm start
`If Metro gets stuck or you encounter module resolution errors:
`bash
Clear Metro cache and restart
rm -rf node_modules/.cache
npx react-native start --reset-cache
`If Metro is stuck on a port:
`bash
lsof -i :8081
kill -9
`Troubleshooting Metro Issues:
- If you see errors about
index.js not being found, ensure you're using SDK version 1.1.7+
- Clear Metro cache: npx react-native start --reset-cache
- Verify SDK installation: npm list jio-payment-sdk---
π 15. Run Android App
`
cd android
./gradlew clean
cd ..
npx react-native run-android
`---
π 16. iOS Podfile Required Config
Inside
ios/Podfile:`
use_react_native!(
:path => config[:reactNativePath],
:app_path => "#{Pod::Config.instance.installation_root}/..",
:new_arch_enabled => true,
:fabric_enabled => true
)
`---
π 17. Run iOS App
`
cd ios
pod install --repo-update
cd ..
npx react-native run-ios
`If build fails β open Xcode and build manually.
---
β
Integration Complete
You should now have the Jio Payment SDK working on both Android & iOS with correct Codegen, Metro config, permissions, Gradle setup, and sample payment flow.
---
π§ Troubleshooting
$3
If you encounter errors like:
`
Unable to resolve module jio-payment-sdk from file...
the package itself specifies a main module field that could not be resolved
`Solution:
1. Ensure you're using SDK version
1.3.1 or later:
`bash
npm install jio-payment-sdk@latest --legacy-peer-deps
`2. Clear Metro cache:
`bash
rm -rf node_modules/.cache
npx react-native start --reset-cache
`3. Verify the SDK package structure:
`bash
ls node_modules/jio-payment-sdk/
# Should show: index.js, package.json, src/, assets/, etc.
`$3
Version
1.1.7 includes important fixes:
- β
Removed invalid types field reference
- β
Added exports field for better module resolution
- β
Fixed Metro bundler compatibility with React Native 0.82+$3
Issue: App crashes on launch with SDK import error
- Fix: Update to
jio-payment-sdk@1.3.1+ and clear Metro cacheIssue:
@babel/runtime not found
- Fix: Install it: npm install @babel/runtime --legacy-peer-depsIssue: Android build fails
- Fix: Clean build:
cd android && ./gradlew clean && cd ..`---
Recommended: Always use the latest version for best compatibility.
---