> For the complete documentation index, see [llms.txt](https://docs.talsec.app/freerasp/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.talsec.app/freerasp/freerasp/integration/kotlin-multiplatform.md).

# Kotlin Multiplatform

{% hint style="success" %}
💡 **Example**: <https://github.com/talsec/Free-RASP-KMP/tree/main/example>
{% endhint %}

## 👀 Understanding the Project Layout

The following structure outlines the critical directories and files you will interact with during the integration. The project is divided into the **shared module** (logic) and **platform-specific modules** (configuration).

Pay attention to the highlighted files, as these are the exact locations where you will apply changes in the upcoming steps.

```
[YourProjectName]/
├───build.gradle.kts                 
├───settings.gradle.kts              <-- Step 1: Add Dependency Repositories
├───gradle.properties            
├───gradle/
│   └───libs.versions.toml       
├───composeApp/      
│   ├───build.gradle.kts             <-- Step 1: Add Dependencies & Obfuscation
│   └───src/
│       ├───commonMain/          
│       │   └───kotlin/              <-- Step 3: Create SecurityManager.kt
│       ├───androidMain/         
│       │   ├───kotlin/
│       │   └───AndroidManifest.xml  <-- Step 2: Add Android Permissions
│       └───iosMain/             
│           └───kotlin/
└───iosApp/                  
    ├───iosApp.xcodeproj/            <-- Step 2: Link Frameworks in Xcode
    ├───iosApp/                  
    │   ├───ContentView.swift    
    │   └───iOSApp.swift         
    ├───TalsecBridge.xcframework/    <-- Step 2: Native iOS dependency
    └───TalsecRuntime.xcframework/   <-- Step 2: Native iOS dependency
```

## 📝 Prerequisites

The freeRASP has the following prerequisites that must be met before starting:

* Kotlin version: **2.2.0**
* Minimum Android Target SDK: **API Level 23**
* Minimum iOS Deployment Target: **13.0**

## 🚀 Integration Steps

{% stepper %}
{% step %}

### 📦 Dependency Setup

To enable the SDK, you must configure your project to access the required repositories and native binaries across all target platforms.

1. Update the `settings.gradle.kts` file to include the necessary URLs within the `dependencyResolutionManagement` block.

{% code fullWidth="true" %}

```kts
// File: settings.gradle.kts

dependencyResolutionManagement {
        ...
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
        maven { url = uri("https://europe-west3-maven.pkg.dev/talsec-artifact-repository/freerasp") }
        ...
}
```

{% endcode %}

2. Ensure that the XCFramework dependencies are correctly linked and available to the iOS target of your Kotlin Multiplatform project.

* Navigate to the Assets section of GitHub Releases and download the `Frameworks.zip` archive. This package contains the required binaries:

  * `TalsecRuntime.xcframework`
  * `TalsecBridge.xcframework`

  Make sure to download the release version matching your KMP library version.&#x20;

<p align="center"><a href="https://github.com/talsec/Free-RASP-KMP/releases/" class="button primary">👉 Click here to access the frameworks in the releases 👈</a></p>

* Once downloaded, unzip (extract) the archive.

{% hint style="info" %}
For better project organization, we suggest creating a dedicated `Frameworks` folder within your `iosApp` directory (at the same level as `iosApp.xcodeproj`) to store these files.

*Expected structure:*

```
📂 iosApp
 ├── 📘 iosApp.xcodeproj
 ├── 📂 Frameworks         <-- Place files here
 │    ├── 📦 TalsecRuntime.xcframework
 │    └── 📦 TalsecBridge.xcframework
 └── ...
```

{% endhint %}

* Navigate to the `iosApp` directory via terminal and launch the project in Xcode using the following commands:

{% code fullWidth="true" %}

```bash
cd iosApp
open iosApp.xcodeproj
```

{% endcode %}

* In Xcode, navigate to the Project Navigator (left sidebar) and select your project root.

  * Select your application Target (usually named `iosApp`).
  * Scroll down to the **Frameworks, Libraries, and Embedded Content** section and click the **+** button at the bottom of the list.

  <figure><img src="/files/hCRb0i9CdARDrH8Yfr3e" alt=""><figcaption></figcaption></figure>

  * In the dialog window, click the **Add Other...** button at the bottom left, then select **Add Files...** from the pop-up menu to browse your local storage.

  <figure><img src="/files/2ZwBA1rk7bUCoVcHfuE3" alt=""><figcaption></figcaption></figure>

  * Locate and select both `TalsecRuntime.xcframework` and `TalsecBridge.xcframework`.

  <figure><img src="/files/cCF10hiJI9Qisvr7C6qB" alt=""><figcaption></figcaption></figure>
* Once added, ensure that the Embed option for both frameworks is set to **Embed & Sign**.

<figure><img src="/files/a3IsgPGsSogPKRls0tY6" alt=""><figcaption></figcaption></figure>

3. Declare the dependencies in the `build.gradle.kts` file of your `:composeApp` or `:shared` module (typically inside the `commonMain` source set):

```kts
// File: build.gradle.kts (usually inside :composeApp or :shared)
kotlin {
    ...
    sourceSets {
        ...
        commonMain.dependencies {
            ...
            implementation("com.aheaditec.talsec.security:freeRASP_KMP:1.1.0")
            ...
        }
        ...
    }
}
```

{% endstep %}

{% step %}

### 🔐 Add Permissions to AndroidManifest.xml

Some checks require additional permissions in order to work properly. Add the following permissions to your `AndroidManifest.xml` file inside the `<manifest>` root tag. If your app already has these permissions, you don't need to add them again.

{% hint style="info" %}
[Some permissions also require runtime request. ](https://developer.android.com/training/permissions/requesting)
{% endhint %}

**Screenshot and Screen Recording Detection**

To enable detection for screenshots and screen recordings, include these required permissions:

```xml
<uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
<uses-permission android:name="android.permission.DETECT_SCREEN_RECORDING" />
```

{% hint style="warning" %}
**Support Limitations**

* Screenshot Detection is supported on Android 14 (API level 34) and higher.
* Screen Recording Detection is supported on Android 15 (API level 35) and higher.
* Application of **FLAG\_SECURE** on Android Window or calling `FreeraspKMP.lockScreenCapture(true)` disables this callback.
  {% endhint %}

**Location Spoofing Detection**

To enable detection for location spoofing, include these required permissions:

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

**Unsecure WiFi Detection**

To enable detection for unsecure WiFi, include these required permissions:

```xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

<details>

<summary><strong>Quick Copy</strong></summary>

```xml
<uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
<uses-permission android:name="android.permission.DETECT_SCREEN_RECORDING" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
```

</details>
{% endstep %}

{% step %}

### ⚙️ Application Configuration Setup

To ensure freeRASP functions correctly in a Kotlin Multiplatform environment, you need to provide the necessary configuration within the shared module. All required values must be filled in for the plugin to operate properly.

**Create a Security Manager**

It is recommended to encapsulate the configuration and initialization logic into a separate singleton object (e.g. `SecurityManager`). This keeps your UI code clean and makes the security logic reusable.

Create a new file in your common source set and define the configuration:

```kts
// File: composeApp/src/commonMain/kotlin/.../SecurityManager.kt

object SecurityManager {

    private val config = freeraspConfig(
        watcherMail = "your_email_address@example.com", // for Security Reports, Talsec Portal, Updates
        androidConfig = AndroidConfig(
            packageName = "your.package.name",
            certificateHashes = listOf("mVr/qQLO8DKTwqlL+B1qigl9NoBnbiUs8b4c2Ewcz0k=")
        ),
        iosConfig = IOSConfig(
            bundleIds = listOf("your.bundle.id"),
            teamId = "YOUR_TEAM_ID"
        ),
        isProd = true,
        killOnBypass = true
    )
    
    // Initialization logic will be added in the next step
    suspend fun start(scope: CoroutineScope) {
        // ...
    }

}
```

{% hint style="info" %}
**Configuration Parameters**

* **`isProd`** - a boolean flag that determines whether the freeRASP integration is in the Dev or Release version. If you want to learn more about `isProd`, visit this [wiki section](/freerasp/freerasp/wiki/isprod-flag.md).
* **`killOnBypass`** - a boolean flag that enables the freeRASP in-SDK reaction to kill the application if it detects any unwanted manipulation with the callback mechanisms.
* **`watcherMail`** - By providing your watcherMail, you consent to receive security reports, product updates, and other essential communications from Talsec. [Learn more](/freerasp/freerasp/wiki/role-of-watchermail.md) about the role of `watcherMail`.
  {% endhint %}
  {% endstep %}

{% step %}

### 🧠 Handle Detected Threats

Once the configuration is ready, you need to start the monitoring service and listen for incoming threats.

**Implement Monitoring Logic**

Update your `SecurityManager` to start the freeRASP engine and handle the `threatEvents` flow.

```kts
// File: composeApp/src/commonMain/kotlin/.../SecurityManager.kt

suspend fun start(scope: CoroutineScope){
     FreeraspKMP.threatEvents.onEach { event ->
          when (event) {
            is FreeRaspEvent.AdbEnabled -> TODO()
            is FreeRaspEvent.AppIntegrity -> TODO()
            is FreeRaspEvent.Debug -> TODO()
            is FreeRaspEvent.DevMode -> TODO()
            is FreeRaspEvent.DeviceBinding -> TODO()
            is FreeRaspEvent.DeviceID -> TODO()
            is FreeRaspEvent.Malware -> TODO()
            is FreeRaspEvent.MultiInstance -> TODO()
            is FreeRaspEvent.ObfuscationIssues -> TODO()
            is FreeRaspEvent.Passcode -> TODO()
            is FreeRaspEvent.PrivilegedAccess -> TODO()
            is FreeRaspEvent.ScreenRecording -> TODO()
            is FreeRaspEvent.Screenshot -> TODO()
            is FreeRaspEvent.SecureHardwareNotAvailable -> TODO()
            is FreeRaspEvent.Simulator -> TODO()
            is FreeRaspEvent.SystemVPN -> TODO()
            is FreeRaspEvent.UnofficialStore -> TODO()
            is FreeRaspEvent.Hooks -> TODO()
            is FreeRaspEvent.LocationSpoofing -> TODO()
            is FreeRaspEvent.TimeSpoofing -> TODO()
            is FreeRaspEvent.UnsecureWifi -> TODO()
            }
          }.flowOn(Dispatchers.IO)
              .launchIn(scope)
          
    try {
      FreeraspKMP.start(config)
      
      // Optional: Configure additional protections
      FreeraspKMP.blockScreenCapture(true)
    } catch (e: Exception) {
        println("Error starting freeRASP: ${e.message}")    
    }
}
```

**Implement Execution State Monitoring**

In addition to threat events, freeRASP provides a dedicated flow for monitoring the SDK execution lifecycle. Subscribe to `raspExecutionStateEvents` to know when all security checks have completed.

```kts
FreeraspKMP.raspExecutionStateEvents.onEach { event ->
    when(event) {
        is RaspExecutionStateEvent.AllChecksFinished -> TODO()
    }
}.launchIn(scope)
```

**Initialize in Entry Point**

Finally, call the `start` method from your main UI entry point (e.g., `App.kt`) using a `LaunchedEffect`. This ensures monitoring begins as soon as the app launches.

```kts
// File: composeApp/src/commonMain/kotlin/.../App.kt

@Composable
fun App() {
    MaterialTheme {
    
        // Start security monitoring when the App composable enters the composition
        LaunchedEffect(Unit) {
            SecurityManager.start(this)
        }
        
        // ... Rest of your UI content
    }
}
```

{% endstep %}
{% endstepper %}

## 🌁 How to Enable Source Code Obfuscation

Code obfuscation (minification) is a critical security step that reduces the size of the compiled code and renames classes and variables to make reverse engineering significantly more difficult.

To enable obfuscation for the Android target, update the `build.gradle.kts` file in your shared module (usually `:composeApp` or `:androidApp`):

```kts
// File: composeApp/build.gradle.kts

android {
    ...
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"),
             "proguard-rules.pro")
        }
    }
}
```

{% hint style="info" %}
**Important Notes**

* **Reflection** - Some other modules in your project may rely on reflection. If the app crashes after enabling obfuscation, you may need to add specific keep rules to your `proguard-rules.pro` file.
* **Obfuscation Callback** - If there is an issue with the obfuscation configuration regarding freeRASP, the plugin will notify you via the `obfuscationIssues` callback.
  {% endhint %}

👉 Read more about the importance of obfuscation in the [wiki](/freerasp/freerasp/wiki/source-code-obfuscation.md). 👈

***

## 🆔 (Optionally) Set External ID

The `externalId` allows you to send a custom identifier (such as a User ID) to the [Talsec Portal](https://my.talsec.app/). This identifier will be visible in the Dashboard, enabling you to correlate security incidents with specific users in your system.

```kts
val yourCustomData = "user_123_456"
scope.launch {
    try {
        FreeraspKMP.storeExternalId(yourCustomData)
    } catch (e: FreeraspKMPException) {
        println("Failed to set External ID: ${e.message}")
    }
}

//To remove a previously stored identifier:
scope.launch {
    FreeraspKMP.removeExternalId()
}
```

{% hint style="info" %}
**Requirements**

* **Allowed characters**: Only alphanumeric characters (a-z, A-Z, 0-9) and the following special characters: +, \_, -, /, :, =.
* If the ID contains any other characters, a `FreeraspKMPException` will be thrown with an error message and the value will not be stored.
  {% endhint %}

***

## ☢️ Optional Module: freeMalwareDetection

**freeMalwareDetection** is a powerful feature designed to enhance the security of your Android application. It quickly and efficiently scans for malicious or suspicious applications (e.g., Android malware) based on various **blacklists** and **security policies**.

This feature helps to detect apps with **suspicious package names**, **hashes**, or potentially dangerous **permissions**.

{% hint style="info" %}
This feature is available only for the **Android** platform.
{% endhint %}

To learn more about this feature and its integration, please refer to the official documentation.

👉 [Go to freeMalwareDetection Documentation](https://docs.talsec.app/freemalwaredetection) 👈

***

## 🖥️ Check Talsec Portal

Check out [Data Visualisation Portal](/freerasp/freerasp/data-visualisation-portal.md) and register using your [watcherMail](/freerasp/freerasp/wiki/role-of-watchermail.md) to see your data. If you integrated the SDK successfully, the application will be present **after a few hours**. The visualisations will be active later due to the bucketing mechanism.

{% hint style="warning" %}
You have to use the **same email for the Portal** as you used for the **watcherMail** parameter.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.talsec.app/freerasp/freerasp/integration/kotlin-multiplatform.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
