Android SDK

The Ravelin Mobile SDKs are critical to our ability to provide informed decisions to our clients.

Like the JavaScript library, the SDK enables:

  • The generation of a unique and persistent device ID
  • The collection of additional device details
  • Session tracking
  • If relevant to your integration, the encryption of card details

You can choose what functionality of the SDK you would like to use. However, at a mimimum we advise that you use the SDK to generate a reliable device ID and to send the additional device details for your app traffic.

Device IDs are critical throughout our fraud prevention tool, especially for use in our graph database. The additional device details can be used as a signal for fraud and can also provide important context for anyone investigating suspicious activity.

If you do NOT want to use encryption, please follow the guidance provided under the Encryption section and do not use either encryptCard or legacy-encryption.

Getting Started

Before you can integrate with the Ravelin mobile SDK for Android, you will need:

  • read access to our cloudrepo
  • valid API keys which are available in the Ravelin Dashboard in the account menu under the Developer option
  • valid username and password for the private Ravelin Maven repository

If you have any questions on getting started, please ask us in your Ravelin support channel on Slack.

Contents

Minimum Requirements

The SDK supports a minimum Android API level: 15 - 4.0.3 ICE_CREAM_SANDWICH_MR1 with some exceptions around encryption written up below.

For Encryption:

If you would like to use encryption supporting a minimum Android API level: 22 5.1 LOLLIPOP_MR1, you can use the encryptCard module which relies on native encryption. This is our preferred implementation.

If you would like to use encryption as well as support earlier versions of the Android operating system (from 4.0.3 up) then you will need to use the legacy-encryption module within the SDK.

Please note, if you decide to offer this level of support, the SDK will significantly impact the size of your app and you will need to use ABI Splitting (as described below).

Installing the Ravelin Android SDK

There are two methods of installing the Ravelin Android SDK: via Gradle, or manually with a precompiled AAR file. Our preferred method is through Gradle, due to its ease of maintenance.

Installing the Ravelin Mobile SDK (via Gradle)

Before attempting to use Gradle for Ravelin, ensure that you have a valid username and password for the private Maven repository. This can be obtained from a Ravelin integrations engineer.

IMPORTANT - Do not store the repository credentials within Source Control. They can be stored in the user’s gradle.properties

// ~/.gradle/gradle,properties

ravelinRepoUsername=username
ravelinRepoPassword=password

Within the Project level build.gradle, make sure the repositories include the appropriate Ravelin maven repository:

allprojects {
   repositories {
      /* other repositories */
      maven {            
         credentials {
            username "$ravelinRepoUsername"
            password "$ravelinRepoPassword"
         }
         url "https://maven.ravelin.com/repositories/releases/"
      }
   }
}

Then in the Module level build.gradle add Ravelin to the app dependencies:

dependencies {
    /* other dependencies */
    implementation 'com.ravelin.sdk:android:0.2.8'
}

Installing Manually

The Ravelin library may be imported as a standard AAR. Please be advised that we do not recommend manual installation and strongly advise that you use Gradle).

Into the Project level build.gradle make sure the repositories include the local libraries directory. Assuming that the AARs are stored within lib:

allprojects {
   repositories {
      /* other repositories */
      flatDir {
        dirs 'libs'
      }
   }
}

Then in the Module level build.gradle, add Ravelin to the app dependencies:

dependencies {
    implementation(name:'ravelin', ext:'aar')
}

APK Size Reduction

If you are using legacy-encryption due to the size of the underlying encryption code, the universal build is roughly 31MB. Using ABI Splitting (as described below) the library size can be reduced to around 7MB per architecture.

Due to the native components contained within the Ravelin SDK, we highly recommend using ABI Splitting to reduce the overall compiled size of your application. The underlying native package is already split into the different architectures so this allows your APKs to only contain the relevant library.

The list of available platforms is maintained on the Android website here.

Below is an adjusted example from the Android website outlining how to perform an ABI Split. This code must be placed into the module level build.gradle, ensuring to include all architectures needed to cover the desired userbase.

android {
    // ...
    splits {

        // Configures multiple APKs based on ABI.
        abi {
        
            // Enables building multiple APKs per ABI.
            enable true
            
            // Resets the list of ABIs that Gradle should create APKs for to none.
            reset()
    
            // Specifies a list of ABIs that Gradle should create APKs for.
            // We have included all Android mobile architectures.
            include "armeabi", "armeabi-v7a", "arm64-v8a"
    
            // Specifies that we do not want to also generate a universal APK that includes all ABIs.
            universalApk false
        }
    }
}

Usage

Please ensure only the publishable API key is used. The live secret API key should never be embedded into the app – it should only be used for server-to-server communications.

Accessing the Singleton

The Ravelin Android SDK has two static instance accessors:

  1. RavelinSDK.createInstance
  2. RavelinSDK.getSharedInstance

These both access the singleton if it has already been created, however, the instance must be created first. Calling getSharedInstance before an instance has been created will pass a RavelinError to the RavelinCallback#failure callback.

Calling RavelinSDK#createInstance a second time will not create a second instance but will instead return a previously created instance.

Kotlin

First call:

// MyApplication.kt

// using callbacks
RavelinSDK.createInstance(this, "publishable_key_live",) object : RavelinCallback<RavelinSDK>() {
    override fun success(ravelin : RavelinSDK) {
        Log.e("Ravelin Setup Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("Ravelin Setup Error", error.message)
    }
})

// not using callback
val ravelin: RavelinSDK? = RavelinSDK.createInstance(this, "publishable_key_live",)

Subsequent calls:

// MyActivity.kt

// using callback
RavelinSDK.getSharedInstance(object : RavelinCallback<RavelinSDK>() {
    override fun success(ravelin : RavelinSDK) {
        Log.e("Ravelin Setup Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("Ravelin Setup Error", error.message)
    }
})

// not using callback
val ravelin: RavelinSDK? = RavelinSDK.getSharedInstance()

Java

First call:

// MyApplication.java

// null-safe inside callback
RavelinSDK.Companion.createInstance(this, "publishable_key_live", new RavelinCallback<RavelinSDK>() {
    @Override
    public void success(RavelinSDK ravelinSDK) {
        Log.e("Ravelin Setup Success", "hooray");
    }

    @Override
    public void failure(@NotNull RavelinError ravelinError) {
        Log.e("Ravelin Setup Error", ravelinError.getMessage());
    }
});

// no callback, not null safe
RavelinSDK ravelin = RavelinSDK.Companion.createInstance(this, "publishable_key_live", );

Subsequent calls:

// MyActivity.java

// null-safe with handled error message
RavelinSDK.getSharedInstance(object : RavelinCallback<RavelinSDK>() {
    override fun success(ravelin : RavelinSDK) {
        Log.e("Ravelin Setup Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("Ravelin Setup Error", error.message)
    }
})

// nullable, no error message
RavelinSDK ravelin = RavelinSDK.Companion.getSharedInstance();

After first initialisation, the SDK instance can be referenced anywhere using RavelinSDK.getSharedInstance(...).

Encrypting Cards

Depending on your integration, you may want to encrypt card details via the SDK. The SDK can be used to allow the secure sharing of card information with Ravelin whilst removing the need to handle PCI-compliant data. When collecting the card details, using CardDetails(pan, month, year, nameOnCard). pan, month, year are required, while nameOnCard is optional and may be an empty string.

The CardDetails are then passed into the encryptCard method along with the appropriate RSA key to produce an EncryptedCard instance with encrypted ciphers. Encrypted cards are validated prior to encryption. You can perform this validation yourself by calling CardDetails#validate. The optional callback parameter will inform you of a success or failure. In case of a failure the method returns null, and if successful the newly created valid CardDetails is created with extra values stripped, ready to be encrypted.

Ravelin Android encryption usage differs depending on the minimum supported Android version for your app. For Android API level: 22 5.1 LOLLIPOP_MR1and above, use the native encryption provided within the standard Ravelin SDK. If you want to support earlier versions for encryption, you will need to make use of the Legacy Support module which provides extension methods to provide the techniques not natively provided within Android.

Validation is performed, confirming that expiry dates are valid and that the PAN is at least 13 characters. Should any validation checks fail, nil is returned from the method. Pass an error by ref to determine the cause of failure if any occurs.

The basic checks performed by the validation are:

  1. PAN length must be greater than 12 digits
  2. the month must be between 1 and 12 inclusive
  3. the year must be between the current year and 50 years in the future
  4. the year-month combination date must be in the future

Please note, the use of encryption is entirely optional and not required as part of your integration. If you are confused about whether or not you should use encryption, please contact an integration engineer. If you do not want to use encryption at all, please make sure not to use either encryptCard or legacy-encryption.

Kotlin

val ravelinSDK = RavelinSDK.getSharedInstance()
val cardDetails = CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson")

// null safe callback
ravelinSDK.encryptCard(cardDetails, "2|rsakeykeykeykeykeykey", object : RavelinCallback<EncryptedCard>() {
    override fun success(encrpytedCard : EncryptedCard) {
        Log.e("Card Encryption Success", "hooray")
    }
    
    override fun failure(error: EncryptedCard) {
        Log.e("Card Encryption Error", error.message)
    }
})

// nullable
val encryptedCard = ravelinSDK.encryptCard(cardDetails, "2|rsakeykeykeykeykeykey")

Java

final CardDetails cardDetails = new CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson");
final RavelinSDK ravelin = RavelinSDK.getSharedInstance();

// null safe callback
ravelin.encryptCard(cardDetails, "2|rsakeykeykeykeykeykey", new RavelinCallback<EncryptedCard>() {
    @Override
    public void success(EncryptedCard result) {
        Log.e("Card Encryption Success", "hooray");
    }

    @Override
    public void failure(EncryptedCard error) {
        Log.e("Card Encryption Error", error.getMessage());
    }
});

// nullable
final CardDetails valid = ravelin.encryptCard(cardDetails, "2|rsakeykeykeykeykeykey");

Card Validation

Kotlin

val cardDetails = CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson")

// null safe callback
cardDetails.validate(object : RavelinCallback<CardDetails>() {
    override fun success(validatedCardDetails : CardDetails) {
        Log.e("Card Validation Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("Card Validation Error", error.message)
    }
})

// nullable
final CardDetails valid = cardDetails.validate()

Java

final CardDetails cardDetails = new CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson");

// null safe callback
cardDetails.validate(new RavelinCallback<CardDetails>() {
    @Override
    public void success(CardDetails result) {
        Log.e("Card Validation Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("Card Validation Error", error.getMessage());
    }
});

// nullable
final CardDetails valid = cardDetails.validate();

Tracking Activity

Using the Ravelin Android SDK, you can capture various built in events along with your own custom events that can later be viewed in the Ravelin dashboard. This can be very useful for analysts to gain additional context during an investigation. For example, if you can see that a user is going through unexpected parts of your customer journey at a set speed on a new device that could indicate suspicious activity.

Track events may be called with either a RavelinRequestCallback callback or no callback. Using a callback, the network request will be triggered immediately.

No callback will return the RavelinRequest object which can then be enqueued with a callback for non-blocking, asynchronous calls or executed to block until completion.

trackEvent

Tracks a user or app event.

Required eventType, optional pageTitle, optional payload to be serialized and optional callback

Kotlin

// no callback, then blocking call later
val request : RavelinRequest = ravelin.trackEvent("app open")

request?.execute()

// no callback, then asynchronous call later
val request = ravelin.trackEvent("app open")

request?.enqueue(object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

// immediately call asynchronously
ravelin.trackEvent("app open", "login activity", arrayOf("Custom", "Data"), object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

Java

// no callback, then blocking call later
RavelinRequest request = ravelin.trackEvent("app open");

if(request != null) {
    request.execute()
}

// no callback, then asynchronous call later
RavelinRequest request = ravelin.trackEvent("app open");

request.enqueue(new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

// immediately call asynchronously
ravelin.trackEvent("app open", "login activity", new String[]{"Custom", "Data"}, new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

trackPage

Tracks navigation to a new App Page (Activity, Fragment, etc).

Required pageName, optional payload to be serialized and optional callback

Kotlin

// no callback, then blocking call later
val request : RavelinRequest = ravelin.trackPage("Product List - Toothbrushes")

request?.execute()

// no callback, then asynchronous call later
val request = ravelin.trackPage("Product List - Toothbrushes")

request?.enqueue(object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

// immediately call asynchronously
ravelin.trackPage("Product List - Toothbrushes", arrayOf("Custom", "Data"), object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

Java

// no callback, then blocking call later
RavelinRequest request = ravelin.trackPage("Product List - Toothbrushes");

if(request != null) {
    request.execute()
}

// no callback, then asynchronous call later
RavelinRequest request = ravelin.trackEvent("app open");

request.enqueue(new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

// immediately call asynchronously
ravelin.trackPage("Product List - Toothbrushes", new String[]{"Custom", "Data"}, new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(@NotNull RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

trackLogIn

Tracks a user login event.

Required customerId, optional pageTitle, optional payload to be serialized and optional callback

Kotlin

// no callback, then blocking call later
val request : RavelinRequest = ravelin.trackLogIn("15464811")

request?.execute()

// no callback, then asynchronous call later
val request = ravelin.trackLogIn("15464811")

request?.enqueue(object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

// immediately call asynchronously
ravelin.trackLogIn("15464811", "login activity", mapOf("Class" to "Mage"), object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

Java

// no callback, then blocking call later
RavelinRequest request = ravelin.trackLogIn("15464811")

if(request != null) {
    request.execute()
}

// no callback, then asynchronous call later
RavelinRequest request = ravelin.trackLogIn("15464811")

request.enqueue(new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

// immediately call asynchronously
final HashMap<String, String> map = new HashMap<>();
map.put("Class", "Mage");

ravelin.trackLogIn("app open", "login activity", map, new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

trackLogOut

Tracks a user logout event.

pageTitle and payload are optional serialized parameters. callback is optional.

Kotlin

// no callback, then blocking call later
val request : RavelinRequest = ravelin.trackLogOut("User Account")

request?.execute()

// no callback, then asynchronous call later
val request = ravelin.trackLogOut()

request?.enqueue(object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

// immediately call asynchronously
ravelin.trackLogOut("User Account", mapOf("Class" to "Mage"), object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

Java

// no callback, then blocking call later
RavelinRequest request = ravelin.trackLogOut()

if(request != null) {
    request.execute()
}

// no callback, then asynchronous call later
RavelinRequest request = ravelin.trackLogOut()

request.enqueue(new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(@NotNull RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

// immediately call asynchronously
final HashMap<String, String> map = new HashMap<>();
map.put("Class", "Mage");

ravelin.trackLogOut("login activity", map, new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(@NotNull RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

trackFingerprint

Sends additional device details to Ravelin. If a Fingerprint has not been generated by this point, it will be generated by calling this method.

Only takes an optional callback.

Kotlin

// no callback, then blocking call later
val request : RavelinRequest = ravelin.trackFingerprint()

request?.execute()

// no callback, then asynchronous call later
val request = ravelin.trackFingerprint()

request?.enqueue(object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

// immediately call asynchronously
ravelin.trackFingerprint(object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

Java

// no callback, then blocking call later
RavelinRequest request = ravelin.trackFingerprint()

if(request != null) {
    request.execute()
}

// no callback, then asynchronous call later
RavelinRequest request = ravelin.trackFingerprint()

request.enqueue(new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

// immediately call asynchronously
ravelin.trackFingerprint(new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

trackPaste

This method is used primarily by the Ravelin PasteEventListener but can be used directly if required.

Required value, optional pageTitle and optional callback

Kotlin

// no callback, then blocking call later
val request : RavelinRequest = ravelin.trackPaste(pastedCharacters)

request?.execute()

// no callback, then asynchronous call later
val request = ravelin.trackPaste(pastedCharacters)

request?.enqueue(object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

// immediately call asynchronously
ravelin.trackPaste(pastedCharacters, "checkout activity", object : RavelinRequestCallback() {
    override fun success() {
        Log.e("API Request Success", "hooray")
    }
    
    override fun failure(error: RavelinError) {
        Log.e("API Request Error", error.message)
    }
})

Java

// no callback, then blocking call later
RavelinRequest request = ravelin.trackPaste(pastedCharacters)

if(request != null) {
    request.execute()
}

// no callback, then asynchronous call later
RavelinRequest request = ravelin.trackPaste(pastedCharacters)

request.enqueue(new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

// immediately call asynchronously
ravelin.trackPaste(pastedCharacters, "login activity", new RavelinRequestCallback() {
    @Override
    public void success() {
        Log.e("API Request Success", "hooray");
    }

    @Override
    public void failure(RavelinError error) {
        Log.e("API Request Error", error.getMessage());
    }
});

Paste Event Listener

The PasteEventListener is a TextWatcher that reports back when a user has pasted into an input box through a PasteEventListener.OnPaste interface.

Internally, the PasteEventListener will report back to Ravelin the pasted text after obfuscating input. The input should be obfuscated automatically as part of PasteEventListener - this is important because we don’t want to be accidently sent sensitive information that may be copied and pasted (for example BINs).

This is primarily for use on PAN input fields but may be used anywhere.

Kotlin

val view = // Your EditText

view.addTextChangedListener(
    PasteListener("page", object : PasteListener.OnPaste() {
        fun pasted() {
            Log.d("Paste Event", "user has pasted some content")
        }
    })
)

Java

EditText view = // Your EditText

view.addTextChangedListener(
    new PasteListener("page", new PasteListener.OnPaste() {
        @Override
        public void pasted() {
            Log.d("Paste Event", "user has pasted some content");
        }
    })
);

Legacy Support

Some required features are not available natively on all versions of Android. To be able to use these Ravelin features within your app you should take advantage of the Extension Modules. Presently the only legacy support module is legacy-encryption.

Then in the Module level build.gradle add the required Legacy Support library alongside the Ravelin Android dependency to the app dependencies:

dependencies {
    /* other dependencies */
   
    implementation 'com.ravelin.sdk:android:0.2.8'
    implementation 'com.ravelin.sdk:legacy-encryption:0.2.8'
}

Encryption

Kotlin

val ravelinSDK = RavelinSDK.getSharedInstance()
val cardDetails = CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson")

// null safe callback
ravelinSDK.legacyEncryptCard(cardDetails, "2|rsakeykeykeykeykeykey", object : RavelinCallback<EncryptedCard>() {
    override fun success(encrpytedCard : EncryptedCard) {
        Log.e("Card Encryption Success", "hooray")
    }
    
    override fun failure(error: EncryptedCard) {
        Log.e("Card Encryption Error", error.message)
    }
})

// nullable
val encryptedCard = ravelinSDK.legacyEncryptCard(cardDetails, "2|rsakeykeykeykeykeykey")

Java

final CardDetails cardDetails = new CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson");
final RavelinSDK ravelin = RavelinSDK.getSharedInstance();

// null safe callback
EncryptionUtil.legacyEncryptCard(ravelin, cardDetails, "2|rsakeykeykeykeykeykey", new RavelinCallback<EncryptedCard>() {
    @Override
    public void success(EncryptedCard result) {
        Log.e("Card Encryption Success", "hooray");
    }

    @Override
    public void failure(EncryptedCard error) {
        Log.e("Card Encryption Error", error.getMessage());
    }
});

// nullable
final CardDetails valid = EncryptionUtil.legacyEncryptCard(ravelin, cardDetails, "2|rsakeykeykeykeykeykey");

End-to-End Example

In the following form, we collect card details from the customer, encrypt them and send that encrypted values (the cipher) back to your server.

Kotlin

class ShopApplication : Application() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // Create instance referencing the application. This can be done anywhere if the application does not extend Application
        RavelinSDK.createInstance(this, "api_key_123456789", object : RavelinCallback<RavelinSDK>() {
            override fun success(instance : RavelinSDK) {
                Log.e("Ravelin Setup Success", "hooray")
            }
            
            override fun failure(error: RavelinError) {
                Log.e("Ravelin Setup Error", error.message)
            }
        })
    }
}


class ShopActivity: AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val customerId = "1234" // get customerId from your login process

        val ravelin = RavelinSDK.getSharedInstance(object : RavelinCallback<RavelinSDK>() {
            override fun success(instance : RavelinSDK) {
                ravelin = instance
                ravelin.customerId = customerId // set customer id either directly or via trackLogin method
                // this id will then be sent with all subsiquent tracking events
                ravelin.orderId = "your own order ID" // set order id to your own order reference
                ravelin.trackPage("Shopping Page")

            }
            
            override fun failure(error: RavelinError) {
                Log.e("Ravelin Setup Error", error.message)
            }
        })
        val cardNumberTextView = findViewById<TextView>(R.id.pan)
        val expirationMonthTextView = findViewById<TextView>(R.id.expiration_month)
        val expirationYearTextView = findViewById<TextView>(R.id.expiration_year)
        val nameOnCardTextView = findViewById<TextView>(R.id.name_on_card)

        findViewById<Button>(R.id.payButton).setOnClickListener {
            val pan = cardNumberTextView.text
            val month = expirationMonthTextView.text
            val year = expirationYearTextView.text
            val name = nameOnCardTextView.text
            
            val cardDetails = CardDetails(pan, month, year, name)

            if(ravelin != null) {
            ravelin.encryptCard(cardDetails, object : RavelinCallback<RavelinSDK>() {
                    override fun success(instance : EncryptedCard) {
                        Log.e("Card Encryption Success", "hooray")
                        sendEncryptedDetailsToYourServer(encryptedCardDetails)
                    }
                    
                    override fun failure(error: EncryptedCard) {
                        Log.e("Card Encryption Error", error.message)
                    }
                })
            }
        }
    }
}

Once the cipher is received by your server, the API request to Ravelin in which a fraud recommendation is requested should use this cipher value:

/* Server-side */

var card = JSON.parse(request.params['ravelinCipherText']);
card.methodType = 'paymentMethodCipher';

var action = request('https://api.ravelin.com/v2/checkout?score=true', {
    // ...
    'paymentMethod': card,
});

Class Methods


createInstance(application: Application, apiKey: String, callback: RavelinCallback? = null) : RavelinSDK?

Create a singleton instance of the Ravelin SDK with your public key.

Parameters

Parameter Type Description
application android.app.Application The Android Application instance
apiKey String The public API key from your Ravelin dashboard
callback com.ravelin.sdk.RavelinCallback Optional the callback to trigger with a null safe instance of the class or an error message

Return value

A nullable singleton instance of the class


encryptCard(cardDetails: CardDetails, rsaKey: String, callback: RavelinCallback? = null) : EncryptedCard?

Encrypt the provided CardDetails.

Parameters

Parameter Type Description
cardDetails com.ravelin.sdk.models.CardDetails The CardDetails to encrypt
rsaKey String The public RSA key from your Ravelin dashboard
callback com.ravelin.sdk.RavelinCallback Optional the callback to trigger with a null safe EncryptedCard instance or an error message

Return value

A nullable encrypted card details


getDeviceId() : String

Obtain public portion of the Ravelin Generated ID.

Return value

A String identifying the device - persistent across Google accounts.


generateFingerprint(callback: RavelinCallback? = null) : Fingerprint?

Generate a new Fingerprint for the device

Parameters

Parameter Type Description
callback com.ravelin.sdk.RavelinCallback Optional the callback to trigger with a null safe Fingerprint instance or an error message

Return value

A nullable device fingerprint

getSharedInstance(callback: RavelinCallback? = null) : RavelinSDK? {

Returns a previously instantiated RavelinSDK instance.

Parameters

Parameter Type Description
callback com.ravelin.sdk.RavelinCallback Optional the callback to trigger with a null safe Fingerprint instance or an error message

Return value

A nullable RavelinSDK


obfuscateInput(value: String): Map {

Takes a given String and replaces digits with 0 and letters with X.

Parameters

Parameter Type Description
value String The input to Obfuscate.

Return value

A map containing the keys pastedValue and panCleaned for the original and obfuscated representations of the input. This is so that we are not accidently sent copied paste values for things like BINs.


Extension Methods

legacyEncryptCard(cardDetails: CardDetails, rsaKey: String, callback: RavelinCallback? = null) : EncryptedCard?

Encrypt the provided CardDetails.

Parameters

Parameter Type Description
cardDetails com.ravelin.sdk.models.CardDetails The CardDetails to encrypt
rsaKey String The public RSA key from your Ravelin dashboard
callback com.ravelin.sdk.RavelinCallback Optional the callback to trigger with a null safe EncryptedCard instance or an error message

Return value

A nullable encrypted card details


Utility Methods

EncryptionUtil#legacyEncryptCard

public static EncryptedCard EncryptionUtil#legacyEncryptCard(RavelinSDK ravelin, CardDetails cardDetails, String rsaKey, RavelinCallback callback)

public static EncryptedCard EncryptionUtil#legacyEncryptCard(RavelinSDK ravelin, CardDetails cardDetails, String rsaKey)

Encrypt the provided CardDetails.

Parameters

Parameter Type Description
ravelin com.ravelin.sdk.RavelinSDK The RavelinSDK instance used within the application
cardDetails com.ravelin.sdk.models.CardDetails The CardDetails to encrypt
rsaKey String The public RSA key from your Ravelin dashboard
callback com.ravelin.sdk.RavelinCallback Optional the callback to trigger with a null safe EncryptedCard instance or an error message

Return value

A nullable encrypted card details


Class Properties

Customer ID

Your chosen customer ID

Kotlin

ravelin.customerId

ravelin.customerId = "cust-1"

Java

ravelin.getCustomerId();

ravelin.setCustomerId("cust-1");

Temp Customer ID

A temporary customer ID that will always be non-blank. Setting to a null, blank or empty value will generate a new temporary customer ID.

Kotlin

ravelin.tempCustomerId

ravelin.tempCustomerId = "temp-1"

Java

ravelin.getTempCustomerId();

ravelin.setTempCustomerId("temp-1");

Order ID

The ID for this specific order.

Kotlin

ravelin.orderId

ravelin.orderId = "930393-BBB"

Java

ravelin.getOrderId();

ravelin.setOrderId("930393-BBB");

Session ID

A temporary session ID that will always be non-blank. Setting to a null, blank or empty value will generate a new session ID.

Kotlin

ravelin.sessionId

ravelin.sessionId = null

Java

ravelin.getSessionId();

ravelin.setSessionId(null);

Bundled Libraries

Providing this library would not have been possible without the stellar works upon which it relies:

Release Notes


v0.2.8 - November 25, 2019

  • Fixed a crash for null errors.
    • Fatal Exception: java.lang.IllegalStateException: error must not be null

v0.2.7 - October 29, 2019

  • Fixed a crash where sdk was trying to read a non-JSON error but treating it as if it was JSON.
    • Fatal Exception: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
  • Updated the build target to be android 10.

v0.2.6 - May 7, 2019

  • Added RSA OAEP Encryption.
  • Extracted Chilkat Encryption to external module ‘legacy-encryption’.
  • ‘Legacy-encryption’ created as an extension module/utility.
  • Created new method ‘legacyEncryptCard’.