Scan Credit Cards with Xamarin.Forms

Hi Guys,

Today, I am going teach you about how to add CreditCard scanning feature to your mobile app.

If you have used the Uber mobile app, then you already know what it is.

Uber-Paytm

This is a very user-friendly and must needed feature in payment related Apps. It will make user to easily scan his credit card with mobile camera and fill the details needed for the payment.

Let’s see how to create this with Xamarin.Forms … 🙂

  1. Create a project with Xamarin.Forms

Screen Shot 2017-03-09 at 2.29.57 PM

2. Create a HomePage and set it as the MainPage in App.xaml

Screen Shot 2017-03-09 at 2.37.12 PM

3. Add Card.iO package to .Droid and .iOS projects from Nuget.

Screen Shot 2017-03-09 at 2.31.42 PM

Screen Shot 2017-03-09 at 2.32.36 PM

As you see here, we are using Card.iO for scanning. Its a free and open source library. You can get more informations from https://www.card.io .

4. Now lets create a dependancy service like below.

  • ICardService.cs in PCL project
  • CardService.cs  in  .Droid project
  • CardService.cs  in .iOS project

Screen Shot 2017-03-09 at 2.40.48 PM.png

ICardService.cs in PCL

namespace CardApp
{
    public interface ICardService
    {
        void StartCapture();

        string GetCardNumber();

        string GetCardholderName();
    }
}

CardService.cs in .iOS

using System;
using Card.IO;
using CardApp.iOS;
using UIKit;
using Xamarin.Forms;

[assembly: Dependency(typeof(CardService))]
namespace CardApp.iOS
{
    public class CardService : CardIOPaymentViewControllerDelegate, ICardService
    {
        private UIViewController rootViewController;
        private CreditCardInfo cardInfo;

        public void StartCapture()
        {
            InitCardService();
            var paymentViewController = new CardIOPaymentViewController(this);
            rootViewController.PresentViewController(paymentViewController, true, null);
        }

        public string GetCardNumber()
        {
            return (cardInfo != null) ? cardInfo.CardNumber : null;
        }

        public string GetCardholderName()
        {
            return (cardInfo != null) ? cardInfo.CardholderName : null;
        }

        private void InitCardService()
        {
            // Init rootViewController
            var window = UIApplication.SharedApplication.KeyWindow;
            rootViewController = window.RootViewController;
            while (rootViewController.PresentedViewController != null)
            {
                rootViewController = rootViewController.PresentedViewController;
            }
        }

        public override void UserDidCancelPaymentViewController(CardIOPaymentViewController paymentViewController)
        {
            Console.WriteLine(Scanning Canceled!);
        }

        public override void UserDidProvideCreditCardInfo(CreditCardInfo cardInfo, CardIOPaymentViewController paymentViewController)
        {
            if (cardInfo == null)
            {
                Console.WriteLine(Scanning Canceled!);
            }
            else 
            {
                this.cardInfo = cardInfo;
            }

            paymentViewController.DismissViewController(true, null);
        }
    }
}


CardService.cs in .Droid

using Android.App;
using Android.Content;
using Card.IO;
using CardApp.Droid;
using Xamarin.Forms;

[assembly: Dependency(typeof(CardService))]
namespace CardApp.Droid
{
    public class CardService : ICardService
    {
        private Activity activity;

        public void StartCapture()
        {
            InitCardService();

            var intent = new Intent(activity, typeof(CardIOActivity));
            intent.PutExtra(CardIOActivity.ExtraRequireExpiry, true);
            intent.PutExtra(CardIOActivity.ExtraRequireCvv, true);
            intent.PutExtra(CardIOActivity.ExtraRequirePostalCode, false);
            intent.PutExtra(CardIOActivity.ExtraUseCardioLogo, true);

            activity.StartActivityForResult(intent, 101);
        }

        public string GetCardNumber()
        {
            return (InfoShareHelper.Instance.CardInfo != null) ? InfoShareHelper.Instance.CardInfo.CardNumber : null;
        }

        public string GetCardholderName()
        {
            return (InfoShareHelper.Instance.CardInfo != null) ? InfoShareHelper.Instance.CardInfo.CardholderName : null;
        }

        private void InitCardService()
        {
            // Init current activity
            var context = Forms.Context;
            activity = context as Activity;
        }
    }

    public class InfoShareHelper
    {
        private static InfoShareHelper instance = null;
        private static readonly object padlock = new object();

        public CreditCard CardInfo { get; set; }

        public static InfoShareHelper Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new InfoShareHelper();
                    }
                    return instance;
                }
            }
        }
    }
}

MainActivity.cs  in .Droid

Add following method after OnCreate in MainActivity.cs

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);

            if (data != null)
            {
                // Be sure to JavaCast to a CreditCard (normal cast wont work)      
                InfoShareHelper.Instance.CardInfo = data.GetParcelableExtra(CardIOActivity.ExtraScanResult).JavaCast<CreditCard>();
            }
            else
            {
                Console.WriteLine(Scanning Canceled!);
            }
        }

Screen Shot 2017-03-09 at 5.31.49 PM

Save all.

Now our CardService is ready to use.

Before use it we have to set Camera access permission in iOS and Android.

5. Set access permissions needed for CardService.

iOS

Add a new Entry “Privacy – Camera Usage Description” in info.plist

Screen Shot 2017-03-09 at 3.10.10 PM

Android

Add following permission and configs to AndroidManifest.xml

<usessdk android:minSdkVersion=15 />
    <usespermission android:name=android.permission.ACCESS_NETWORK_STATE />
    <usespermission android:name=android.permission.INTERNET />
    <usespermission android:name=android.permission.CAMERA />
    <usespermission android:name=android.permission.VIBRATE />
    <application android:label=CardApp>
        <activity android:name=io.card.payment.CardIOActivity android:configChanges=keyboardHidden|orientation />
        <activity android:name=io.card.payment.DataEntryActivity />
    </application>

Screen Shot 2017-03-09 at 5.40.16 PM

6. Now add a button to HomePage and set an event handler

<?xml version=1.0 encoding=UTF8?>
<ContentPage xmlns=http://xamarin.com/schemas/2014/forms xmlns:x=http://schemas.microsoft.com/winfx/2009/xaml x:Class=CardApp.HomePage>
    <ContentPage.Content>
        <Button Clicked=onScanCard HorizontalOptions=CenterAndExpand VerticalOptions=CenterAndExpand WidthRequest=200 Text=Scan my Card TextColor=White BackgroundColor=Purple/>
    </ContentPage.Content>
</ContentPage>

In code behind:

using System;
using Xamarin.Forms;

namespace CardApp
{
    public partial class HomePage : ContentPage
    {
        public HomePage()
        {
            InitializeComponent();
        }

        private void onScanCard(object sender, EventArgs e)
        {
            DependencyService.Get<ICardService>().StartCapture();
        }
    }
}

7. Now compile and run on iOS / Android:

IMG_2685          IMG_2684

Done.

Source code is available in https://github.com/hiranpeiris/CardApp

Happy coding… 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s