Skip to main content
PlatformArchitectures
macOSarm64, x86_64
Linuxx86_64, aarch64 (glibc)
Windowsx86_64
Androidaarch64, armv7 (requires building from source)
The Kotlin bindings live in iroh-ffi, generated by uniffi-rs from the same Rust core as the Swift and Python bindings. Published to Maven Central as computer.iroh:iroh.

Prerequisites

  • A JDK (21 or newer) and java on your PATH
  • Gradle

Install

In your build.gradle.kts:
repositories {
    mavenCentral()
}

dependencies {
    implementation("computer.iroh:iroh:1.0.0-rc.1")
}
The published artifact is single-platform. It does not yet ship a multiplatform build, so it won’t cover Android or arbitrary host triples out of the box. If you need a target the artifact doesn’t cover, build the bindings from source.

Hello, iroh

import computer.iroh.*
import kotlinx.coroutines.runBlocking

private val ALPN = "hello-iroh/0".toByteArray()

fun main() = runBlocking {
    val ep = Endpoint.bind(
        EndpointOptions(preset = presetN0(), alpns = listOf(ALPN)),
    )
    println("endpoint id: ${ep.id()}")
    ep.shutdown()
}
Drop this in any module that depends on the generated computer.iroh package. The API mirrors the Swift and Python bindings: same Endpoint.bind, same EndpointOptions, same presets.

Next steps

Connect two endpoints

Walkthrough of endpoints, tickets, and ALPNs. Code samples are Rust but APIs map 1:1 to Kotlin.

hello-iroh-ffi example app

A full working Jetpack Compose demo: two devices stream live positions to each other at 60 Hz and show whether the connection is direct or relayed.

Kotlin API reference

Generated Dokka reference for the computer.iroh package.

iroh-ffi on GitHub

Source, Kotlin tests, and issue tracker.

Foreground and backgrounding

On Android, the OS aggressively suspends background processes: sockets get torn down, threads stop scheduling, and an iroh endpoint that was happily accepting connections a moment ago goes silent. Treat each foreground/background transition as a lifecycle event for your endpoint:
  • Going to background: call ep.shutdown() to close cleanly and release sockets. Persist the endpoint’s secret key (ep.secretKey().toBytes()) somewhere durable (e.g. EncryptedSharedPreferences) so the next bind keeps the same endpoint id.
  • Returning to foreground: re-bind with EndpointOptions(secretKey = persistedBytes, preset = presetN0(), ...). Discovery republishes the new direct addresses automatically.
  • Staying live while backgrounded: run iroh inside an Android foreground service (with the appropriate FOREGROUND_SERVICE_* permission for your use case). Without one, Android will eventually kill the network sockets regardless of how the coroutine scope is structured.
For desktop JVM apps these constraints don’t apply. Keep the endpoint bound for the lifetime of the process and call shutdown() on exit.

Building from source

For Android, an unsupported host, or to hack on the bindings themselves, clone iroh-ffi and generate the sources locally:
git clone https://github.com/n0-computer/iroh-ffi
cd iroh-ffi
cargo install cargo-make
cargo make bindgen-kotlin     # generates Kotlin sources + the cdylib
cargo make test-kotlin        # bindgen + ./gradlew test (optional)
The Kotlin sources land in kotlin/lib/src/main/kotlin/ and the native library is staged into kotlin/lib/src/main/resources/. Point your project at that lib module via settings.gradle.kts to consume it instead of the Maven artifact. For Android, install the Android NDK via Android Studio and point Cargo at it via .cargo/config.toml. The relevant ABI targets are aarch64-linux-android, armv7-linux-androideabi, i686-linux-android, and x86_64-linux-android. The full NDK config template is in the iroh-ffi Kotlin README.