Brief: In this post we can see how to integrate payment gateway using RazorPay in Xamarin form for iOS and Android.
Right now i'm seeing very limited support for Xamarin with payment SDK from the top payment gateway providers like Stripe,RazorPay,PayU,JustPay. Few are providing the SDK but that is outdated and not supporting in the latest version.
Even RazorPay does not support with any SDK for Xamarin but we can use binding library created on top of native SDK, but for iOS even binding library doesn't work so alternate approach here taken is Webview based payment with proper callbacks.
User interface output is very identical for Webview and SDK based payment, but few options looks like restricted in webview as there is some restrictions for opening popup from iOS WKWebview, more details in razor pay document page.
Need to be cautious with webview based payment as it has certain limitation like Netbanking is not supported as it tries to open view window which is not supported inside webview. So the Netbanking option is hidden in the below example.
Before getting started need to create Razorpay_key and Razorpay_password from razor pay dashboard.
Code:
Add new Content page for Webview in common project and create CustomRenderer for the same.
CustomWebView.cs: | |
using System; | |
using Xamarin.Forms; | |
namespace CustomControls | |
{ | |
public class CustomWebView : WebView | |
{ | |
} | |
} | |
PaymentWebViewPage.xaml: | |
<?xml version="1.0" encoding="utf-8" ?> | |
<ContentPage xmlns:pages="clr-namespace:Views" | |
xmlns="http://xamarin.com/schemas/2014/forms" | |
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | |
xmlns:customControls="clr-namespace:CustomControls" | |
x:Name="PaymentWebViewPage" | |
x:Class="MyPlans.PaymentWebViewPage"> | |
<ContentPage.Content> | |
<customControls:CustomWebView VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"> | |
</customControls:CustomWebView> | |
</ContentPage.Content> | |
</ContentPage> |
Implement Custom renderer for iOS:
using System; | |
using Diet.iOS.CustomRenderer; | |
using UIKit; | |
using Xamarin.Forms; | |
using Xamarin.Forms.Platform.iOS; | |
using WebKit; | |
using Foundation; | |
using System.Net.Http; | |
using Newtonsoft.Json; | |
using System.Net.Http.Headers; | |
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))] | |
namespace CustomRenderer | |
{ | |
public class CustomWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler | |
{ | |
public CustomWebViewRenderer() | |
{ | |
} | |
protected override void OnElementChanged(VisualElementChangedEventArgs e) | |
{ | |
base.OnElementChanged(e); | |
if (e.NewElement != null) | |
{ | |
LoadCustomWebview(); | |
} | |
} | |
async private void LoadCustomWebview() | |
{ | |
RazorPayload payload = new RazorPayload(); | |
payload.amount = Constant.NetPayableAmount * 100; | |
payload.currency = "INR"; | |
payload.receipt = GenerateRefNo(); | |
payload.payment_capture = 1; | |
RazorResp resp; | |
using (var httpClient = new HttpClient()) | |
{ | |
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.razorpay.com/v1/orders")) | |
{ | |
var plainTextBytes = Encoding.UTF8.GetBytes($"{Constants.RazorPay_Key}:{Constants.RazorPay_Secret}"); | |
var basicAuthKey = Convert.ToBase64String(plainTextBytes); | |
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {basicAuthKey}"); | |
string jsonData = JsonConvert.SerializeObject(payload); | |
request.Content = new StringContent(jsonData); | |
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); | |
var response = await httpClient.SendAsync(request); | |
string jsonResp = await response.Content.ReadAsStringAsync(); | |
resp = JsonConvert.DeserializeObject<RazorResp>(jsonResp); | |
} | |
} | |
var js = @" <body onload=""openpaymentscreen()""> | |
<script src=""https://checkout.razorpay.com/v1/checkout.js""></script> | |
<script> | |
var options = { | |
""key"": ""@key@"", | |
""amount"": ""@amount@"", | |
""currency"": ""INR"", | |
""name"": ""CodeLog"", | |
""description"": ""AppliedCodeLog"", | |
""order_id"": ""@orderid@"", | |
""handler"": function (response){ | |
window.webkit.messageHandlers.PaymentJSBridge.postMessage(response) | |
}, | |
""modal"": { | |
""ondismiss"": function(){ | |
window.webkit.messageHandlers.PaymentJSBridge.postMessage(""closed"") | |
} | |
}, | |
""prefill"": { | |
""name"": ""@name@"", | |
""email"": ""@email@"", | |
""contact"": ""@contact@"" | |
}, | |
""config"": { | |
""display"": { | |
""hide"": [{ | |
method: ""netbanking"" | |
}] | |
} | |
}, | |
""notes"": { | |
""address"": "" address here"" | |
}, | |
""theme"": { | |
""color"": ""#ee3a70"" | |
} | |
}; | |
var rzp1 = new Razorpay(options); | |
rzp1.on('payment.failed', function (response){ | |
window.webkit.messageHandlers.PaymentJSBridge.postMessage(response); | |
}); | |
function openpaymentscreen() | |
{ | |
rzp1.open(); | |
} | |
</script></body>"; | |
//#33nine ninecc | |
js = js.Replace("@orderid@", resp.id.ToString()); | |
js = js.Replace("@amount@", (Constant.NetPayableAmount * 100; * 100).ToString()); | |
js = js.Replace("@key@", Constants.RazorPay_Key); | |
js = js.Replace("@name@", Constant.name?.ToString()); | |
js = js.Replace("@email@", Constant.email?.ToString()); | |
js = js.Replace("@contact@", Constant.mobileNumber?.ToString()); | |
Configuration.Preferences.JavaScriptCanOpenWindowsAutomatically = true; | |
Configuration.Preferences.JavaScriptEnabled = true; | |
LoadHtmlString((NSString)js, null); | |
var _userController = Configuration.UserContentController; | |
_userController.AddScriptMessageHandler(this, "PaymentJSBridge"); | |
} | |
} | |
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message) | |
{ | |
MessagingCenter.Send("Message", "ClosePaymentPage");//call back to close the current contentpage | |
var result = message?.Body; | |
if (result != null && result.ToString() != new NSString("closed")) | |
{ | |
var paymentId = result.ValueForKey(new NSString("razorpay_payment_id")); | |
var orderId = result.ValueForKey(new NSString("razorpay_order_id")); | |
var signatureId = result.ValueForKey(new NSString("razorpay_signature")); | |
var error = result.ValueForKey(new NSString("error")); | |
if (string.IsNullOrEmpty(error?.ToString())) | |
{ | |
MessagingCenter.Send<RazorPayPaymentData>("paymentId", eventKey); | |
} | |
else | |
{ | |
MessagingCenter.Send<RazorPayPaymentData>("error", eventKey); | |
} | |
} | |
} | |
public static string GenerateRefNo() | |
{ | |
string refNo = ""; | |
Random ran = new Random(); | |
String b = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
int length = 6; | |
String random = ""; | |
for (int i = 0; i < length; i++) | |
{ | |
int a = ran.Next(26); | |
random = random + b.ElementAt(a); | |
} | |
int d = ran.Next(100000, 999999); | |
refNo = $"{random}{d}"; | |
return refNo; | |
} | |
public class RazorPayload | |
{ | |
public int amount { get; set; } | |
public string currency { get; set; } | |
public string receipt { get; set; } | |
public int payment_capture { get; set; } | |
} | |
} | |
} |
Android Custom renderer:
For Android i prefer the razorpay SDK created by using binding library. Still we can use the webview based implementation for Android in similar way as we did for iOS. We can follow this below link for reference:
https://razorpay.com/docs/payments/payment-gateway/web-integration/standard/webview/
RazorPay sdk based payment:
Download the binding project created for RazorPay SDK in Xamarin.Android using link RazorPayAndroidBindingLibrary.
Build the binding project and create the dll's and the project reference for your project.
Create the dependency service for the pay button click event and follow the below code.
using Com.Razorpay; | |
using System.Net.Http; | |
using Newtonsoft.Json | |
using Xamarin.Forms; | |
[assembly: Dependency(typeof(PaymentInterface))] | |
namespace PlatformServices | |
{ | |
public class PaymentInterface :IPaymentInterface | |
{ | |
public void OnPaymentError(int p0, string p1, PaymentData p2) | |
{ | |
var orderId = p2.OrderId; | |
var paymentId = p2.PaymentId; | |
var PaymentFailureError = p1; | |
} | |
public void OnPaymentSuccess(string p0, PaymentData p1) | |
{ | |
var orderId = p1.OrderId; | |
var paymentId = p1.PaymentId; | |
} | |
public async Task PayViaRazor() | |
{ | |
RazorPayload payload = new RazorPayload(); //update model class | |
payload.amount = (int)amount * 100; | |
payload.currency = "INR"; | |
payload.receipt = Helper.GenerateRefNo(); //refer the above method | |
payload.payment_capture = 1; | |
using (var httpClient = new HttpClient()) | |
{ | |
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.razorpay.com/v1/orders")) | |
{ | |
var plainTextBytes = Encoding.UTF8.GetBytes($"{RazorPay_Key}:{RazorPay_Secret}"); //update razorpay credentials here | |
var basicAuthKey = Convert.ToBase64String(plainTextBytes); | |
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {basicAuthKey}"); | |
string jsonData = JsonConvert.SerializeObject(payload); | |
request.Content = new StringContent(jsonData); | |
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); | |
var response = await httpClient.SendAsync(request); | |
string jsonResp = await response.Content.ReadAsStringAsync(); | |
RazorResp resp = JsonConvert.DeserializeObject<RazorResp>(jsonResp); | |
if (!string.IsNullOrEmpty(resp.id)) | |
{ | |
// checkout | |
Checkout checkout = new Checkout(); | |
checkout.SetImage(Resource.Drawable.splash_logo); | |
//checkout.SetFullScreenDisable(false); | |
checkout.SetKeyID(username); | |
JSONObject options = new JSONObject(); | |
options.Put("name", "CodeLog"); | |
options.Put("description", $"Reference No. {payload.receipt}"); | |
options.Put("image", "https://s3.amazonaws.com/rzp-mobile/images/rzp.png"); | |
options.Put("order_id", resp.id);//from response of step 3. | |
options.Put("theme.color", "#3399cc"); | |
options.Put("currency", "INR"); | |
options.Put("amount", payload.amount);//pass amount in currency subunits | |
options.Put("prefill.email", myemail); | |
options.Put("prefill.contact", mycontact); | |
checkout.Open(this, options); | |
} | |
} | |
} | |
} | |
} |
Conclusion: This is the walkthrough for the payment integration using webview for Xamarin.iOS as there is no clear alternate available for iOS using SDK and for Android binding project based SDK.
Follow the CodeLog FB page for all the updates and Keep supporting, Happy coding!!!.
No comments:
Post a Comment