Migrating From Standard to Native Payment Experience with Razorpay at Pratilipi Comics

Nimit Srivastava
Team Pratilipi
Published in
8 min readAug 9, 2022

Starting off with a brief introduction of who exactly is talking about this herculean task; I am Nimit Srivastava, a developer for Pratilipi Comics specifically working on the Android side of things. First of all, let’s talk about the use case for this particular migration, for the longest time, our payment system was powered by the Standard Android SDK from Razorpay which was sufficient for the all the requirements of a checkout system but as our system matured and the need arose for a more customised and controllable payment system that felt natural to the theme of the application and enabling the development of quicker and easier methods to checkout, it made much more sense to switch to a custom user interface SDK provided by Razorpay to suit our requirements. So if your team or product have similar requirements then this article might be helpful to you, if not, then still maybe this article could still provide some insight and a little knowledge never hurt nobody.

Setting Up Dependencies

The first step of migration is changing dependencies (..duh!) , the main SDK that needs to be updated in order to switch to custom UI is

implementation ‘com.razorpay:checkout:{version}’

to

implementation ‘com.razorpay:customui:{version}’

Along with this one another dependency you might want to set up is an image library that supports GIF image formats since some image URLs that are provided with the list of supported payments methods point to GIF resources for logos. The dependency we had to add in order to display GIF images was implementation ‘com.facebook.fresco:animated-gif:{version}’ . For our particular migration , these two dependency changes were sufficient for our application.

Backend Order Generation

The second step of the process is to alter the Razorpay options map that is sent to the SDK at the point of the submitting details to razorpay to start the payment process. For the custom checkout, the only required fields for razorpay options are the amount, description and currency, all other user interface related options such as theme, config, image are omitted since all the UI related aspects need to handled on the product side and hence is not required for payment processing. If the rest of your payment system was up and functional no more changes should be required on the server side of things, if not, then you can refer to the documentation linked below to help set that up and then make the option changes for the custom checkout.

Layout Changes

In that standard razorpay checkout, the screens for user details such as email and phone number and the payment methods screen were both provided in the SDK itself, so for the custom UI SDK those screens need to be built in-house. For this we built three new layouts to replace the ones in the standard checkout in our own design : Checkout, UPI Dialog, Card Dialog, Details Dialog.

The Checkout layout shows all the various payment methods in various recycler views along with details of the payment itself which can be the amount or any specific item that comes with the payment (in our case, coins). This fragment also has a hidden WebView with android:visibility=”gone” which is required by the SDK to show specific states when the payment is submitted such as the bank pages for netbanking or waiting state for UPI payments; out of the box we get default WebView user interfaces which can also be customised to better suit the application’s feel. However we will not be getting into that in this article but it is an exciting aspect to look into so here’s a link for that as well!

The UPI Dialog is a DialogFragment which lets the user enter their VPA which is verified and submitted to start a payment, and the Card Dialog works similarly with only replacing VPA details with Credit/Debit Card details. The Details Dialog is an optional dialog that can be made according to specific use-cases, it solves the purpose of collecting the contact number and email details of users since that is required to start a payment with the Custom UI SDK, if you would like users to be able to add or edit their details then this type of functionality is required. At last, we build one additional layout which is a loader for all asynchronous calls that are done in order to prevent multi-clicks and show an intermediary state.

Application Changes

Now coming to changes that were made in the code on the client side, firstly we needed to make some data classes in order to store the various kinds of information we need to complete our checkout page. Firstly, to store all the various payment methods fetched from razorpay, we create a data class PaymentMethod with a structure like :

The name field stores the name of the method that is to be displayed to the user and the logoUrl field contains a link to a network image to the particular payment method’s logo which needs to be loaded through an image library and displayed. As seen above the type field of the data class determines it values from an Enum called PaymentMethodTypes which store all the various kinds of payment methods that your particular system supports, an example of that enum can be seen below,

The next data class we require is to handle the various states of a payment, these states can differ based on your particular implementation of the system but in this example we handle cases for four different states of a particular payment,

Each of the payment states is linked to corresponding prompt that is shown to the user upon receiving a response from the server regarding the payment that was done and since the success and failed state have additional information linked with them, hence the use of sealed classes is preferred for this use-case to classify the states.

Coming to the implementation of the Checkout screen, there are a few important things to keep in mind to complete the migration. Firstly, we initalize a razorpay instance with the razorpay key and attach the WebView that we created earlier in our layout to this instance, this is mandatory in order for the system to behave as it is supposed to, this is done using razorpay.setWebView({insert reference to webview here}). Next, we populate our screen with payment methods that are fetched from two sources :

  1. getPaymentMethods :- The Custom UI razorpay SDK gives us this method to fetch all supported payments on your Razorpay account in a PaymentMethodsCallback which has a response with all the details of every payment method available in the corresponding razorpay account. This response is all merged into one hence a function must be written in order to extract information from this response and to pass that data to the appropriate recyclers in the layout. This method is put in the Fragment’s ViewModel and it accepts a JSONObject created from the response string of the PaymentMethodsCallback and the razorpay instance parameters, separates all the various methods and creates them as instances of the PaymentMethod class and updates the UI. The razorpay instance is also passed to the separate payment methods function since the instance gives us access to methods razorpay.getWalletSqLogoUrl({wallet name}) and razorpay.getBankLogoUrl(bankCode) which are required to get the network image link of payment providers such as wallets and banks.

2. getAppsWhichSupportUpi :- This method in the SDK gives back a List<ApplicationDetails> of all the applications in the user’s device which are capable of completing UPI payments, i.e, the app must be installed and must have a UPI ID set up in order for it to show up here. This response can then be used to setup your views to display that data to the user.

In case of creating a common view for all the payment methods, one thing needs to be kept in mind that all image resources for Netbanking are linked to GIF images and the rest are in PNG, so you can classify it according to the type field in the PaymentMethod class to display the image according to its type. In our case, the ViewHolder for UPI Intent ,Pay Later and Netbanking was the same so according to the enums defined by us, we were able to classify and load images according to the format they are defined in,

Here, setOptimalImageURI and setGifImageController are extension functions on a SimpleDraweeView which use Fresco to load in network images or network GIFs respectively into the view.

Now that our methods are up and visible to the user, the only other major change remaining is the process of submitting a payment to Razorpay to initiate it, for that we create three methods of submitting a payment, one which handles direct clicks such as for UPI Intent, Netbanking and Wallets; one which accepts a VPA for UPI Collect and lastly one which accepts card details to start a Credit/Debit Card Payment. After setting the necessary options according to the method selected, the WebView that was attached to the razorpay instance, it must now be made visible before calling the submit method on the razorpay instance like such,

Now for the results of the submitted payment, the implementation remains similar to the Standard Checkout with the Fragment or Activity implementing a PaymentResultListener , the only major change here is to again set the visibility of the WebView to GONE once a success or failure response is received from the instance.

To ensure correct responses from the instance, two more changes must be made, one is to override the OnBackPress of your Fragment or Activity, since a challenge we faced during development was that the Fragment and the WebView would both close on a back press, this override ensures that if the WebView is currently visible then its visibility else would be updated otherwise functioning would take place normally.

and to override OnActivityResult as well to receive correct responses for UPI Intent and Wallets.

If you are using Navigation Component for your fragments you might need to pass the Activity Result from the Main Activity to that particular fragment in order for the above override to work. One method of doing so is,

This concludes the major changes that go into the migration from a Standard to Native Checkout experience. The things we looked at in this article are just the major implementation changes and the creation of an introductory version of a native experience, with the custom SDK, the possibilities of optimising and modifying the checkout flow is very deep *tips hat to Razorpay*. If you want to check it out yourself, I’ll be attaching the link to its documentation at the end. Hope this article could’ve given you some insight, thanks for reading till the end, here’s a cookie 🍪.

Documentation :

--

--