Skip to content

Async

Swift async methods are exported as functions that return CompletableFuture<T> on the JVM side. This lets you use them with Kotlin coroutines via kotlinx-coroutines-jdk8.

import Swift4j
import Dispatch
@jvm
struct DataFetcher {
func fetchData() async -> String {
try? await Task.sleep(nanoseconds: 1_000_000_000)
return "Data from Swift"
}
func process() async throws {
for i in 0..<5 {
print("Step \(i)")
try await Task.sleep(nanoseconds: 500_000_000)
}
}
}

Add kotlinx-coroutines-jdk8 to your Kotlin project, then use .await() to suspend until the future completes:

import kotlinx.coroutines.future.await
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
System.loadLibrary("MyLibrary")
val fetcher = DataFetcher()
val data = fetcher.fetchData().await()
println(data) // Data from Swift
fetcher.process().await()
}

Without coroutines, use the CompletableFuture API directly:

DataFetcher fetcher = new DataFetcher();
fetcher.fetchData()
.thenAccept(data -> System.out.println(data))
.join();

async throws Swift methods propagate exceptions through the CompletableFuture. Catch them with CompletableFuture.exceptionally() or handle them at the coroutine call site:

try {
fetcher.process().await()
} catch (e: Exception) {
println("Failed: ${e.message}")
}

Swift async tasks run on Swift’s cooperative thread pool. The CompletableFuture is completed on whatever thread Swift’s runtime chooses. On Android, do not update UI directly inside the future callback — post the result to the main thread using Handler or a StateFlow.