There is no cross-platform abstraction for CoreLocation. Nothing to point expect/actual at. Kotlin/Native's cinterop tool closes the gap by generating Kotlin bindings straight from a C or Objective-C header, so iosMain code calls the framework directly instead of routing through a hand-written Swift shim.
#The old way
Getting the device's location meant a Swift LocationManager class wrapping CLLocationManager, then exposing a narrow closure-based API back across the bridge so Kotlin could reach it. That translation layer existed for exactly one reason: Kotlin had no way to see CoreLocation itself.
#The new way
Kotlin/Native ships pre-generated bindings for Apple's own frameworks under the platform.* package. No .def file required:
import platform.CoreLocation.CLLocationManager
import platform.CoreLocation.CLLocationManagerDelegateProtocol
import platform.CoreLocation.kCLLocationAccuracyBest
import platform.darwin.NSObject
class IosLocationProvider : NSObject(), CLLocationManagerDelegateProtocol {
private val manager = CLLocationManager().apply {
desiredAccuracy = kCLLocationAccuracyBest
delegate = this@IosLocationProvider
}
fun start() {
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
}
For a vendored or third-party C library, you write the .def file yourself and register it per target:
kotlin {
iosArm64 {
compilations.getByName("main") {
cinterops {
create("mylib") {
defFile(project.file("src/nativeInterop/cinterop/mylib.def"))
}
}
}
}
}
The .def file lists headers = mylib.h plus any compilerOpts/linkerOpts. That is the whole file. cinterop reads the header at build time and generates a full Kotlin API from it.
#Why it matters
iosMaincode can call CoreLocation, CoreBluetooth, or any Apple framework with real Kotlin types, not string-typed reflection- Custom C libraries become first-class Kotlin dependencies instead of requiring a Swift wrapper module
- The generated bindings are regenerated from the header on every build, so they can't silently drift from the actual library API
#Gotcha
The class has to extend NSObject. Implementing the generated *Protocol interface is not enough — a plain Kotlin class that implements CLLocationManagerDelegateProtocol without subclassing NSObject fails to compile. The Objective-C runtime expects delegate callbacks to land on an NSObject-derived instance, and cinterop enforces that at the type level rather than at runtime.