Learn in detail about our custom checkout integration for iOS.
The iOS integration can be completed in three steps and should not take you more than 30 minutes.
Integration Flow
This integration requires your application’s bundle name to be whitelisted by Cashfree Payments. Please check Whitelisting Process
Please follow the steps mentioned in this link to create an order. This will return a “payment_session_id” value which will be used later.
Don’t forget to provide the return URL while creating the order as this will be used to detect payment completion.
String platform = "iosx-c-x-x-x-w-x-a-" + <BuildVersion>;
String session = "PAYMENT_SESSION_ID";
func createForm(session: String, platform: String) -> String {
var secureURL = ""
if CFConstants.environment == .SANDBOX {
secureURL = "https://sandbox.cashfree.com/pg/view/sessions/checkout"
} else {
secureURL = "https://api.cashfree.com/pg/view/sessions/checkout"
}
var paymentInputFormHtml =
"<html>"
+ "<body>"
+ "<form id=\'redirectForm\' name=\'order\' action=\'\(secureURL)\' method=\'post\'>"
paymentInputFormHtml += "<input type=\'hidden\' name=\'payment_session_id\' value=\'\(session)\'/>" +
"<input type=\'hidden\' name=\'platform\' value=\'\(platform)\'/>" +
"</form>" +
"<script\n" +
" type=\"text/javascript\">\t window.onload = function () { const form = document.getElementById(\"redirectForm\"); const meta = { userAgent: window.navigator.userAgent, }; const sortedMeta = Object.entries(meta).sort().reduce((o, [k, v]) => { o[k] = v; return o; }, {}); const base64Meta = btoa(JSON.stringify(sortedMeta)); FN = document.createElement('input'); FN.setAttribute('type', 'hidden'); FN.setAttribute('name', 'browser_meta'); FN.setAttribute('value', base64Meta); form.appendChild(FN); form.submit(); } </script>\n"
+ "</body>"
+ "</html>";
return paymentInputFormHtml
}
override func viewDidLoad(){
self.cfWebView.loadHTMLString(createForm(session: session_id, platform: "") , baseURL: nil)
}
Once the payment flow has ended, Cashfree Payments will redirect you to the URL specified while creating the order. Detect the URL redirection and close the web view appropriately.
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
// Allowing all navigations
decisionHandler(.allow)
if navigationAction.request.url?.absoluteString ?? "" == "your return_url" {
// close the web view
}
}
If you are doing a custom integration of Cashfree Payments Web Checkout in iOS and want to add UPI intent functionality, follow the steps below. Read more about UPI Intent functionality here.
Add the permissions in info.plist file.
You need to add the following to your info.plist
<key>LSApplicationCategoryType</key>
<string></string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>bhim</string>
<string>paytmmp</string>
<string>phonepe</string>
<string>tez</string>
<string>credpay</string>
</array>
Add the JSBridge functions for the checkout page to get the list of UPI apps installed and for opening the UPI app selected by the user.
override func viewDidLoad() {
super.viewDidLoad()
self.cfWebView.configuration.userContentController.add(self, name: "nativeProcess")
self.cfWebView.uiDelegate = self
self.cfWebView.navigationDelegate = self
}
func getInstalledUPIApplications() -> [[String: String]] {
var installedApps = [[String: String]]()
let appName = [
[
"displayName": CFConstants.googlePayName,
"id": "tez://",
"icon": (UIImage(named: "gpay", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
],
[
"displayName": CFConstants.paytmName,
"id": "paytmmp://",
"icon": (UIImage(named: "paytm", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
],
[
"displayName": CFConstants.phonePeName,
"id": "phonepe://",
"icon": (UIImage(named: "phonepe", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
],
[
"displayName": CFConstants.bhimName,
"id": "bhim://",
"icon": (UIImage(named: "bhim", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
],
[
"displayName": CFConstants.credName,
"id": "credpay://",
"icon": (UIImage(named: "credpay", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
]
]
for app in appName {
let url = app["id"] ?? ""
if UIApplication.shared.canOpenURL(URL(string: url)!) {
installedApps.append(app)
}
}
return installedApps
}
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
var msg = message.body as? String ?? ""
if msg == "getAppList" {
let installedApps = getInstalledUPIApplications()
do {
let jsonData = try JSONSerialization.data(withJSONObject: installedApps, options: [])
let jsonString = String(data: jsonData, encoding: String.Encoding.utf8)!
self.cfWebView.evaluateJavaScript("window.receiveAppList(\(jsonString))") { (_, _) in
}
} catch {
print("Serialisation Failed")
}
} else if msg.contains("paytm") || msg.contains("phonepe") || msg.contains("tez") || msg.contains("bhim") || msg.contains("credpay") {
if msg.contains("paytm") {
msg = msg.replacingOccurrences(of: "paytm:", with: "paytmmp:")
}
self.cfWebView.evaluateJavaScript("verifyPaymentForiOS()") { (val, error) in
let url = URL(string: msg)!
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:]) { (response) in
}
}
}
}
}
}
class CF2FAWebViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate {
@IBOutlet weak var cfWebView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.cfWebView.configuration.userContentController.add(self, name: "nativeProcess")
self.cfWebView.uiDelegate = self
self.cfWebView.navigationDelegate = self
self.cfWebView.loadHTMLString(createForm(session: session_id, platform: "") , baseURL: nil)
}
func getInstalledUPIApplications() -> [[String: String]] {
var installedApps = [[String: String]]()
let appName = [
[
"displayName": CFConstants.googlePayName,
"id": CFConstants.googlePayPackage,
"icon": (UIImage(named: "gpay", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
],
[
"displayName": CFConstants.paytmName,
"id": CFConstants.paytmPackage,
"icon": (UIImage(named: "paytm", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
],
[
"displayName": CFConstants.phonePeName,
"id": CFConstants.phonePePackage,
"icon": (UIImage(named: "phonepe", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
],
[
"displayName": CFConstants.bhimName,
"id": CFConstants.bhimPackage,
"icon": (UIImage(named: "bhim", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
],
[
"displayName": CFConstants.credName,
"id": CFConstants.credPackage,
"icon": (UIImage(named: "credpay", in: Bundle(for: CFUPIUtils.self), compatibleWith: nil)!).toBase64() ?? ""
]
]
for app in appName {
let url = app["id"] ?? ""
if UIApplication.shared.canOpenURL(URL(string: url)!) {
installedApps.append(app)
}
}
return installedApps
}
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
// Allowing all navigations
decisionHandler(.allow)
if navigationAction.request.url?.absoluteString ?? "" == "your return_url" {
// close the web view
}
}
func createForm(session: String, platform: String) -> String {
var secureURL = ""
if CFConstants.environment == .SANDBOX {
secureURL = "https://sandbox.cashfree.com/pg/view/sessions/checkout"
// secureURL = "https://test-k8s.cashfree.com/pgnextgenapi/api/v1/view/sessions/checkout"
} else {
secureURL = "https://api.cashfree.com/pg/view/sessions/checkout"
// secureURL = "https://prod.cashfree.com/pgnextgenapi-test/api/v1/view/sessions/checkout"
}
var paymentInputFormHtml =
"<html>"
+ "<body>"
+ "<form id=\'redirectForm\' name=\'order\' action=\'\(secureURL)\' method=\'post\'>"
paymentInputFormHtml += "<input type=\'hidden\' name=\'payment_session_id\' value=\'\(session)\'/>" +
"<input type=\'hidden\' name=\'platform\' value=\'\(platform)\'/>" +
"</form>" +
"<script\n" +
" type=\"text/javascript\">\t window.onload = function () { const form = document.getElementById(\"redirectForm\"); const meta = { userAgent: window.navigator.userAgent, }; const sortedMeta = Object.entries(meta).sort().reduce((o, [k, v]) => { o[k] = v; return o; }, {}); const base64Meta = btoa(JSON.stringify(sortedMeta)); FN = document.createElement('input'); FN.setAttribute('type', 'hidden'); FN.setAttribute('name', 'browser_meta'); FN.setAttribute('value', base64Meta); form.appendChild(FN); form.submit(); } </script>\n"
+ "</body>"
+ "</html>";
return paymentInputFormHtml
}
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
var msg = message.body as? String ?? ""
if msg == "getAppList" {
let installedApps = getInstalledUPIApplications()
do {
let jsonData = try JSONSerialization.data(withJSONObject: installedApps, options: [])
let jsonString = String(data: jsonData, encoding: String.Encoding.utf8)!
self.cfWebView.evaluateJavaScript("window.receiveAppList(\(jsonString))") { (_, _) in
}
} catch {
print("Serialisation Failed")
}
} else if msg.contains("paytm") || msg.contains("phonepe") || msg.contains("tez") || msg.contains("bhim") || msg.contains("credpay") {
if msg.contains("paytm") {
msg = msg.replacingOccurrences(of: "paytm:", with: "paytmmp:")
}
self.cfWebView.evaluateJavaScript("verifyPaymentForiOS()") { (val, error) in
let url = URL(string: msg)!
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:]) { (response) in
}
}
}
}
}
}
Was this page helpful?