Android SDK

Contents

Introduction

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 Access The DeviceId.
  • The collection of additional device details
  • Session tracking
  • If relevant to your integration, the encryption of card details

We have two modules/dependencies within the SDK:

  • ravelin-core - Which is used for deviceId, fingerprinting and tracking activity
  • ravelin-encrypt - for card details encryption

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

Getting started

Versions 3.1.0+

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

  • Valid API keys which are available in the Ravelin dashboard. See Authentication for where to find these.
  • ravelin-core and ravelin-encrypt are now public and may be accessed without credentials from Ravelin Maven/CloudRepo repository.

Versions 3.0.3 and below

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

  • Valid API keys which are available in the Ravelin dashboard. See Authentication for where to find these.
  • Valid username and password for the private Ravelin Maven/CloudRepo repository.

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

Minimum Requirements

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.8.20

Installing the Ravelin Android SDK

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).

Installing via Gradle

Please note that the following setup is basic and doesn’t include buildSrc configurations, version catalogs or convention plugins.

Versions 3.1.0+

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:3.1.0'
    implementation 'com.ravelin.sdk:ravelin-encrypt:3.1.0'
}
dependencies {
    /* other dependencies */
    implementation("com.ravelin.sdk:ravelin-core:3.1.0")
    implementation("com.ravelin.sdk:ravelin-encrypt:3.1.0")
}

Versions 3.0.3 and below

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")
}

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.

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.

Handle application backup rules

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" />
    </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" />
    </full-backup-content>

Updating the Ravelin Android SDK

There are two methods of updating 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.

Updating via Gradle

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:3.1.0'
    implementation 'com.ravelin.sdk:ravelin-encrypt:3.1.0'
}

To verify the latest Ravelin SDK version check our Release Notes section.

Updating Manually

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 sectionand make sure you are using the latest SDK version AAR.

Permissions

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:

ACCESS_COARSE_LOCATION & ACCESS_FINE_LOCATION

Information about users localization

  • Accuracy
  • Altitude
  • Bearing
  • ElapsedRealTimeNanos
  • Latitude
  • Longitude
  • Provider
  • Speed
  • Time

In addition, the ACCESS_FINE_LOCATION permission is required in order to get the connection MAC address.

READ_PHONE_STATE & READ_BASIC_PHONE_STATE (API level <= 33)

Information about users phone

  • IsWorldPhone
  • Network type
  • imei (GSM networks) / meid (CDMA networks) / deviceId (API level <= 25)
  • imsi

BLUETOOTH & BLUETOOTH_CONNECT (API level <= 31)

Information about devices bluetooth.

  • Bluetooth MAC

ACCESS_NETWORK_STATE

Information about network capabilities.

  • Transport type attribute

ACCESS_WIFI_STATE

Information about devices wireless connection interface.

  • WIFI MAC

REQUEST_INSTALL_PACKAGES (API level >= 26)

Information about installed packages.

  • Non market apps package installation permission.

INTERNET

Allows internet connection access to background processes.

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.


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 three static instance accessors:

  1. RavelinSDK.createInstance
  2. RavelinSDK.getSharedInstance
  3. 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(...).

Custom WorkManager Configuration and Initialization

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:

  1. Let your Application class implement the 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)
    }

    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);
    }

    @NonNull
    @NotNull
    @Override
    public Configuration getWorkManagerConfiguration() {
        return new Configuration.Builder().build();
    }

    //...
}

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.

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:

  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. If the year is the current year then the month must be greater than or equal to the current month
  5. When not null, the name must be between 2-26 long and consist of the following characters: ‘, -, a-z, A-Z and space.

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");
}

Card Validation

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());
            }
        });
}

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.

These are the available predefined events:

The full documentation is present on the javadocs to better help implementation.

trackFingerprint

Sends the device Fingerprint to Ravelin. Call this function before any important moment in the customer journey that matches a checkpoint. The fingerprint is used to profile a user’s device. The following is a list of possible checkpoints (subject to the Ravlein products you are using):

  • Right after initialisation and before trackLogin.
  • Before any call to the checkout API.
  • Before sending a refund request.
  • Before sending an account registration request.

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() {
        Log.d("API Request Success", "hooray")
    }

    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() {
                Log.d("API Request Success", "hooray");
            }

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

trackPage

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() {
            Log.d("API Request Success", "hooray")
        }

        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() {
                Log.d("API Request Success", "hooray");
            }

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

trackSearch

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() {
            Log.d("API Request Success", "hooray")
        }

        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() {
                Log.d("API Request Success", "hooray");
            }

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

trackSelectOption

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() {
            Log.d("API Request Success", "hooray")
        }

        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() {
                Log.d("API Request Success", "hooray");
            }

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

trackAddToCart and trackRemoveFromCart

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() {
        Log.d("API Request Success", "hooray")
    }

    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() {
                Log.d("API Request Success", "hooray");
            }

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

trackAddToWishlist and trackRemoveFromWishlist

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() {
        Log.d("API Request Success", "hooray")
    }

    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() {
                Log.d("API Request Success", "hooray");
            }

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

trackLanguageChange

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() {
        Log.d("API Request Success", "hooray")
    }

    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() {
                Log.d("API Request Success", "hooray");
            }

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

trackCurrencyChange

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() {
        Log.d("API Request Success", "hooray")
    }

    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() {
                Log.d("API Request Success", "hooray");
            }

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

trackViewContent

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() {
        Log.d("API Request Success", "hooray")
    }

    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() {
                Log.d("API Request Success", "hooray");
            }

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

trackEvent

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() {
            Log.d("API Request Success", "hooray")
        }

        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() {
                Log.d("API Request Success", "hooray");
            }

            @Override
            public void failure(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.

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() {
            Log.d("API Request Success", "hooray")
        }

        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() {
                    Log.d("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.

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() {
            Log.e("API Request Success", "hooray")
        }

        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() {
                Log.d("API Request Success", "hooray");
            }

            @Override
            public void failure(@NotNull 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

// immediately call asynchronously
ravelin.trackPaste("checkout activity", pastedCharacters, object : RavelinRequestCallback() {
    override fun success() {
        Log.d("API Request Success", "hooray")
    }

    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() {
                Log.d("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 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");
                    }
                })
            );
    }
}

ProGuard rules

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. 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.

Access the DeviceId

The Ravelin SDK generates a unique DeviceId during the initialisation stage.

The following code snippets show how to access the deviceId.

Kotlin

class Example {
    fun getDeviceId(): String = run {
        val ravelinSdk = RavelinSDK.getSharedInstance()
        ravelinSdk.getDeviceId()
    }
}

Java

class Example {
    String getDeviceId() {
        RavelinSdk ravelinSdk = RavelinSDK.Companion.getSharedInstance();
        if (ravelinSdk != null) {
            return ravelinSdk.getDeviceId();
        } else {
            return null;
        }
    }
}

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() {
        // 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)
                        }
                    })
            }
        }
    }
}

java

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,
});

Class members - Ravelin Core

createInstance

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

Create a singleton instance of the Ravelin SDK with your Publishable API Key.

Parameters

Parameter Type Description
application Application The Android Application class that this instance is attached to.
apiKey String Your Publishable API Key. See Authentication for where to find this.
callback RavelinCallback Optional callback.

Return value

A nullable singleton instance of the class

Create a new instance of the RavelinSDK. If this is called a second time, no new instance is created.


getSharedInstance

getSharedInstance(callback: RavelinCallback<RavelinSDK>? = null): RavelinSDK?

Method for accessing the required methods for communicating with Ravelin APIs.

Only to be called after the Ravelin SDK has been first initialised using your Publishable API Key and/or RSA key otherwise the RavelinCallback#failure callback method is triggered.

Parameters

Parameter Type Description
callback Application An optional callback that is responsible to warn whether the RavelinSDK instance could be retrieved with success or not.

Return Value

An instance of a previously created RavelinSDK, null if it is not existent.


getDeviceId()

Utility method that allows user to know the unique identifier that represents users device.

Return value

A String identifying the device - persistent across Google accounts.


trackFingerprint

trackFingerprint(callback: RavelinRequestCallback? = null)

Fingerprints the device and sends results to Ravelin.

Parameters

Parameter Type Description
callback RavelinRequestCallback? Optional callback for the API response.

trackPage

trackPage(pageTitle: String, payload: LinkedHashMap<String, Any?>? = null, callback: RavelinRequestCallback? = null)

Sends a track page event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
payload LinkedHashMap<String, Any?>? Additional data to be sent to Ravelin.
callback RavelinRequestCallback? Optional callback for the API responses.

trackSearch

trackSearch(pageTitle: String, searchValue: String? = null, callback: RavelinRequestCallback? = null)

Sends a track search event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
searchValue String? Optional string that was used to perform a search.
callback RavelinRequestCallback? Optional callback for the API responses.

trackSelectOption

trackSelectOption(pageTitle: String, option: String? = null, optionValue: String? = null, callback: RavelinRequestCallback? = null)

Sends a track selected option event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
option String? The name of the option, optional. Example: {colour, size, date, time, seat, ticketType}
optionValue String? The value of the option, optional. Example: {blue, M, 14, first class}
callback RavelinRequestCallback? Optional callback for the API responses.

trackAddToCart

trackAddToCart(pageTitle: String, itemName: String? = null, quantity: Int? = 0, callback: RavelinRequestCallback? = null)

Sends a track add to cart event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
itemName String? The name of the item, optional.
quantity String? The quantity of the item, optional.
callback RavelinRequestCallback? Optional callback for the API responses.

trackRemoveFromCart

trackRemoveFromCart(pageTitle: String, itemName: String? = null, quantity: Int? = 0, callback: RavelinRequestCallback? = null)

Sends a track remove from cart event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
itemName String? The name of the item, optional.
quantity String? The quantity of the item, optional.
callback RavelinRequestCallback? Optional callback for the API responses.

trackAddToWishlist

trackAddToWishlist(pageTitle: String, itemName: String? = null, callback: RavelinRequestCallback? = null)

Sends a track add to wishlist event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
itemName String? The name of the item, optional.
callback RavelinRequestCallback? Optional callback for the API responses.

trackRemoveFromWishlist

trackRemoveFromWishlist(pageTitle: String, itemName: String? = null, callback: RavelinRequestCallback? = null)

Sends a track remove from wishlist event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
itemName String? The name of the item, optional.
callback RavelinRequestCallback? Optional callback for the API responses.

trackLanguageChange

trackLanguageChange(pageTitle: String, language: String? = null, callback: RavelinRequestCallback? = null)

Sends a track language changed event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
language String? An ISO-639-1 representation of the new language, optional.
callback RavelinRequestCallback? Optional callback for the API responses.

trackCurrancyChange

trackCurrancyChange(pageTitle: String, currency: String? = null, callback: RavelinRequestCallback? = null)

Sends a track currency changed event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
currency String? An ISO-4217 representation of the new currency, optional.
callback RavelinRequestCallback? Optional callback for the API responses.

trackViewContent

trackViewContent(pageTitle: String, contentType: String? = null, callback: RavelinRequestCallback? = null)

Sends a track view content event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page.
contentType String? The type of the content, optional. Examples: {video, photo, productDescription, deliveryOptions}
callback RavelinRequestCallback? Optional callback for the API responses.

trackEvent

trackEvent(eventType: String, pageTitle: String? = null, payload: LinkedHashMap<String, Any?>? = null, callback: RavelinRequestCallback? = null)

Sends a track event to Ravelin. Use this method to send custom events and data to analyse in your dashboard.

Parameters

Parameter Type Description
eventType String The type of triggered event.
pageTitle String? The title of the current page.
payload LinkedHashMap<String, Any?>? Optional object to be serialized and transmitted with the event.
callback RavelinRequestCallback Optional callback for the API request communication.

trackLogIn

trackLogIn(customerId: String, pageTitle: String? = null, payload: LinkedHashMap<String, Any?>? = null, callback: RavelinRequestCallback? = null)

Sends a track login event to Ravelin.

Parameters

Parameter Type Description
customerId String The Customer identifier as a String.
pageTitle String The page where the login occurred.
payload LinkedHashMap<String, Any?> Additional data to be sent to Ravelin.
callback RavelinRequestCallback Optional callback for the API responses.

trackLogOut

trackLogOut(pageTitle: String? = null, payload: LinkedHashMap<String, Any?>? = null, callback: RavelinRequestCallback? = null)

Ends current Ravelin session and sends logout event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The page where the logout occurred .
payload LinkedHashMap<String, Any?>? Additional data to be sent to Ravelin.
callback RavelinRequestCallback Optional callback for the API responses.

trackPaste

trackPaste(value: String, pageTitle: String? = null, callback: RavelinRequestCallback? = null)`

Track a paste event with the content tracked.

Parameters

Parameter Type Description
value String Pasted text string.
pageTitle String Optional. The page where the pasting occurred.
callback RavelinRequestCallback Optional callback for the API responses.

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);

Device ID

A unique device identifier that is calculated at runtime.

Kotlin

ravelin.getDeviceId()

Java

ravelin.getDeviceId();

Class members - Ravelin Encrypt


encryptCard

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

Encrypt provided [CardDetails] ready to be sent to Ravelin

Parameters

Parameter Type Description
cardDetails CardDetails the plain text [CardDetails] to be encrypted
rsaKey String the RSA key provided
callback RavelinCallback to handle null-safe results or handle errors

Return value

A nullable encrypted card details


WebView cookies handling

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 = ""
    }
}
private const val HOST_NAME = "https://www.yourhostname.org/"

@Composable
internal fun Browser(
    modifier: Modifier,
    myUrl: String = HOST_NAME,
    viewModel: BrowserViewModelContract?
) {
    
    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()
    }
}

Bundled libraries

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.5.0
Kotlin Serialization Converter(Apache2) 1.0.0
Coroutines
Kotlin Coroutines(Apache2) 1.6.4
Retrofit (Apache2) 2.9.0
Http Client
okhttp3 (Apache2) 4.10.0
okhttp3-logging-interceptor (Apache2) 4.10.0
Architecture Components
KTX (Apache2) 1.9.0
WorkManager (Apache2) 2.8.1
AppCompat (Apache2) 1.6.1 Only when integrating Ravelin encryption
Local Database
Room (Apache2) 2.5.2
Room Ktx (Apache2) 2.5.2
Room Compiler (Apache2) 2.5.2 for Annotation processing with Kapt
Security Crypto (Apache2) 1.1.0-alpha04
Dependency Injection
Dagger2 (Apache2) 2.46.1
Dagger2-Android (Apache2) 2.46.1
Dagger-Compiler (Apache2) 2.46.1 for Annotation processing with Kapt
Dagger-Android-Processor (Apache2) 2.46.1 for Annotation processing with Kapt
Logging
Timber (Apache2) 5.0.1
Location
Play-services-location (Apache2) 21.0.1

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+.


Release Notes

v3.1.0 - August 29, 2023

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.
  • New track session events are now supported by the SDK. 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.
  • Updates in the Fingerprint model to assist detecting fraudulent activity.
  • Bug fixes and improvements.
  • Enrichment of the Mobile error reports to obtain more information about errors and events happening in the SDK.
  • Third party dependencies updates.
  • Compatibility with Kotlin 1.8.20.
  • Extend mime types recognised by the trackPaste session tracking function.
  • Emulator detection updates.

v3.0.0.1 - August 1, 2023

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.

  • Prevent use of Bluetooth and WiFi MAC addresses for device identification.
  • Emulator detection updates.
  • The field tempCustomerId is public again.
  • Extend mime types recognised by the trackPaste session tracking function.

v3.1.0 - July 7, 2023

This is a special release. Only ravelin-encrypt library is updated in this release.

  • ravelin-encrypt library is now public and can be accessed without credentials.

v3.0.3 - May 24, 2023

  • The field tempCustomerId is public again.
  • Avoid linking native libraries in unfavorable conditions such as when the app is installed by an unfamiliar vendor or side-loaded.

v3.0.2 - April 06, 2023

  • DeviceId improvements.

v3.0.1 - March 09, 2023

  • SDK is built with play-services-location (21.0.1). Version 21.0.0 of this library introduced a breaking change.

v3.0.0 - January 11, 2023

  • Support Android 13 (API level 33).
  • Migration to Kotlin 1.7.20.
  • Built with AGP 7.3.1.
  • 3rd party libraries versions update.
  • Random numbers generation seeding improvement.
  • Check the primaryClipDescription MimeType to avoid cases where intents or URIs were used instead of plain text.

v2.0.0 - July 18, 2022

  • Introduce Dependency Injection to make it easier to conduct unit and instrumentation tests.
  • Add a new accessor to RavelinSDK cleanup to clean resources when the application finishes its work with the SDK.
  • Add security measures to help detect a fraudulent transaction. Those are collected within the DeviceProperties.
  • Migration to Kotlin 1.6.21.
  • Migration to Kotlin Serialisation and remove dependency on Gson.
  • Payload type is changed to LinkedHashMap<String, Any?>? instead of Any?
  • Migration to Room.
  • Update dependencies.
  • Migration to Kotlin DSL and update our continuous integration and deployment process.
  • Migration to Timber for logging messages.
  • Retrofit calls return Call instead of Call
  • Introduce EncryptedSharedPreferences for securely storing on device data.
  • nameOnCard is still optional but when set, it will be subjected to validation.

v1.1.1 - January 13, 2022

  • Fixed a crash related to WorkManager - Remove setExpedited for API’s lower than 31 to avoid launching foreground services.

v1.1.0 - November 23, 2021

  • Support for Android 12.
  • Compatibility with Kotlin version 1.6.0
  • Updated dependencies.
  • Fixed an issue related to the way WorkManager tasks are being ran from the background when their conditions are met.

v1.0.2 - June 30, 2021

  • Fixed a crash related to WorkManager

v1.0.1 - January 14, 2021

  • Fixed an ANR issue related to RootBeer library

v1.0.0 - September 16, 2020

  • Support for Android 11.
  • Security improvements.

v0.3.0 - May 15, 2020

  • SDK is now modularised into “Core” and “Encrypt” components.
    • ravelin-core - which is used for deviceId, fingerprinting and tracking activity.
    • ravelin-encrypt - for card details encryption.
    • The modules are independent.
  • Queueing and retrying events when no internet connection or server errors.
  • Collecting new device properties (Emulator and Rooted).
  • More events to track customer activity ( example: trackSearch, trackAddToWishList ).
  • Callbacks for any track function are now all optional.

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’.

Feedback

© Ravelin Technology Ltd. All rights reserved