iOS SDK

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

Like the JavaScript library, the SDK enables:

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

We have two frameworks within the SDK:

  • RavelinCore.xcframework - Which is used for deviceId, fingerprinting and tracking activity
  • RavelinEncrypt.xcframework - for card details encryption

We also have a legacy “fat” framework available for both core and encrypt modules on versions beloow 1.1.0. We recommend that you use the XCFramewoks, since the legacy frameworks will no longer have new updates.

You can choose what functionality of the SDK you would like to use. However, at a mimimum we advise that you use the SDK to generate a reliable device ID and to send the additional device details for your app traffic. Device IDs are critical throughout our fraud prevention tool, especially for use in our graph database.

Getting Started

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

  • Obtain valid API keys which are available in the Ravelin Dashboard in the account menu under the Developer option

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

Contents

Minimum Requirements

The SDK supports a minimum iOS 9 with some exceptions around encryption written up below.

For Encryption:

If you would like to use encryption it’s only available for iOS 10 and above, where you can use the RavelinEncrypt.xcframework module which relies on native encryption.

Installing the Ravelin iOS SDK

The SDK is available via Cocoapods or Swift Swift Package Manager(SPM).

Installing via Cocoapods

Add RavelinCore to your PodFile:

pod 'RavelinCore', '1.1.0', :source => 'https://github.com/unravelin/Specs.git'

Then, from the command line: pod install

If you are using encryption also add RavelinEncrypt to your PodFile.

pod 'RavelinEncrypt', '1.1.0', :source => 'https://github.com/unravelin/Specs.git'

Installing via Swift Package Manager(SPM)

Add RavelinCore via Xcode, Add Package Dependency: a package manifest is available at: git@github.com:unravelin/ravelin-core-ios-xcframework-distribution.git

core install

If you are using encryption also add the encrypt module that is available at: git@github.com:unravelin/ravelin-encrypt-ios-xcframework-distribution

encrypt install

Swift Package Manager support is only available from version 1.1.0

Updating the Ravelin iOS SDK

Updating via Cocoapods

In your PodFile change the version to the latest SDK version number.

Use the Cocoapod command line and run pod update RavelinCore (for deviceId, fingerprinting and tracking activity) and/or pod update RavelinEncrypt (if using encryption) to update the SDK with the new version.

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

Updating via Swift Package Manager(SPM)

You can update to the latest version of any packages you depend on by selecting File ▸ Swift Packages ▸ Update to Latest Package Versions.

Updating from “fat” framework to XCFrameworks:

Before v1.1.0 the SDK was only available as a “fat” framework, since v1.1.0 and above we have updated to use the XCFrameworks.

To update to the XCFrameworks in your project’s Podfile, change from using:

'pod 'RavelinCore', '1.0.2' or: pod 'RavelinCore'

to:

pod 'RavelinCore', '1.1.0', :source => 'https://github.com/unravelin/Specs.git'

If you are using encryption follow the same steps for with RavelinEncrypt.

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

Preparing for the App Store

  • Ravelin’s encryption algorithm qualifies for exemption provided under category 5 part 2 - Information Security ECN 5X (5A002.a.a.1) of the BIS Export Administration Regulation as the primary function is “information security” and therefore no export compliance documentation is required in App Store Connect.

Usage

Importing the module

To use the framework within your project, import RavelinCore and/or RavelinEncrypt where required:

Objective-C

#import <RavelinCore/Ravelin.h>
#import <RavelinEncrypt/RavelinEncrypt.h>

Swift

import RavelinCore
import RavelinEncrypt

The singleton Ravelin class should be accessed via the sharedInstance method. You will first need to initialise the SDK with the createInstance method call with your Ravelin Publishable API Key. See the Authentication for where to find this key.

Please ensure you use your Publishable API Key. Your Secret API Key should never be embedded in your app – it should only be used to send requests from your backend to api.ravelin.com.

The singleton RVNEncryption class should be accessed via the sharedInstance method. You must then provide your RSA key for card encryption.

Objective-C

// Instantiation for tracking only
self.ravelin = [Ravelin createInstance:@"publishable_key_live_----"];

// Instantiation for encryption
self.ravelinEncrypt = [RVNEncryption sharedInstance];
self.ravelinEncrypt.rsaKey = @"----|----";

Swift

// Instantiation for tracking only
let ravelin = Ravelin.createInstance("publishable_key_live_----")

// Instantiation for encryption
let ravelinEncrypt = RVNEncryption.sharedInstance()
ravelinEncrypt.rsaKey = "----|----"

Once initialised, you can use the sharedInstance directly to access methods and properties.

Objective-C

// Directly
[[Ravelin sharedInstance] methodName];
[[RVNEncryption sharedInstance]] methodName];

// Variable
Ravelin *ravelin = [Ravelin sharedInstance];
RVNEncryption *ravelinEncrypt = [RVNEncryption sharedInstance];

Swift

// Directly
Ravelin.sharedInstance().methodName()
RVNEncryption.sharedInstance().methodName()

// Variable
let ravelin = Ravelin.sharedInstance()
let ravelinEncrypt = RVNEncryption.sharedInstance()

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 encrypt(pan, month, year, nameOnCard), pan, month, year are required, while nameOnCard is optional and may be an empty string but never null. We then encrypt the values to send using the code method below.

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

Objective-C

// Card details
NSString *pan = @"41111111111111";
NSString *month = @"10";
NSString *year = @"2022";
NSString *cardHolder = @"Mr John Doe";

// Error handling
NSError *error;

// Encrypt
NSDictionary *encryptionPayload = [[RVNEncryption sharedInstance] encrypt:pan month:month year:year nameOnCard:cardHolder error:&error];

if(!error) {
    NSLog(@"Ravelin encryption payload: %@",encryptionPayload);
    // Send to your servers

} else {
    NSLog(@"Ravelin encryption error %@", error.localizedDescription);
}

Swift

var error:NSError? = nil

let encryptionPayload = RVNEncryption.sharedInstance().encrypt("41111111111111", month: "10", year: "10", nameOnCard: "Mr John Doe", error: &error)

if let error = error {
    print("Ravelin encryption error \(error.localizedDescription)")
} else {
    print("Ravelin Encryption payload: \(encryptionPayload as AnyObject)")
    // Send to your servers
}

Tracking Activity

Using the Ravelin Mobile SDK, you can capture various built in events along with your own custom ones 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. It can also be powerfull information to use for our Machine Learning Models to identify new parterns and behaviours.

These are the available predefined events:

trackFingerprint

To be used at checkout to profile the users device. Ensure that the customerId is set before trackFingerprint() is called.

Ravelin.trackFingerprint:(NSDictionary *)eventProperties

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.

Ravelin.trackPage:(NSString *)pageTitle

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.

Ravelin.trackSearch:(NSString* _Nullable)pageTitle searchValue:(NSString* _Nullable)searchValue;

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 porperty that can be sent to let us know what value was selected.

Ravelin.trackSelectOption:(NSString* _Nullable)pageTitle option:(NSString* _Nullable)option optionValue:(NSString* _Nullable)optionValue;

trackAddToCart and removeFromCart

To be used when an item is added or removed from the cart. There are two optional properteis itemName and quantity that can be added to let us know the product name and the quantity.

Ravelin.trackAddToCart:(NSString* _Nullable)pageTitle itemName:(NSString* _Nullable)itemName quantity:(NSNumber* _Nullable)quantity;

Ravelin.trackRemoveFromCart:(NSString* _Nullable)pageTitle itemName:(NSString* _Nullable)itemName quantity:(NSNumber* _Nullable)quantity;

trackAddToWishlist and removeFromWishlist

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.

Ravelin.trackAddToWishlist:(NSString* _Nullable)pageTitle itemName:(NSString* _Nullable)itemName;

Ravelin.trackRemoveFromWishlist:(NSString* _Nullable)pageTitle itemName:(NSString* _Nullable)itemName;

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 intercated with, we suggest using one of the following values video, photo, productDescription, deliveryOptions, but other values are accepted.

Ravelin.trackViewContent:(NSString* _Nullable)pageTitle contentType:(NSString* _Nullable)contentType;

trackLogin

To indicate that the user has just authenticated themselves. Use eventProperties to add additional key/pair information to the payload

Ravelin.trackLogin:(NSString *)pageTitle eventProperties:(NSDictionary *)eventProperties

trackLogout

To indicate when the user has signed out of their session.

Ravelin.trackLogout:(NSString *)pageTitle eventProperties:(NSDictionary *)eventProperties

Custom Events and Metadata

The track method can be used to log notable client-side events:

Objective-C

NSString *pagetitle = @"productPpage";
NSString *eventName = @"SHARE_PRODUCT";
NSDictionary *meta = @{@"productId" : @"213", @"sharePlaftorm" : @"facebook"};
[[Ravelin sharedInstance]track:pageTitle eventName:eventName eventProperties:meta];

Swift

let pageTitle = "productPage"
let eventName = "SHARE_PRODUCT"
let meta = ["productId" : "213", "sharePlaftorm" : "facebook"]
Ravelin.sharedInstance().track(pageTitle, eventName: eventName, eventProperties: meta)

NOTE: Track events have overload methods with completion handlers and will accept nil values for eventProperties

Detecting paste events

We can detect paste events using the UITextFieldDelegate method shouldChangeCharactersInRange in conjunction with the Ravelin track method to send a custom event.

Objective-C

- (BOOL)textField:(UITextField *)iTextField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    // avoid checking the pasteboard when a user is typing and only adding a single character at a time
    if(string.length <= 1) { return YES; }
    // Check if the textfield contains pasted text
    if([string containsString:[UIPasteboard generalPasteboard].string]) {
        // Send paste event to Ravelin
        NSString *pageTitle = @"home";
        NSString *pasteLength = [NSString stringWithFormat:@"%ld", (long)[UIPasteboard generalPasteboard].string.length];
        NSDictionary *meta = @{@"pasteLength": pasteLength};
        [self.ravelin track:pageTitle eventName:@"paste" eventProperties:meta];
    }
    
    return YES;
}

Swift

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
         // avoid checking the pasteboard when a user is typing and only adding a single character at a time
        guard string.count > 1 else {
            return true
        }
        guard string.contains(UIPasteboard.general.string ?? "") else {
            return true
        }
        let pageTitle = "home"
        let eventName = "paste"
        let pasteLength : String = "\(UIPasteboard.general.string?.count ?? 0)"
        let meta = ["pasteLength" : pasteLength]
        self.ravelin.track(pageTitle, eventName: eventName, eventProperties: meta)

        return true
    }

NOTE: Track events have overload methods with completiton handlers

Fingerprint location tracking

For location tracking to be successful from within the Ravelin Mobile SDK, your application should ask for user permissions for location sharing. Please refer to the Apple documentation here for more information on the subject.

End-to-end example

You can check our demo repos with simple projects, showing the integration and usage of RavelinCore and RavelinEncrypt:

  • Swift using SPM
  • Swift using Cocoapods
  • Objective-C using Cocoapods

Here is a simple end-to-end example of using the Ravelin Framework within a View.

NOTE: All Ravelin network methods are asynchronous. Completion blocks are provided so you can handle each request accordingly. The example code will not necessarily call each method sequentially and is for demonstration purposes only.

Objective-C

#import "ViewController.h"
#import <UIKit/UIKit.h>
#import <RavelinCore/Ravelin.h>
#import <RavelinEncrypt/RavelinEncrypt.h>
@interface ViewController ()
@property (strong, nonatomic) Ravelin *ravelin;
@property (strong, nonatomic) RVNEncryption *ravelinEncrypt;
@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];


    // Make Ravelin instance with API keys
    self.ravelin = [Ravelin createInstance:@"publishable_key_live_----"];

    // Make RavelinEncrypt instance with rsa key
    self.ravelinEncrypt = [RVNEncryption sharedInstance];
    self.ravelinEncrypt.rsaKey = @"----|----";

    // Setup customer info and track their login
    self.ravelin.customerId = @"customer1234";
    self.ravelin.orderId = @"web-001";
    [self.ravelin trackLogin:@"loginPage"];

    // Track customer moving to a new page
    [self.ravelin trackPage:@"checkout"];

    // Send a device fingerprint
    [self.ravelin trackFingerprint];

    // Send a device fingerprint with a completion block (if required)
    [self.ravelin trackFingerprint:^(NSData *data, NSURLResponse *response, NSError *error) {
        if(!error) {
            NSDictionary *responseData;
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            if (httpResponse.statusCode == 200) {
                responseData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragments error:nil];
                // Do something with responseData

            } else {
                // Status was not 200. Handle failure
            }
        } else {
            NSLog(@"%@",error.localizedDescription);
        }
    }];

    // Encrypt customer card details, ready for sending for payment
    NSError *error;
    NSDictionary *encryptionPayload = [self.ravelinEncrypt encrypt:@"41111111111111" month:@"10" year:@"20" nameOnCard:@"Mr John Doe" error:&error];
    if(!error) {
        NSLog(@"Ravelin Encryption payload: %@", encryptionPayload);
    } else {
        NSLog(@"Ravelin encryption error %@", error.localizedDescription);
    }

    // Track a customer logout
    [self.ravelin trackLogout:@"logoutPage"];
}
@end

Swift

import UIKit
import RavelinCore
import RavelinEncrypt

class ViewController: UIViewController {

    // Declare Ravelin Shared Instance with API keys
    private var ravelin : Ravelin = Ravelin.createInstance("publishable_key_live_----")

    private var ravelinEncrypt = RVNEncryption.sharedInstance()


    override func viewDidLoad() {
        super.viewDidLoad()

        // set up ravelin encryption RSA key

        ravelinEncrypt.rsaKey = "----|----"

        // Setup customer info and track their login
        ravelin.customerId = "customer1234"
        ravelin.orderId = "web-001"
        ravelin.trackLogin("loginPage")

        // Track customer moving to a new page
        ravelin.trackPage("checkout")

        // Send a device fingerprint
        ravelin.trackFingerprint()

        // Send a device fingerprint with a completion block (if required)
        ravelin.trackFingerprint { (data, response, error) -> Void in
            if let error = error {
                // Handle error
                print("Ravelin error \(error.localizedDescription)")
            } else if let httpResponse = response as? HTTPURLResponse {
                if httpResponse.statusCode == 200 {
                    // Handle success
                }
            }
        }

        // Encrypt customer card details, ready for sending for payment
        var error:NSError? = nil
        let encryptionPayload = ravelinEncrypt.encrypt("41111111111111", month: "10", year: "20", nameOnCard: "Mr John Doe", error: &error)
        if let error = error {
            print("Ravelin encryption error \(error.localizedDescription)")
        } else {
            print("Ravelin Encryption payload: \(encryptionPayload as AnyObject)")
            // Send to server
        }

        // Track a customer logout
        ravelin.trackLogout("logoutPage")

    }
}

Ravelin Class Reference

Note: The Ravelin class requires the RavelinCore pod.

Ravelin Class Methods


createInstance (apiKey)

Create a singleton instance of the Ravelin SDK with your Publishable API Key. Use this method to create an SDK instance for tracking purposes only (i.e. without card encryption functionality)

Parameters

Parameter Type Description
apiKey String Your Publishable API Key. See Authentication for where to find this.

Return value

The singleton instance of the class


sharedInstance

Get the instantiated Ravelin singleton

Return value

The singleton instance of the class


trackFingerprint

Fingerprints the device and sends results to Ravelin

Return value

Null


trackFingerprint (completionHandler)

Fingerprints the device and sends results to Ravelin

Parameters

Parameter Type Description
completionHandler Object Completion block to handle response

trackFingerprint(customerId, completionHandler)

Sets a customerId if one has not already been set and sends a fingerprint to Ravelin

Parameters

Parameter Type Description
customerId String The customerId to set for this device fingerprint.
completionHandler Object Completion block to handle response

trackPage (pageTitle, eventProperties)

Sends a track page event to Ravelin.

Parameters

Parameter Type Description
pageTitle String The title of the current page
eventProperties Dictionary A dictionary of meta data to send with the event

Also available with a completion handler: trackPage (pageTitle, eventProperties, completionHandler)


trackSearch (pageTitle, searchValue)

Sends a track search event to Ravelin

Parameters

Parameter Type Description
pageTitle String The title of the current page
searchValue String The searched term, optional

Also available with a completion handler: trackSearch (pageTitle, searchValue, completionHandler)


trackSelectOption (pageTitle, option, optionValue)

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}

Also available with a completion handler: trackSelectOption (pageTitle, option, optionValue, completionHandler)


trackAddToCart (pageTitle, itemName, quantity)

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 NSNumber The quantity of the item, optional

Also available with a completion handler: trackAddToCart (pageTitle, itemName, quantity, completionHandler)


trackRemoveFromCart (pageTitle, itemName, quantity)

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 NSNumber The quantity of the item, optional

Also available with a completion handler: trackRemoveFromCart (pageTitle, itemName, quantity, completionHandler)


trackAddToWishlist (pageTitle, itemName)

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

Also available with a completion handler: trackAddToWishlist (pageTitle, itemName, completionHandler)


trackRemoveFromWishlist (pageTitle, itemName)

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

Also available with a completion handler: trackRemoveFromWishlist (pageTitle, itemName, completionHandler)


trackViewContent (pageTitle, contentType)

Sends a track content type 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}

Also available with a completion handler: trackViewContent (pageTitle, contentType, completionHandler)


trackLogin (pageTitle, eventProperties)

Sends a track login event to Ravelin

Parameters

Parameter Type Description
pageTitle String The title of the current page
eventProperties Dictionary A dictionary of meta data to send with the event

Also available with a completion handler: trackLogin (pageTitle, eventProperties, completionHandler)


trackLogout (pageTitle, eventProperties)

Ends current Ravelin session and sends logout event to Ravelin

Parameters

Parameter Type Description
pageTitle String The title of the current page
eventProperties Dictionary A dictionary of meta data to send with the event

Also available with a completion handler: trackLogout (pageTitle, eventProperties, completionHandler)


track (pageTitle, eventName, eventProperties)

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

Parameters

Parameter Type Description
pageTitle String The title of the current page
eventName String The name of the event
eventProperties Dictionary A dictionary of meta data to send with the event

Also available with a completion handler: track (pageTitle, eventName, eventProperties, completionHandler)


Ravelin Class Properties


apiKey

Your Publishable API Key. See Authentication for where to find this.

customerId

Your chosen customer ID

tempCustomerId

Temporary customer ID

sessionId (read only)

The Ravelin generated sessionId

deviceId (read only)

The Ravelin generated device ID

orderId

Your chosen order ID

RVNEncryption Class Reference

The RVNEncryption class requires the RavelinEncrypt pod.

RVNEncryption Class Methods


sharedInstance

Get the instantiated RVNEncryption singleton

Return value

The singleton instance of the class


encrypt (pan, month, year, nameOnCard, &error)

Generates encryption payload ready for sending to Ravelin

Parameters

Parameter Type Description
pan String A string representation of the long card number
month String Expiry month of card (1-12)
year String Expiry year (2 or 4 digit)
nameOnCard String The customer name on the card
error Object Passed as reference

Return value

Dictionary containing methodType, aesKeyCiphertext, cardCiphertext, algorithm, keyIndex and ravelinSDKVersion


RVNEncryption Class Properties


rsaKey

Your Public RSA Key. See Authentication for where to find this.

Release Notes

v1.1.0 - July 27, 2021

  • Support for XCFrameworks, supporting both M1 and Intel architectures when developing via Simulator
  • Added Swift Packager Manager (SPM) support.
  • Using native encryption for the Encrypt module, min version iOS 10.

v1.0.2 - January 13, 2021

  • Small improvements

v1.0.1 - December 2, 2020

  • Fixed crash associated with deviceId failing to persist to the keychain.
    • Fatal Exception: NSInvalidArgumentException

v1.0.0 - September 18, 2020

  • Support for iOS 14.
  • Security improvements.

v0.3.4 - June 15, 2020

  • Fixed crash when retrying events.
    • Fatal Exception:NSInvalidArgumentException

v0.3.3 - May 12, 2020

  • Queueing and retrying events when there is no internet connection or server errors.
  • Collecting new device properties (Emulator and Jailbroken).
  • More events to track customer activity ( example: trackSearch, trackAddToWishList, … ).
  • We had to bump the version from 0.3.1 to 0.3.3 due to some issues during the release process.

v0.3.1 - December 6, 2019

  • Documentation improvements for CocoaPods.

v0.3.0 - October 21, 2019

  • Added altitude tracking.
  • SDK is now modularised into “Core” and “Encrypt” components.
    • RavelinCore.framework - which is used for deviceId, fingerprinting and tracking activity.
    • RavelinEncrypt.framework - for card details encryption.
    • The modules are independent.

v0.2.4 - May 7, 2019

  • Updates to encryption.
  • Minor refactoring.