The Ravelin Mobile SDKs are critical to our ability to provide informed decisions to our clients.
Like the JavaScript library, the SDK enables:
We have two modules/dependencies within the SDK:
You may choose which functionality of the SDK to use. However, at a minimum, 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.
Use ravelin-core
for deviceId, fingerprinting and tracking activity and ravelin-encrypt
if using
card encryption.
The table below lists the available artefacts:
Artefact | Private release version | Public release version |
---|---|---|
ravelin-core | 3.0.3 | 3.1.0+ |
ravelin-encrypt | 3.0.3 | 3.1.0+ |
Before you can integrate with the Ravelin mobile SDK for Android, you will need:
ravelin-core
and ravelin-encrypt
are now public and may be accessed without credentials from Ravelin Maven/CloudRepo repository.Before you can integrate with the Ravelin mobile SDK for Android, you will need:
If you have any questions on getting started, please ask us in your Ravelin support channel on Slack.
The SDK supports a minimum Android API level: 21 - 5.0.0 LOLLIPOP
with some exceptions around
encryption (see below).
For Encryption:
Encryption, is available only for Android API level: 22 5.1 LOLLIPOP_MR1 and above, where you can
use the ravelin-encrypt
module which relies on native encryption.
The SDK is mainly written in Kotlin and compatible with Kotlin plugin version 1.9.23
There are two methods for installing the Ravelin Android SDK: via Gradle, or manually with a precompiled AAR file. Our preferred method is installation through Gradle, due to its ease of maintenance. In case you still prefer to install the SDK manually, make sure to also append its dependencies (described in Bundled libraries).
Please note that the following setup is basic and doesn’t include buildSrc
configurations, version catalogs or convention plugins.
Both ravelin-core
and ravelin-encrypt
are public since version 3.1.0 and may be accessed without the use of credentials.
The artefacts may be imported from a maven repository as shown below:
allprojects {
repositories {
/* other repositories */
maven {
setUrl("https://maven.ravelin.com/public/repositories/core-android/")
}
}
}
The next step is to add the dependencies in the Module level build.gradle
(build.gradle.kts
) add Ravelin to the app dependencies:
dependencies {
/* Other dependencies */
implementation 'com.ravelin.sdk:ravelin-core:5.0.0'
implementation 'com.ravelin.sdk:ravelin-encrypt:5.0.0'
}
in Kotlin DSL:
dependencies {
/* Other dependencies */
implementation("com.ravelin.sdk:ravelin-core:5.0.0")
implementation("com.ravelin.sdk:ravelin-encrypt:5.0.0")
}
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.
The credentials are required only for ravelin-core
and ravelin-encrypt
version 3.0.3 and below.
IMPORTANT - Do not store the repository credentials within Source Control. They can be stored in
the user’s gradle.properties
file.
// ~/.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 {
name "Ravelin"
credentials {
username "$ravelinRepoUsername"
password "$ravelinRepoPassword"
}
url "https://maven.ravelin.com/repositories/releases/"
}
}
}
In Kotlin DSL:
allprojects {
repositories {
/* other repositories */
maven {
credentials {
username = properties["ravelinRepoUsername"] as? String
password = properties["ravelinRepoPassword"] as? String
}
setUrl("https://maven.ravelin.com/repositories/releases/")
}
}
}
The next step is to add the dependencies in the Module level build.gradle
(build.gradle.kts
) add Ravelin to the app dependencies:
dependencies {
/* other dependencies */
implementation 'com.ravelin.sdk:ravelin-core:3.0.3'
implementation 'com.ravelin.sdk:ravelin-encrypt:3.0.3'
}
dependencies {
/* other dependencies */
implementation("com.ravelin.sdk:ravelin-core:3.0.3")
implementation("com.ravelin.sdk:ravelin-encrypt:3.0.3")
}
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.
A common way to add the library into the project is to add it into a library in the Project
level build.gradle
(build.gradle.kts
) make sure the repositories include the local libraries
directory. Assuming that the AARs are stored within libs
:
Groovy:
allprojects {
repositories {
/* other repositories */
flatDir {
dirs 'libs'
}
}
}
Kotlin DSL
allprojects {
repositories {
/* other repositories */
flatDir {
dirs("libs")
}
}
}
Then in the Module level build.gradle
(build.gradle.kts
), add Ravelin to the app dependencies:
Groovy
dependencies {
implementation(name: 'ravelin', ext: 'aar')
}
Kotlin DSL
dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
}
When building your project you will probably see a warning which says: ‘Using flatDir should be avoided because it doesn’t support any meta-data formats.’ You may ignore this warning. Alternatively, you may generate a new module in your application and fetch the library through this new module.
There are two ways to update 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.
In the Module level build.gradle
change the dependencies to the latest SDK version number.
Groovy
dependencies {
/* other dependencies */
implementation 'com.ravelin.sdk:ravelin-core:5.0.0'
implementation 'com.ravelin.sdk:ravelin-encrypt:5.0.0'
}
To verify the latest Ravelin SDK version check our Release Notes section.
The Ravelin library may be imported as a standard AAR. Please be advised that we do not recommend manual update and strongly advise that you use Gradle.
Please follow the same steps mentioned in the Installing Manually section and make sure you are using the latest SDK version AAR.
The Ravelin SDK is defining backup rules in its Manifest file. In case you have backup rules in your application manifest file, make sure to merge the SDK backup rules, otherwise they will be override during the Manifest merging process and that may result with an unexpected behaviour.
<application
android:dataExtractionRules="@xml/backup_rules_31_and_above"
android:fullBackupContent="@xml/backup_rules_until_30"
tools:targetApi="s"
/>
Backup rules for API level >= 31:
<?xml version="1.0" encoding="utf-8"?>
<data-extraction-rules disableIfNoEncryptionCapabilities="false">
<include
domain="sharedpref"
path="." />
<exclude
domain="sharedpref"
path="my_secret_shared_pref_data.xml" />
<exclude
domain="sharedpref"
path="my_com.ravelin.core_shared_pref_data.xml" />
</data-extraction-rules>
Backup rules for API level < 31:
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<include
domain="sharedpref"
path="." />
<exclude
domain="sharedpref"
path="my_secret_shared_pref_data.xml" />
<exclude
domain="sharedpref"
path="my_com.ravelin.core_shared_pref_data.xml" />
</full-backup-content>
This section is relevant to application providers that use the R8 compiler to optimise and obfuscate their source code and app resources.
Since version 3.1.0, both ravelin-core
and ravelin-encrypt
source code is obfuscated with the help of the R8 compiler.
Ravelin SDK v4.0.0 and above
In case you’re using the R8 compiler, there’s no additional requirements. The compiler will take care of merging the SDK’s ProGuard keep rules. In case you’re using a different dexing tool, please add the following ProGuard rules to your ProGuard configuration file manually.
Ravelin SDK v3.1.0 To avoid additional obfuscation/optimisation/shrinking of these libraries or to avoid obfuscation of lower versions than 3.1.0, please add the following keep rules to your ProGuard configuration file: ProGuard rules. Ignoring these keep rules may lead to potential errors.
Ravelin SDK v4.0.0 and above
The following configuration is required in order to support Java API desugaring in Android API level 23 and older :
// Add the following to your build.gradle.kts file
compileOptions {
// Other configurations ...
isCoreLibraryDesugaringEnabled = true
}
// Add the following dependency to your build.gradle.kts file:
dependencies {
// Other dependencies
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
}
For a better experience with Ravelin SDK each app has to provide a way for accessing users information. Here is a list of what each permission allows us to get from the users:
Following information about users localization:
In addition, the ACCESS_FINE_LOCATION permission is required in order to get the connection MAC address.
Information about users phone
Information about network capabilities.
Information about devices wireless connection interface.
Information about installed packages.
Warning: Request this permission only when your app core functionality includes:
Allows internet connection access to background processes.
The SDK requires permission to use internet connection in order to send data to Ravelin. The SDK will retry events in case of issues like no internet connection or server errors. Since the retry is a background process that relies on internet connection this permission is needed for the retry functionality to work. If you do not grant this permission the retry functionality will not work and silently fail.
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.
The Ravelin Android SDK has three static instance accessors:
RavelinSDK.createInstance
RavelinSDK.getSharedInstance
RavelinSDK.cleanup
While the first accessor is aimed to generate an instance of the SDK, the other two, should access
the singleton if its already been created. Calling getSharedInstance
or cleanup
before an
instance was created shall result with a RavelinError
returned to the application via
the RavelinCallback#failure
callback.
Calling RavelinSDK#createInstance
a second time will not create a second instance but will instead
return a previously created instance.
When the application finishes its use of the SDK, a cleanup
accessor should be called. It is aimed
to clear SDK resources and the SDK instance itself.
Kotlin
First call:
// MyApplication.kt
// using callbacks
RavelinSDK.createInstance(this, "publishable_key_live", object : RavelinCallback<RavelinSDK>() {
override fun success(ravelin: RavelinSDK) {
Log.d("Ravelin Setup Success", "hooray")
}
override fun failure(error: RavelinError) {
Log.e("Ravelin Setup Error", error.message)
}
})
// without a 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.d("Ravelin Setup Success", "hooray")
}
override fun failure(error: RavelinError) {
Log.e("Ravelin Setup Error", error.message)
}
})
// without a callback
val ravelin: RavelinSDK = RavelinSDK.getSharedInstance()
Cleaning Resources:
RavelinSDK.cleanup(object : RavelinCallback<String>() {
override fun success(response: String) {
Log.d("Ravelin Setup Success", response)
}
override fun failure(error: RavelinError) {
Log.e("Ravelin Setup Error", error.message)
}
})
Java
First call:
// MyApplication.java
// null-safe inside callback
class Example {
RavelinSDK instance = RavelinSDK.Companion.createInstance(this, "publishable_key_live", new RavelinCallback<RavelinSDK>() {
@Override
public void success(RavelinSDK ravelinSDK) {
Log.d("Ravelin Setup Success", "hooray");
}
@Override
public void failure(@NotNull RavelinError ravelinError) {
Log.e("Ravelin Setup Error", ravelinError.getMessage());
}
});
// no callback, not null safe
RavelinSDK instance2 = RavelinSDK.Companion.createInstance(this, "publishable_key_live");
}
Subsequent calls:
// MyActivity.java
// null-safe with handled error message
class Example {
RavelinSDK instance1 = RavelinSDK.getSharedInstance(new RavelinCallback<RavelinSDK>() {
@Override
public void success(RavelinSDK ravelinSDK) {
Log.d("Ravelin Setup Success", "hooray");
}
@Override
public void failure(@NotNull RavelinError ravelinError) {
Log.e("Ravelin Setup Error", error.getMessage());
}
});
// nullable, no error message
RavelinSDK instance2 = RavelinSDK.Companion.getSharedInstance();
}
Cleaning Resources:
class Example {
void main() {
RavelinSDK.Companion.cleanup(new RavelinCallback<String>() {
@Override
public void success(String response) {
Log.d("Ravelin Setup Success", response);
}
@Override
public void failure(@NotNull RavelinError ravelinError) {
Log.e("Ravelin Setup Error", ravelinError.getMessage());
}
});
}
}
After first initialization, the SDK instance can be referenced anywhere
using RavelinSDK.getSharedInstance(...)
.
This section is relevant only to those apps which rely on the WorkManager API and initialize it manually.
Should this use case apply to your app, please make sure to meet the following requirement:
Configuration.Provider
Interface. A minimal setting of
the configuration object would be:Kotlin
class YourApplication : Application(), Configuration.Provider {
//...
override fun onCreate() {
super.onCreate()
val configuration = workManagerConfiguration
WorkManager.initialize(this, configuration) // call only for WorkManager older than 2.1.0
}
override fun getWorkManagerConfiguration(): Configuration =
Configuration.Builder()
.build()
//...
}
Java
public class YourApplication extends Application implements Configuration.Provider {
//...
@Override
public void onCreate() {
super.onCreate();
Configuration config = getWorkManagerConfiguration();
WorkManager.initialize(this, config); // call only for WorkManager older than 2.1.0
}
@NonNull
@NotNull
@Override
public Configuration getWorkManagerConfiguration() {
return new Configuration.Builder().build();
}
//...
}
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.
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 is only available for Android 5.1 LOLLIPOP_MR1
API level: 22 and above,
since it uses the native encryption provided within the standard Ravelin SDK.
Validation is performed, confirming that expiry dates are valid, that the PAN is at least 12 characters and that the name on the card is valid. 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:
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 encryptCard
.
Kotlin
val cardDetails = CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson")
// null safe callback
RavelinEncrypt().encryptCard(cardDetails, "RSA-Key",
object : EncryptCallback<EncryptedCard>() {
override fun failure(error: EncryptError) {
Log.d("Card encryption Error", error.message)
}
override fun success(result: EncryptedCard?) {
Log.d("Card encryption Success", result.toString())
}
})
// nullable
val encryptedCard = RavelinEncrypt().encryptCard(cardDetails, "2|rsakeykeykeykeykeykey")
Java
class Example {
final CardDetails cardDetails = new CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson");
// null safe callback
EncryptedCard encryptedCard = RavelinEncrypt().encryptCard(cardDetails, "RSA-Key",
new EncryptCallback<CardDetails>() {
public void failure(EncryptError error) {
Log.d("Card encryption Error", error.getMessage());
}
public void success(CardDetails result) {
Log.d("Card encryption Success", result.toString());
}
});
}
// nullable
class Example {
final EncryptedCard encryptedCard = RavelinEncrypt().encryptCard(cardDetails, "2|rsakeykeykeykeykeykey");
}
Kotlin
val cardDetails = CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson")
cardDetails.validate(object : EncryptCallback<CardDetails>() {
override fun failure(error: EncryptError) {
Log.d("Card Validation Error", error.message)
}
override fun success(result: CardDetails?) {
Log.d("Card Validation Success", "hooray")
}
})
RavelinEncrypt().encryptCard(cardDetails, "RSA-Key",
object : EncryptCallback<EncryptedCard>() {
override fun failure(error: EncryptError) {
Log.d("Card encryption Error", error.message)
}
override fun success(result: EncryptedCard?) {
Log.d("Card encryption Success", result.toString())
}
})
Java
class Example {
final CardDetails cardDetails = new CardDetails("1234 1234 1234 1234", "02", "18", "Dr Jilly McJillson");
// null safe callback
CardDetailks cardDetails = cardDetails.validate(new EncryptCallback<CardDetails>() {
@Override
public void success(CardDetails result) {
Log.e("Card Validation Success", "hooray");
}
@Override
public void failure(EncryptError error) {
Log.e("Card Validation Error", error.getMessage());
}
});
EncryptedCard encryptedCard = RavelinEncrypt().encryptCard(cardDetails, "RSA-Key",
new EncryptCallback<CardDetails>() {
@Override
public void failure(EncryptError error) {
Log.d("Card encryption Error", error.getMessage());
}
@Override
public void success(CardDetails result) {
Log.d("Card encryption Success", result.toString());
}
});
}
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.
These are the available predefined events:
The full documentation is present on the javadocs to better help implementation.
Sends the device Fingerprint to Ravelin. Call this function before any important moment in the customer journey that matches a checkpoint. The following is a list of possible checkpoints (subject to the Ravelin products you are using):
Ensure that the customerId is set before trackFingerprint() is called.
Only takes an optional callback
.
Kotlin
// set Customer ID
ravelin.customerId = "12346578"
// immediately call asynchronously
ravelin.trackFingerprint(object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
// set Customer ID
void main() {
ravelin.setCustomerId("12346578");
// immediately call asynchronously
ravelin.trackFingerprint(new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
To indicate when the user hits a new page. We would like this to be used for every new page or screen the user goes to.
Required pageName
, optional payload
to be serialized and optional callback
. Note: payload is
of type LinkedHashMap<String, Any?>? but will accept only the following types for the value entry:
Number?, String?, Boolean?, List<Any?>? where Any? could include combinations of Number?, String?
and Boolean? In case you require support for additional types, please contact us and we would
support them in future versions.
Kotlin
// immediately call asynchronously
ravelin.trackPage(
"Product List - Toothbrushes",
linkedMapOf("Property 1" to "Custom", "Property 2" to "Data"),
object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
// immediately call asynchronously
final LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("Proeprty 1", "Custom");
map.put("Proeprty 2", "Data");
ravelin.trackPage("Product List - Toothbrushes", map, new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
To be used when a user performs a search.
There is an optional searchValue property that can be added to let us know about the search term.
Required pageTitle
, optional searchValue
to be serialized and optional callback
.
Kotlin
// immediately call asynchronously
ravelin.trackSearch(
"Product List - Toothbrushes",
"search value",
object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
// immediately call asynchronously
ravelin.trackSearch("Product List - Toothbrushes", "Search value", new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
To be used when a user selects or changes a product option like colour, size or delivery option.
There is an optional option
property that can be added to let us know about the what option was
selected, we suggest using one of the following values colour
, size
, date
, time
, seat
, ticketType
, delivery option
, but other values are accepted.
There is also an optional optionValue
property that can be sent to let us know what value was
selected.
Required pageTitle
, optional option
and optionValue
to be serialized and optional callback
.
Kotlin
// immediately call asynchronously
ravelin.trackSelectOption(
"Product Page",
"Option",
"Option Value",
object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
// immediately call asynchronously
ravelin.trackSelectOption("Product Page", "Option", "Option Value", new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
To be used when an item is added or removed from the cart.
There are two optional properties itemName
and quantity
that can be added to let us know the
product name and the quantity.
Required pageTitle
, optional itemName
and quantity
to be serialized and optional callback
.
Kotlin
// immediately call asynchronously
ravelin.trackAddToCart("Product Page", "Item Name", 5, object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
// immediately call asynchronously
ravelin.trackAddToCart("Product Page ", "Item Name", 5, new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
To be used when an item is added or removed from the wishlist.
There is an optional itemName
property that can be added to let us know the product name.
Required pageTitle
, optional itemName
to be serialized and optional callback
.
Kotlin
// immediately call asynchronously
ravelin.trackAddToWishlist("Product Page", "Item Name", object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
// immediately call asynchronously
ravelin.trackAddToWishlist("Product Page", "Item Name", new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
To be used when a user changes the language of the application. The language
is an optional parameter and it should be compatible with ISO-639.
Examples for accepted values: en, en-us, en-gb, da, cs, EN-GB, EN-US, En-uS
When language
is not set, this track session event may only indicate that the application language has changed without the actual new value.
Required pageTitle
, optional language
to be serialized and optional callback
.
Kotlin
// immediately call asynchronously
ravelin.trackLanguageChange("Product Page", "en-us", object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
// immediately call asynchronously
ravelin.trackLanguageChange("Product Page", "en-us", new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
To be used when a user changes the currency used by the application. The currency
itself is an optional parameter and it should be compatible with ISO-4217.
Examples for accepted values: EUR, USD, NZD, eur, usd, nzd, nZd
When currency
is not set, this track session event may only indicate that the application currency has changed without the actual new value.
Required pageTitle
, optional currency
to be serialized and optional callback
.
Kotlin
// immediately call asynchronously
ravelin.trackCurrencyChange("Product Page", "EUR", object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
// immediately call asynchronously
ravelin.trackCurrencyChange("Product Page", "EUR", new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
To be used when the user interacts with product content like plays a video, expands a photo, expands product details.
There is an optional contentType
property to let us know what content the user interacted with, we
suggest using one of the following values video
, photo
, productDescription
, deliveryOptions
,
but other values are accepted.
Required pageTitle
, optional contentType
to be serialized and optional callback
.
Kotlin
// immediately call asynchronously
ravelin.trackViewContent("Product Page", "Content Type", object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
java
class Example {
void main() {
// immediately call asynchronously
ravelin.trackViewContent("Product Page", "Content Type", new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
Tracks a user or app event.
Required eventType
, optional pageTitle
, optional payload
to be serialized and
optional callback
.
Note: payload is of type LinkedHashMap<String, Any?>? but will accept only the following types for the value entry: Number?, String?, Boolean?, List<Any?>? where Any? could include combinations of Number?, String? and Boolean? In case you require support for additional types, please contact us and we would support them in future versions.
Kotlin
// immediately call asynchronously
ravelin.trackEvent(
"app open",
"login activity",
linkedMapOf(
"Property 1" to "Custom",
"Property 2" to 1,
"Property 3" to true,
"Property4" to null,
"Property 5" to listOf(1, null, true, 1.234)
),
object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
final LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("Proeprty 1", "Custom");
map.put("Proeprty 2", 1);
map.put("Proeprty 3", true);
map.put("Proeprty 4", null);
List<Object> list = new ArrayList();
list.add(1);
list.add(null);
list.add(true);
list.add(1.234);
// immediately call asynchronously
ravelin.trackEvent("app open", "login activity", map, new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
Tracks a user login event.
Required customerId
, optional pageTitle
, optional payload
to be serialized and
optional callback
.
Note: payload is of type LinkedHashMap<String, Any?>? but will accept only the following types for the value entry: Number?, String?, Boolean?, List<Any?>? where Any? could include combinations of Number?, String? and Boolean? In case you require support for additional types, please contact us and we would support them in future versions.
Kotlin
// immediately call asynchronously
ravelin.trackLogIn(
"15464811",
"login activity",
linkedMapOf("Class" to "Mage"),
object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
final HashMap<String, String> map = new LinkedHashMap<>();
map.put("Class", "Mage");
// immediately call asynchronously
ravelin.trackLogIn("app open", "login activity", map, new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
Tracks a user logout event.
pageTitle
and payload
are optional serialized parameters. callback
is optional.
Note: payload is of type LinkedHashMap<String, Any?>? but will accept only the following types for the value entry: Number?, String?, Boolean?, List<Any?>? where Any? could include combinations of Number?, String? and Boolean? In case you require support for additional types, please contact us and we would support them in future versions.
Kotlin
// immediately call asynchronously
ravelin.trackLogOut(
"User Account",
linkedMapOf("Class" to "Mage"),
object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
final HashMap<String, String> map = new LinkedHashMap<>();
map.put("Class", "Mage");
// immediately call asynchronously
ravelin.trackLogOut("login activity", map, new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(@NotNull RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
This method is used primarily by the Ravelin PasteEventListener
but can be used directly if
required.
Required value
, optional pageTitle
and optional callback
.
Kotlin
// immediately call asynchronously
ravelin.trackPaste("checkout activity", pastedCharacters, object : RavelinRequestCallback() {
override fun success(payload: Array<ResponsePayload>?) {
payload?.forEachIndexed { index, responsePayload ->
Log.d(TAG, "API Request Success with payload $index = $responsePayload")
}
}
override fun failure(error: RavelinError) {
Log.e("API Request Error", error.message)
}
})
Java
class Example {
void main() {
// immediately call asynchronously
ravelin.trackPaste("login activity", pastedCharacters, new RavelinRequestCallback() {
@Override
public void success(@Nullable ResponsePayload[] payload) {
if (payload != null) {
for (ResponsePayload responsePayload : payload) {
Log.i("MainActivity", "Ravelin payload = " + responsePayload);
}
}
}
@Override
public void failure(RavelinError error) {
Log.e("API Request Error", error.getMessage());
}
});
}
}
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 accidentally 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
class Example {
void main() {
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");
}
})
);
}
}
The Ravelin SDK generates a unique DeviceId during the initialisation stage.
The following code snippets show how to access the deviceId.
class Example {
fun getDeviceId(): String = run {
val ravelinSdk = RavelinSDK.getSharedInstance()
ravelinSdk.getDeviceId()
}
}
class Example {
String getDeviceId() {
RavelinSdk ravelinSdk = RavelinSDK.Companion.getSharedInstance();
if (ravelinSdk != null) {
return ravelinSdk.getDeviceId();
} else {
return null;
}
}
}
Alternatively, you may provide your own deviceId implementation by setting it directly as an argument when creating the SDK instance.
In this case the SDK will opt for the provided deviceId instead of generating a new one.
The provided deviceId needs to meet the following conditions:
1.
Max length is 128 characters.
2.
Should consist of basic latin(Unicode) characters in the range (‘u0021’-‘u007e’) only.
The following code snippets show how set the deviceId during SDK creation:
class Example {
fun createInstance(app: Application, myDeviceId: String, myAppVersion: String) {
RavelinSDK.createInstance(this, "api_key_123456789", myAppVersion, myDeviceId,
object : RavelinCallback<RavelinSDK>() {
override fun success(instance: RavelinSDK) {
Log.i("Ravelin Setup Success", "deviceId = ${instance.getDeviceId()}")
}
override fun failure(error: RavelinError) {
Log.e("Ravelin Setup Error", error.message)
}
})
}
}
class Example {
void createInstance(Application app, String myDeviceId, String myAppVersion) {
RavelinSDK.Companion.createInstance(app, "api_key_123456789", myAppVersion, myDeviceId,
new RavelinCallback<RavelinSDK>() {
@Override
public void success(RavelinSDK instance) {
Log.i("Ravelin Setup Success", "deviceId = " + instance.getDeviceId());
}
@Override
public void failure(RavelinError error) {
Log.e("Ravelin Setup Error", error.getMessage());
}
});
}
}
In the following form, we collect card details from the customer, encrypt them and send that encrypted values (the cipher) back to your server.
class ShopApplication : Application() {
override fun onCreate() {
// 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(result: RavelinSDK) {
result.customerId =
customerId // set customer id either directly or via trackLogin method
// this id will then be sent with all subsequent tracking events
result.orderId = "your own order ID" // set order id to your own order reference
result.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.toString()
val month = expirationMonthTextView.text.toString()
val year = expirationYearTextView.text.toString()
val name = nameOnCardTextView.text.toString()
val cardDetails = CardDetails(pan, month, year, name)
if (ravelin != null) {
ravelin.encryptCard(
cardDetails,
"RSA-KEY",
object : RavelinCallback<EncryptedCard>() {
override fun success(result: EncryptedCard) {
Log.e("Card Encryption Success", "hooray")
sendEncryptedDetailsToYourServer(encryptedCardDetails)
}
override fun failure(error: RavelinError) {
Log.e("Card Encryption Error", error.message)
}
})
}
}
}
}
public class ShopApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// Create instance referencing the application.
// This can be done anywhere if the application does not extend Application
RavelinSDK.Companion.createInstance(this, "api_key_123456789", new RavelinCallback<RavelinSDK>() {
@Override
public void success(RavelinSDK result) {
Log.e("Ravelin Setup Success", "hooray");
}
@Override
public void failure(@NotNull RavelinError error) {
Log.e("Ravelin Setup Error", error.getMessage());
}
});
}
}
public class ShopActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final String customerId = "1234"; // get customerId from your login process
final RavelinSDK ravelin = RavelinSDK.Companion.getSharedInstance(new RavelinCallback<RavelinSDK>() {
@Override
public void success(RavelinSDK result) {
result.setCustomerId(customerId); // set customer id either directly or via trackLogin method
// this id will then be sent with all subsequent tracking events
result.setOrderId("your own order ID"); // set order id to your own order reference
result.trackPage("Shopping Page");
}
@Override
public void failure(RavelinError error) {
Log.e("Ravelin Setup Error", error.getMessage());
}
});
final TextView cardNumberTextView = findViewById(R.id.pan);
final TextView expirationMonthTextView = findViewById(R.id.expiration_month);
final TextView expirationYearTextView = findViewById(R.id.expiration_year);
final TextView nameOnCardTextView = findViewById(R.id.name_on_card);
findViewById(R.id.payButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String pan = cardNumberTextView.getText().toString();
String month = expirationMonthTextView.getText().toString();
String year = expirationYearTextView.getText().toString();
String name = nameOnCardTextView.getText().toString();
CardDetails cardDetails = new CardDetails(pan, month, year, name);
if (ravelin != null) {
ravelin.encryptCard(cardDetails, "RSA-KEY", new RavelinCallback<EncryptedCard>() {
@Override
public void success(EncryptedCard result) {
Log.e("Card Encryption Success", "hooray");
sendEncryptedDetailsToYourServer(encryptedCardDetails);
}
@Override
public void failure(@NotNull RavelinError error) {
Log.e("Card Encryption Error", error.getMessage());
}
});
}
}
});
}
}
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://pci.ravelin.com/v2/checkout?score=true', {
// ...
'paymentMethod': card,
});
/**
* Method for creating a singleton instance of the object that holds required methods for
* communicating with Ravelin APIs. The created object can be accessed by a call to
* [getSharedInstance]. In order to create the object the API key must be provided.
*
* If called a second time, the parameters are ignored and the initial instance is returned, unless a call
* to [cleanup] is made between the two calls.
*
* @param application - The Android Application class that this instance is attached to
* @param apiKey - The Ravelin public API key.
* @param appVersion - Optional. Version of the application.
* @param myDeviceId - Optional. User device id. When set, it will be used as the device id.
* Instead of the SDK generated device id, even when the SDK
* is first initialised with its own device id.
* @param callback - Optional. callback.
* @return - Create a new instance of the RavelinSDK. If this is called a second time, no
* new instance is created.
*/
@JvmOverloads
@Synchronized
fun createInstance(
application: Application,
apiKey: String,
appVersion: String? = null,
myDeviceId: String? = null,
callback: RavelinCallback<RavelinSDK>? = null
): RavelinSDK?
Your Publishable API Key. See Authentication for where to find this.
/**
* Method for accessing the Ravelin object for communicating with its APIs.
*
* Only to be called after the Ravelin SDK has been first initialised using the API key,
* otherwise, the [RavelinCallback.failure] callback method is triggered.
*
* @param callback - An optional callback that is responsible to warn
* whether the RavelinSDK instance could be retrieved successfully or not.
* @return - An instance of a previously created RavelinSDK, null if it is not existent.
*/
@JvmOverloads
fun getSharedInstance(callback: RavelinCallback<RavelinSDK>? = null): RavelinSDK?
/**
* cleaning the SDK instance and its resources.
* Note: This function should be called if additional interactions with the SDK are not
* expected and it can be garbage collected.
*
* @param callback a [RavelinCallback] of type [String] to indicate the function status
* back to the caller.
*/
@JvmOverloads
@JvmStatic
fun cleanup(callback: RavelinCallback<String>? = null): Unit?
/**
* Property to access the unique identifier that represents user's device. The property has a
* private setter and hence can't be set externally. If the deviceId failed to be generated, calling
* this property should throw an [UninitializedPropertyAccessException] exception.
*
* @return the device id [String?]
*/
@get:Throws(UninitializedPropertyAccessException::class)
var deviceId: String? = null
How to call access this property:
ravelin.deviceId
ravelin.getDeviceId();
/**
* Notify Ravelin of the device fingerprint. This function creates a coroutine and runs
* asynchronously.
*
* @param callback - Optional callback for the API response of type [RavelinRequestCallback].
*/
@JvmOverloads
fun trackFingerprint(callback: RavelinRequestCallback? = null): Job?
/**
* Notify Ravelin of a new page being shown.
*
* @param pageTitle - The title of the current screen.
* @param payload - Additional data to be sent to Ravelin. [Properties] is a type alias of
* [LinkedHashMap<String, Any?>?].
* @param callback - Optional callback for the API responses.
*
*/
@JvmOverloads
fun trackPage(
pageTitle: String,
payload: Properties? = null,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin of a new search being performed.
*
* @param pageTitle - The title of the current screen.
* @param searchValue - Optional string that was used to perform a search.
* @param callback - Optional callback for the API responses.
*
*/
@JvmOverloads
fun trackSearch(
pageTitle: String,
searchValue: String? = null,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin of an option being selected.
*
* @param pageTitle - The title of the current screen.
* @param option - Optional selected item definition.
* Example: {colour, size, date, time, seat, ticketType}
* @param optionValue - Optional value of the informed option.
* Example: {blue, M, 14, first class}
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackSelectOption(
pageTitle: String,
option: String? = null,
optionValue: String? = null,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin of a new cart addition.
*
* @param pageTitle - The title of the current page.
* @param itemName - Optional. The name of the item added to the cart.
* @param quantity - Optional. The amount of the items that were added.
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackAddToCart(
pageTitle: String,
itemName: String? = null,
quantity: Int? = 0,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin of a new cart removal.
*
* @param pageTitle - The name of the current screen.
* @param itemName - Optional. The name of the item removed to the cart.
* @param quantity - Optional. The amount of the items that were removed.
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackRemoveFromCart(
pageTitle: String,
itemName: String? = null,
quantity: Int? = 0,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin of a new item added to users wishlist.
*
* @param pageTitle - The page where the item was added to a wishlist.
* @param itemName - Optional. The name of the item added to a wishlist.
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackAddToWishlist(
pageTitle: String,
itemName: String? = null,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin of a item removed from users wishlist.
*
* @param pageTitle - The page where the item was removed from a wishlist.
* @param itemName - Optional. The name of the item removed from a wishlist.
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackRemoveFromWishlist(
pageTitle: String,
itemName: String? = null,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin about a change in the application language.
*
* @param pageTitle - The page where the new language was set.
* @param language - An ISO-639-1 representation of the new language.
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackLanguageChange(
pageTitle: String,
language: String?,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin about a change in the application currency.
*
* @param pageTitle - The page where the new currency was set.
* @param currency - An ISO-4217 representation of the new currency.
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackCurrencyChange(
pageTitle: String,
currency: String?,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin that a user interacts with product contents. This interaction can be
* plays a video, expands a photo, expands product details, clicks a link in the page, etc.
* The call can optionally include the content type that the user interacted with.
*
* @param pageTitle - The page where the content was seen.
* @param contentType - Optional. The type of content that was interacted to.
* Examples: {video, photo, product description, delivery options}
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackViewContent(
pageTitle: String,
contentType: String? = null,
callback: RavelinRequestCallback? = null
)
/**
* Track a Click (customer action) Event.
*
* @param eventType - The type of triggered event
* @param pageTitle - Optional. The screen in which the click event occurred.
* @param payload - Optional object to be serialized and transmitted with the event.
* [Properties] is a type alias of [LinkedHashMap<String, Any?>?].
* @param callback - Optional callback for the API request communication.
*/
@JvmOverloads
fun trackEvent(
eventType: String,
pageTitle: String? = null,
payload: Properties? = null,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin of a successful login.
*
* @param customerId - The Customer identifier as a String
* @param pageTitle - Optional. The screen where the login occurred.
* @param payload - Optional. Additional data to be sent to Ravelin.
* [Properties] is a type alias of [LinkedHashMap<String, Any?>?].
* @param callback - Optional callback for the API responses.
*
*/
@JvmOverloads
fun trackLogIn(
customerId: String,
pageTitle: String? = null,
payload: Properties? = null,
callback: RavelinRequestCallback? = null
)
/**
* Notify Ravelin of a logout and clears [sessionId].
*
* @param pageTitle - Optional. The page where the logout occurred
* @param payload - Optional. Additional data to be sent to Ravelin.
* [Properties] is a type alias of [LinkedHashMap<String, Any?>?].
* @param callback - Optional callback for the API responses.
*/
@JvmOverloads
fun trackLogOut(
pageTitle: String? = null,
payload: Properties? = null,
callback: RavelinRequestCallback? = null
)
/**
* Track a paste event with the content tracked.
*
* @param pageTitle - Optional. The screen where the paste event occurred.
* @param value - Pasted text string.
* @param callback - Optional callback for the API request.
*
*/
@JvmOverloads
fun trackPaste(
pageTitle: String? = null,
value: String,
callback: RavelinRequestCallback? = null
)
/**
* Your chosen customer ID
*
* @return the customer ID [String?].
*/
var customerId: String? = null
How to access this property:
Kotlin
ravelin.customerId
ravelin.customerId = "cust-1"
Java
ravelin.getCustomerId();
ravelin.setCustomerId("cust-1");
/**
* 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.
*
* @return the temporary customer ID [String?].
*/
var tempCustomerId: String? = null
How to access this property:
Kotlin
ravelin.tempCustomerId
ravelin.tempCustomerId = "temp-1"
Java
ravelin.getTempCustomerId();
ravelin.setTempCustomerId("temp-1");
/**
* The ID for this specific order.
*
* @return the order ID [String?].
*/
var orderId: String? = null
How to access this property:
Kotlin
ravelin.orderId
ravelin.orderId = "930393-BBB"
Java
ravelin.getOrderId();
ravelin.setOrderId("930393-BBB");
/**
* Encrypt provided [CardDetails] ready to be sent to Ravelin.
*
* @param cardDetails the plain text [CardDetails] to be encrypted
* @param callback to handle null-safe results or handle errors
* @return - An encrypted card of type [EncryptedCard?] or null if an error occurred during
* encryption.
*/
@Suppress("unused")
@JvmOverloads
@RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
fun encryptCard(
cardDetails: CardDetails,
rsaKey: String,
callback: EncryptCallback<EncryptedCard>? = null
): EncryptedCard?
For apps that provide part of the user interface with WebViews, embedded within a native app, it is recommended making a deviceId cookie available to those WebViews that utilise ravelinjs. The current version of ravelinjs will adhere to any ravelinDeviceId cookie that it finds.
Here is a simple example of sharing the deviceId via a cookie. It is based on jetpack compose but you may use any other UI framework.
internal class BrowserViewModel : ViewModel() {
private val cookie = MutableStateFlow(EMPTY_STRING)
val safeCookie = cookie.asStateFlow()
fun fetchCookieContent() = viewModelScope.launch(Dispatchers.Default) {
val deviceId = RavelinSDK.getSharedInstance()?.deviceId
cookie.updateAndGet { "$COOKIE_NAME=$deviceId" }
}
companion object {
private const val COOKIE_NAME = "ravelinDeviceId"
private const val EMPTY_STRING = ""
}
}
And the composable:
private const val HOST_NAME = "https://www.yourhostname.org/"
@Composable
internal fun Browser(
modifier: Modifier,
myUrl: String = HOST_NAME,
viewModel: BrowserViewModel?
) {
var webView: WebView? = null
val cookie = viewModel?.safeCookie?.collectAsStateWithLifecycle(EMPTY_STRING)?.value
val cookiesManager = CookieManager.getInstance()
// The following if-statement is important to make sure that the WebView is created when the cookie
// state is updated as the factory lambda is not a recomposition point.
if (!cookie.isNullOrEmpty()) {
AndroidView(
modifier = modifier,
factory = { context ->
WebView(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
webViewClient = object : WebViewClient() {
override fun onPageStarted(
view: WebView?,
url: String?,
favicon: Bitmap?
) {
println("Cookie = ${cookiesManager.getCookie(url)}")
super.onPageStarted(
view,
url,
favicon
)
}
}
webView = this
cookiesManager.setCookie(
myUrl,
cookie
)
loadUrl(myUrl)
}
})
}
LaunchedEffect(true) {
viewModel?.fetchCookieContent()
}
}
Providing this library would not have been possible without the stellar works upon which it relies:
Dependency Name | Version | Comment for manual integration |
---|---|---|
*** Serialization*** | ||
Kotlin Serialization(Apache2) | 1.6.0 | |
Kotlin Serialization Converter(Apache2) | 1.0.0 | |
Coroutines | ||
Kotlin Coroutines(Apache2) | 1.7.3 | |
Retrofit | ||
Retrofit (Apache2) | 2.9.0 | |
Http Client | ||
okhttp3 (Apache2) | 4.12.0 | |
okhttp3-logging-interceptor (Apache2) | 4.12.0 | |
Architecture Components | ||
KTX (Apache2) | 1.12.0 | |
WorkManager (Apache2) | 2.9.0 | |
AppCompat (Apache2) | 1.6.1 | Only when integrating Ravelin encryption |
Local Database | ||
Room (Apache2) | 2.6.1 | |
Room Ktx (Apache2) | 2.6.1 | |
Room Compiler (Apache2) | 2.6.1 | for Annotation processing with Ksp |
Dependency Injection | ||
Dagger2 (Apache2) | 2.51 | |
Dagger2-Android (Apache2) | 2.51 | |
Dagger-Compiler (Apache2) | 2.51 | for Annotation processing with Ksp |
Dagger-Android-Processor (Apache2) | 2.51 | for Annotation processing with Ksp |
Logging | ||
Timber (Apache2) | 5.0.1 | |
Play services | ||
Play-services-location (Apache2) | 21.2.0 |
Important! Due to a breaking change in play-services-location in version 21.0.0, use versions older than 3.0.1 only in case you are working with play-services-location older than version 21.0.0. In case you have a version of play-services-location equal or greater than 21.0.0, please use Ravelin SDK version 3.0.1+.
Breaking changes:
Array<ResponsePayload>
parameter.
This means that the core SDK is now providing an array of payload objects of type ResponsePayload
to the success function.
This is useful in case that the client is interested about the response payload from the Ravelin API, for instance when calling trackFingerprint
.Minor changes:
BIOMETRIC_STRONG
(class 3 and above) capabilities.secure-crypto
library. This library was recently deprecated by Google and
has some synchronisation issues when accessing the device KeyStore.Bug Fixes:
android.permission.READ_BASIC_PHONE_STATE
android.permission.READ_PHONE_STATE
permissions is granted.Breaking changes:
core-sdk
.
The app version is sent to Ravelin as part of the device fingerprint.deviceId
setter is now private. Setting the deviceId can be done during the SDK initialisation.Minor changes:
trackFingerprint
event to avoid sending too many fingerprints at once.Bug fixes:
source
is renamed to installationSource
.This is a special release. Only ravelin-core library is updated in this release.
ravelin-core
library is now public and can be accessed without credentials.trackCurrencyChange
and trackLanguageChange
are now available.ravelin-core
library source code is obfuscated again with ProGuard. Please see ProGuard rules required to avoid additional obfuscation of the library by the app provider.trackPaste
session tracking function.This is a special version of ravelin-core introducing several updates aimed only for clients of play-services-location older than 21.0.0. We have no plans to introduce new features or releases related to this version in the future, hence we recommend to use it only in case you are working with play-services-location older than version 21.0.0.
trackPaste
session tracking function.This is a special release. Only ravelin-encrypt library is updated in this release.
cleanup
to clean resources when the application finishes its
work with the SDK.Timber
for logging messages.Fatal Exception: java.lang.IllegalStateException: error must not be null
Fatal Exception: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
Was this page helpful?