# Android SDK

> Install the fraud detection SDK in an Android app: Gradle dependency, permissions, sending transactions in Kotlin and Java, a full example, and the changelog.

URL: https://docs.ironchip.com/en/fraude/sdk/android/

The Android SDK collects device and environment signals on every sensitive operation and sends them to the Ironchip fraud engine. Use it if your mobile app is a native Android app.

## Requirements

| Platform | Supported versions |
| -------- | ------------------ |
| Android  | 5.0.0+             |

## Installation

### Add the library to your project

First, in the `settings.gradle` file, reference the remote repository where the library is hosted:

```groovy title="settings.gradle"
dependencyResolutionManagement {
    ...

    repositories {
        maven { url 'https://jitpack.io' }
        ...
    }
}
```

Next, in the `build.gradle` file, add the SDK dependency:

### Permissions

Add the following permissions to your manifest:

```xml title="AndroidManifest.xml"
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
```

`tools:ignore` requires the `xmlns:tools="http://schemas.android.com/tools"` namespace on the `<manifest>` tag.

## Use in an app

To take full advantage of the SDK, grant the `ACCESS_FINE_LOCATION` permission. See [how to request permissions on Android](https://developer.android.com/training/permissions/requesting).

**Kotlin**

```kotlin
import com.ironchip.ironchiplbfraudandroidsdk.LBFraudSDK

// Replace APIKEY with the API key generated in the console.
val fraud = LBFraudSDK(this, "APIKEY")
// By default the SDK targets the production environment. To target a different one:
// val fraud = LBFraudSDK(this, "APIKEY", LBFraudSDK.Environment.TESTING)

val extraData = hashMapOf<String, Any>(
    "concept" to "Book august",
    "amount" to 30,
    "operation" to "booking",
)

// transactionId (required, unique): identifier you will later use to request the report
// userId (required): user identifier
// extraData (optional): extra information for analysis
fraud.sendTransaction("random_identifier_generated", "john.doe@gmail.com", extraData, {
    // Code to run when the transaction has finished.
}, { exception ->
    // Code to run if an error occurs during the transaction.
})
```

**Java**

```java
import com.ironchip.ironchiplbfraudandroidsdk.LBFraudSDK;
...

// Replace APIKEY with the API key generated in the console.
// The constructor throws LBFraudInitializationException: handle it with try/catch.
LBFraudSDK fraud = new LBFraudSDK(this, "APIKEY");
// By default the SDK targets the production environment. To target a different one:
// LBFraudSDK fraud = new LBFraudSDK(this, "APIKEY", LBFraudSDK.Environment.TESTING);

//public enum Environment {
//    PRODUCTION,
//    TESTING,
//    DEVELOPMENT
//}

Map<String, Object> extraData = new HashMap<>();
extraData.put("concept", "Book august");
extraData.put("amount", 30);
extraData.put("operation", "booking");

// transactionId (required, unique): identifier you will later use to request the report
// userId (required): user identifier
// extraData (optional): extra information for analysis
// sendTransaction accepts two callbacks: the first runs when the transaction has finished
// and the second runs if an error occurs during the process.
fraud.sendTransaction("random_identifier_generated", "john.doe@gmail.com", extraData, () -> {
    // Code to run when the transaction has finished.
}, exception -> {
    // Code to run if an error occurs during the transaction.
    // exception.printStackTrace()
});
```

Besides an `Activity`, the constructor also accepts a `Context` (since version 1.2.23), so you can use the SDK from a service. The constructor throws `LBFraudInitializationException` (a checked exception) if the context is null: in Java wrap it in `try/catch`; in Kotlin it is optional.

## Error handling

`sendTransaction` sends the transaction in the background and takes two callbacks: the first one (a `Runnable`) runs if the engine accepts the transaction, and the second one (an `ExceptionCallback`, with the `onExceptionOccurred(Exception e)` method) runs if an error occurs. Only one of them runs, on a background thread: if you update the UI from them, use `runOnUiThread`.

If the error is a network error or is returned by the server, the exception is a `TransactionException`. Its `getCode()` method returns the error code from the server response (`error_code`) or one of these constants:

| Code  | Constant                 | Meaning                                               |
| ----- | ------------------------ | ----------------------------------------------------- |
| `"0"` | `RESPONSE_PARSING_ERROR` | The server returned an error that could not be parsed |
| `"1"` | `NO_CONNECTION_ERROR`    | The server cannot be reached                          |
| `"2"` | `TIMEOUT_ERROR`          | The request timed out                                 |
| `"3"` | `NETWORK_ERROR`          | Other network error                                   |

`getHttpCode()` returns the HTTP status code of the response (`0` on network errors), and `getTraceabilityId()` returns its traceability ID (`null` if the response has none). Include it when you open a ticket with support. The format of error responses is described in [Error responses](https://docs.ironchip.com/en/fraude/referencia/errores/).

## Configure a proxy

If your app reaches the Internet through a proxy, configure it with `setProxy` before sending transactions. It takes a `java.net.Proxy` and can throw `IllegalArgumentException`.

**Kotlin**

```kotlin
import java.net.InetSocketAddress
import java.net.Proxy

fraud.setProxy(Proxy(Proxy.Type.HTTP, InetSocketAddress("proxy.example.com", 8080)))
```

**Java**

```java
import java.net.InetSocketAddress;
import java.net.Proxy;
...

fraud.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.example.com", 8080)));
```

## Example

Full example: after a successful login, the user identifier is anonymized with SHA-256 and the transaction is sent.

```java
import com.ironchip.ironchiplbfraudandroidsdk.LBFraudSDK;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

...

// Replace APIKEY with the API key generated in the console.
// The constructor throws LBFraudInitializationException: handle it with try/catch.
LBFraudSDK fraud = new LBFraudSDK(this, "APIKEY");

// Asynchronous method to log the user in
private void login(String username, String password) {
    performLogin(username, password).thenAccept(loginSuccessful -> {
        if (loginSuccessful) {
            // If the login succeeds, call sendTransaction with the required parameters
            String transactionID = generateRandomTransactionID(10); // Generate or fetch your transaction ID
            String userID = "john.doe@gmail.com"; // User identifier
            String anonymizedUserID = anonymizeUserID(userID); // Anonymized user ID

            Map<String, Object> extraData = new HashMap<>(); // Extra information for analysis
            extraData.put("amount", 30); // Use Integer.valueOf(30) if needed
            extraData.put("operation", "login");

            sendTransactionAfterLogin(transactionID, anonymizedUserID, extraData);
        } else {
            // Handle the login failure
        }
    });
}

// Asynchronous login that returns a CompletableFuture<Boolean>
private CompletableFuture<Boolean> performLogin(String username, String password) {
    return CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(2000);

            // Replace with your real login logic:
            // authenticate the user and return true on success
            return true;
        } catch (InterruptedException e) {
            return false; // On error, return false
        }
    });
}

// Send the transaction after a successful login
private void sendTransactionAfterLogin(String transactionID, String anonymizedUserID, Map<String, Object> extraData) {
    fraud.sendTransaction(transactionID, anonymizedUserID, extraData, () -> {
        // Code to run when the transaction has finished.
    }, exception -> {
        // Code to run if an error occurs during the transaction.
    });
}

// Trim, lowercase, and hash the userID
public static String anonymizeUserID(String userID) {
    String trimmedLowercaseUserID = userID.trim().toLowerCase();
    return hashString(trimmedLowercaseUserID);
}

// Compute the hash with SHA-256
public static String hashString(String input) {
    try {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hashBytes = digest.digest(input.getBytes(StandardCharsets.UTF_8));

        StringBuilder hexString = new StringBuilder();
        for (byte b : hashBytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("Error while calculating hash", e);
    }
}

private String generateRandomTransactionID(int length) {
    // Implement your own method to generate a unique transaction ID.
    final String chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890";
    Random rnd = new Random();
    return IntStream.range(0, length)
        .mapToObj(i -> String.valueOf(chars.charAt(rnd.nextInt(chars.length()))))
        .collect(Collectors.joining());
}
```

## Changelog

### 1.2.26 (2026-09-08)

**Changed**

- Updated an internal SDK library.

### 1.2.25 (2026-08-06)

**Changed**

- Updated an internal SDK library.

### 1.2.23 (2026-06-25)

**Added**

- `LBFraudSDK` also accepts a `Context` in addition to an `Activity`, so it can be used from components that are not activities, such as services.

**Changed**

- Updated an internal SDK library.

**Fixed**

- `sendTransaction` returns a `TransactionException` on network errors instead of an `IOException`. New codes: `NO_CONNECTION_ERROR`, `TIMEOUT_ERROR`, and `NETWORK_ERROR`.

### 1.2.20 (2026-03-10)

**Changed**

- Updated an internal SDK library.

### 1.2.19 (2026-03-05)

**Changed**

- The transaction JSON is now generated on a background thread.

### 1.2.18 (2026-03-05)

**Changed**

- Updated an internal SDK library.

### 1.2.17 (2026-03-02)

**Changed**

- Updated the identifiers in the device model.

### 1.2.16 (2026-02-11)

**Added**

- New identifiers in the device model.

### 1.2.15 (2026-02-11)

**Changed**

- Updated an internal SDK library.

### 1.2.14

**Changed**

- Updated an internal SDK library.

### 1.2.13 (2023-10-11)

**Added**

- Communication detection.
- SIM network type (2G, 3G, 4G, 5G).

### 1.2.12 (2023-09-12)

**Added**

- Proxy configuration method.

**Changed**

- Cipher suites are now used.

### 1.2.11 (2023-07-05)

**Changed**

- Fixed additional data that was not being sent.

### 1.2.10 (2023-06-23)

- This version is an update with no functional changes. The version number was updated to 1.2.10 to maintain the version sequence.

### 1.2.9.2 (2023-06-23)

**Changed**

- Commons library updated with additional fixes.

### 1.2.9.1 (2023-06-22)

**Changed**

- Commons library updated to apply some bug fixes.

### 1.2.9 (2023-05-18)

**Added**

- SDK version added to the transaction model.

**Changed**

- Previous error handling implemented to allow fraud service creation even if the GPS provider is unavailable.

### 1.2.8 (2023-05-12)

**Added**

- Additional error handling to prevent the transaction from failing when one of the steps that build it fails.

### 1.2.7 (2023-03-15)

**Changed**

- Transaction model modified to include SIM card information.

### 1.2.6 (2023-02-02)

**Changed**

- Transaction model modified to include the status of requested permissions.
- Transaction model modified to include whether the GPS and Wi-Fi providers are enabled.

### 1.2.5 (2023-01-13)

**Changed**

- Fixed the ProGuard configuration that caused the client application to be repackaged into the library internal folder.

### 1.2.4 (2023-01-10)

**Changed**

- Errors during the `sendTransaction` callback are now logged instead of being redirected to the exception callback.

### 1.2.3 (2022-12-09)

**Changed**

- Fixed an issue with the fingerprint ID.

### 1.2.2 (2022-11-30)

**Changed**

- Fixed a bug when the device is not connected to a Wi-Fi network.
- Fixed line breaks in the encrypted IDs.
- Improved emulation detection.

### 1.2.1 (2022-11-22)

**Changed**

- Class name refactoring.
- Log tags updated to match the refactoring.
- The Fraud constructor no longer accepts a URL host; it only allows selecting the desired environment.

### 1.2.0 (2022-10-12)

**Added**

- Kernel version added to the device properties.
- Debug logs.

**Changed**

- Fixed errors where JSON strings were sent instead of arrays.
- Improved device ID, installation ID, and fingerprint.
- GPS and signal can no longer block the process.

### 1.1.3 (2022-09-30)

**Changed**

- The library is now published on GitHub.

### 1.1.2 (2022-09-30)

**Added**

- Support for Android 5 and later.

### 1.1.0 (2022-09-22)

**Added**

- `LICENSE` file added to the project.

**Changed**

- Module name refactoring.

### 1.0.2 (2022-09-10)

**Added**

- Custom exceptions.

**Changed**

- Callbacks and exceptions excluded from obfuscation to simplify client usage.
- Model parameter names and structure changed.

### 1.0.1 (2022-09-10)

**Changed**

- Callbacks and exceptions excluded from obfuscation to simplify client usage.
- Model parameter names and structure changed.

### 1.0.0 (2022-09-10)

**Added**

- Code obfuscation.

**Changed**

- Code sections migrated to a common library.
- GPS service behavior modified.
