Google Map

Set up a map

Let's take our new key and add it to the project.

First, add the name of the key to a secrets.properties file in the root directory of your project. It should contain the following (replace YOUR_KEY_NAME_GOES_HERE with your API key)

# DO NOT CHECK THIS FILE IN!
MAPS_API_KEY=YOUR_KEY_NAME_GOES_HERE

This file should NEVER be checked into git, as the key name is a secret. (Because this file isn't checked in, and I'm using git to generate the code display on the right, I'll show its contents below). Be sure to add secrets.properties to the top-level .gitignore file:

show in full file .gitignore
// ...
.cxx
local.properties
secrets.properties

To access the key, we'll use the "secrets" plugin, which reads secrets.properties and makes the properties available in other files.

To add the secrets plugin to your build, declare the version of the secrets plugin and the plugin artifact in your version catalog

show in full file gradle/libs.versions.toml
[versions]
// ...
activityCompose = "1.9.3"
composeBom = "2024.12.01"
secrets = "2.0.1"

maps-compose = "6.2.1"
// ...
[libraries]
// ...
[plugins]
// ...
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
//
secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" }

Declare that you want to use the plugin in your root build.gradle.kts. We use apply false so it doesn't do anything other than set up the plugin on the classpath for all modules that will use it.

show in full file build.gradle.kts
// ...
plugins {
    // ...
    alias(libs.plugins.kotlin.android) apply false
    alias(libs.plugins.kotlin.compose) apply false
    alias(libs.plugins.secrets) apply false
}

Apply the plugin in your app/build.gradle.kts and configure it to use our secrets.properties file

show in full file app/build.gradle.kts
plugins {
    // ...
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
    alias(libs.plugins.secrets)
}

// ...
}

secrets {
    propertiesFileName = "secrets.properties"
}

Then we can drop the key in the Manifest for Google Maps to find at runtime.

show in full file app/src/main/AndroidManifest.xml
// ...
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    // ...
    <application
        // ...
        tools:targetApi="31">

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="${MAPS_API_KEY}" />

        <activity
            // ...
    </application>
// ...
</manifest>

So far we don't have access to the Google Maps @Composable function, so we add versions and libraries to the version catalog:

show in full file gradle/libs.versions.toml
[versions]
// ...
secrets = "2.0.1"

maps-compose = "6.2.1"

[libraries]
maps-compose = { group = "com.google.maps.android", name = "maps-compose", version.ref = "maps-compose" }
maps-compose-utils = { group = "com.google.maps.android", name = "maps-compose-utils", version.ref = "maps-compose" }

androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
// ...
[plugins]
// ...

Then add the dependencies to the app's build script.

show in full file app/build.gradle.kts
// ...
dependencies {
//
    implementation(libs.maps.compose)
    implementation(libs.maps.compose.utils)
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    // ...
}
// ...

Finally, add a Map to the UI

show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/MainActivity.kt
// ...
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        setContent {
            GoogleMapsTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
//                  Greeting(
//                      name = "Android",
//                      modifier = Modifier.padding(innerPadding)
//                  )
                    GoogleMap(
                        modifier = Modifier.padding(innerPadding).fillMaxSize(),
                    ) {
                        // no content yet
                    }
                }
            }
        }
    }
}
// ...

When we run the app, we'll see

We have a Map!


All code changes

CHANGED: .gitignore
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
secrets.properties
CHANGED: app/build.gradle.kts
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
alias(libs.plugins.secrets)
} android { namespace = "com.androidbyexample.compose.google.google.maps" compileSdk = 35 defaultConfig { applicationId = "com.androidbyexample.compose.google.google.maps" minSdk = 24 targetSdk = 35 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { jvmTarget = "11" } buildFeatures { compose = true } } dependencies {
// implementation(libs.maps.compose) implementation(libs.maps.compose.utils)
implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) }
secrets { propertiesFileName = "secrets.properties" }
CHANGED: app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">


    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.GoogleMaps"
        tools:targetApi="31">

<meta-data android:name="com.google.android.geo.API_KEY" android:value="${MAPS_API_KEY}" />
<activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name" android:theme="@style/Theme.GoogleMaps"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
CHANGED: app/src/main/java/com/androidbyexample/compose/google/google/maps/MainActivity.kt
package com.androidbyexample.compose.google.google.maps

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.androidbyexample.compose.google.google.maps.ui.theme.GoogleMapsTheme
import com.google.maps.android.compose.GoogleMap

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            GoogleMapsTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
// Greeting( // name = "Android", // modifier = Modifier.padding(innerPadding) // ) GoogleMap( modifier = Modifier.padding(innerPadding).fillMaxSize(), ) { // no content yet }
} } } } } // //@Composable //fun Greeting(name: String, modifier: Modifier = Modifier) { // Text( // text = "Hello $name!", // modifier = modifier // ) //} // //@Preview(showBackground = true) //@Composable //fun GreetingPreview() { // GoogleMapsTheme { // Greeting("Android") // } //}
CHANGED: build.gradle.kts
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.kotlin.android) apply false
    alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.secrets) apply false
}
CHANGED: gradle/libs.versions.toml
[versions]
agp = "8.7.3"
kotlin = "2.0.21"
coreKtx = "1.15.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.9.3"
composeBom = "2024.12.01"
secrets = "2.0.1"
maps-compose = "6.2.1" [libraries] maps-compose = { group = "com.google.maps.android", name = "maps-compose", version.ref = "maps-compose" } maps-compose-utils = { group = "com.google.maps.android", name = "maps-compose-utils", version.ref = "maps-compose" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } androidx-ui = { group = "androidx.compose.ui", name = "ui" } androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
// secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" }