📱Mixed platforms

If you are targeting Mobile (Android/iOS) and other platforms like Desktop, or the Browser. You will need to do some additional setup since the Mobile Geocoder/Geolocation services aren't available.

Geocoding example

This example is for a Compose Multiplatform app that targets mobile and Desktop, using Google Maps on non-mobile platforms. This is just an example, be sure to customize to your needs.

Declare Dependencies

First you will need to add the necessary dependencies:

# gradle/libs.versions.toml

[libraries]
compass-geocoder = { module = "dev.jordond.compass:geocoder", version.ref = "compass" }
compass-geocoder-mobile = { module = "dev.jordond.compass:geocoder-mobile", version.ref = "compass" }
compass-geocoder-web = { module = "dev.jordond.compass:geocoder-web", version.ref = "compass" }
compass-geocoder-web-googlemaps = { module = "dev.jordond.compass:geocoder-googlemaps", version.ref = "compass" }
compass-geocoder-web-mapbox = { module = "dev.jordond.compass:geocoder-mapbox", version.ref = "compass" }

Compass includes out of the box support for Google Maps and Mapbox. If you need support for another service you can use the geocoder-web to implement your own, or Request a Geocoder API

Add dependencies & create source-set

Now you need to edit the build.gradle.kts for your application module and add the following dependencies to the proper source-sets.

We will be creating a mobileMain and nonMobileMain source-set to minimize boilerplate. You can read about source-sets here.

// composeApp/build.gradle.kts

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation(libs.compass.geocoder)
            implementation(libs.compass.geocoder.web.googlemaps)
        }
        
        val mobileMain by creating {
            dependsOn(commonMain.get())
            androidMain.get().dependsOn(this)
            iosMain.get().dependsOn(this)
            dependencies {
                implementation(libs.compass.geocoder.mobile)
            }
        }
        
        val desktopMain by getting
        val nonMobileMain by creating {
            dependsOn(commonMain.get())
            desktopMain.dependsOn(this)
            dependencies {
                implementation(libs.compass.geocoder.web.googlemaps)
            }
        }
    }
}

Add platform expect/actual

This will produce the following folder structure, which you can then define a expect function to create a Geocoder instance:

composeApp
|
|----commonMain
|        |---kotlin/src/Platform.kt
|
|----mobileMain
|        |---kotlin/src/Platform.mobileMain.kt
|
|----nonMobileMain
|        |---kotlin/src/Platform.nonMobileMain.kt

Inside of commonMain/kotlin/src/Platform.kt you need to define an expect function that creates a Geocoder instance:

expect fun createGeocoder(): Geocoder

Then you need to create the actual functions:

// mobileMain/kotlin/src/Platform.mobileMain.kt

actual fun createGeocoder(): Geocoder {
    return Geocoder.mobile()
}

And for the nonMobile source set:

// mobileMain/kotlin/src/Platform.nonMobileMain.kt

actual fun createGeocoder(): Geocoder {
    // There are other optional parameters to customize the API request
    return Geocoder.googleMaps(apiKey = "my-google-maps-api-key")
}

The Google Maps and Mapbox integration require API keys in order to use. If you want to customize the HttpClient or the arguments passed to the API service, you can use the optional parameters. See Web API Service.

Using the Geocoder

Now that you are all setup you can use your createGeocoder() function in the commonMain source-set:

class MyRepository {
    private val geocoder: Geocoder = createGeocoder()
    
    suspend fun reverseGeocode(lat: Long, lng: Long): Location? {
        return geocoder.reverse(lat, lng).getOrNull()
    }
}

Last updated