en un clic
places-android
// Guide for integrating the Places SDK for Android into an application. Use when users ask to add Places, autocomplete, place details, or search for places.
// Guide for integrating the Places SDK for Android into an application. Use when users ask to add Places, autocomplete, place details, or search for places.
| name | places-android |
| description | Guide for integrating the Places SDK for Android into an application. Use when users ask to add Places, autocomplete, place details, or search for places. |
You are an expert Android developer specializing in modern Android architecture. Before generating any code, ask the user the following questions to tailor the solution:
PlaceDetailsCompactFragment) or a full-page details viewer (PlaceDetailsFragment)?DISPLAY_NAME, FORMATTED_ADDRESS, PHOTO_METADATAS)? Limiting fields saves costs!Add the necessary dependencies to your module-level build.gradle.kts file. It is recommended to use the Versions Catalog if available:
[versions]
places = "5.1.1" # x-release-please-version
[libraries]
places = { group = "com.google.android.libraries.places", name = "places", version.ref = "places" }
Then in build.gradle.kts:
dependencies {
implementation(libs.places)
}
Use the Secrets Gradle Plugin for Android to inject the API key securely into your project (e.g., via BuildConfig), so you can access it programmatically during initialization.
Ensure you have the plugin applied in your app-level build.gradle.kts:
plugins {
alias(libs.plugins.secrets.gradle.plugin)
}
secrets {
propertiesFileName = "secrets.properties"
defaultPropertiesFileName = "local.defaults.properties"
}
Add your API Key to secrets.properties:
PLACES_API_KEY=YOUR_API_KEY
In your Application or Activity (before accessing any Places APIs, usually inside onCreate), initialize the Places SDK.
import com.google.android.libraries.places.api.Places
class DemoApplication : Application() {
override fun onCreate() {
super.onCreate()
val apiKey = BuildConfig.PLACES_API_KEY
if (apiKey.isNotEmpty()) {
Places.initializeWithNewPlacesApiEnabled(applicationContext, apiKey)
}
}
}
import com.google.android.libraries.places.api.Places;
public class DemoApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
String apiKey = BuildConfig.PLACES_API_KEY;
if (!apiKey.isEmpty()) {
Places.initializeWithNewPlacesApiEnabled(getApplicationContext(), apiKey);
}
}
}
Prefer Places UI Kit: For displaying place details (photos, reviews, addresses), prefer using the Places UI Kit over manual programmatic retrieval. It provides pre-built, beautifully designed, and automatically maintained UI components!
Null Safety & Validation: Handle nulls defensively for optional parameters (e.g. Place fields).
Scoped Fields: Always specify only parameters that are needed (e.g. Place.Field.ID, Place.Field.DISPLAY_NAME) to avoid over-billing.
Coroutine Extensions: Use Kotlin Coroutines extensions (places-ktx if available) to make code cleaner.
Location Permission: Location permissions are optional but helpful. ACCESS_COARSE_LOCATION is sufficient for biasing prediction calls (like searching search results) to general cities. ACCESS_FINE_LOCATION is necessary only for exact current position tracking. Declare them in your AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
The Places UI Kit (PlaceDetailsCompactFragment and PlaceDetailsFragment) are View-based. To use them in Jetpack Compose, use AndroidView to host a FragmentContainerView.
LocalActivity.current as FragmentActivity to access the support FragmentManager. Avoid casting LocalContext.current directly to Activity.AndroidView update block, always wrap calls (like .loadWithPlaceId()) in view.post { ... } to ensure updates run after the layout is inflated and bindings are stable.@Composable
fun PlaceDetailsCompactView(
placeId: String,
onDismiss: () -> Unit
) {
val fragmentContainerId = remember { View.generateViewId() }
val fragmentManager = (LocalActivity.current as FragmentActivity).supportFragmentManager
val fragment = remember {
PlaceDetailsCompactFragment.newInstance(
PlaceDetailsCompactFragment.ALL_CONTENT,
Orientation.VERTICAL
)
}
Box(modifier = Modifier.fillMaxWidth()) {
AndroidView(
modifier = Modifier.fillMaxWidth(),
factory = { context ->
FragmentContainerView(context).apply {
id = fragmentContainerId
if (fragmentManager.findFragmentById(fragmentContainerId) == null) {
fragmentManager.beginTransaction()
.add(fragmentContainerId, fragment)
.commit()
}
}
},
update = { view ->
// Ensures updates run after view hierarchy is ready
view.post {
fragment.loadWithPlaceId(placeId)
}
}
)
}
}
When hosting UI Kit fragments inside navigation drawers or overlays, follow these architectural bounds to avoid viewport clipping snags:
enableEdgeToEdge() and your container loses standard Scaffold body padding context, manually append Modifier.statusBarsPadding() to avoid overlapping with system status bar text:
Column(modifier = modifier.statusBarsPadding()) {
// Beautiful search results sit safely under the status bar
}
enum class DetailsUiType { COMPACT, FULL }
Track currentUiType at the Activity level and pass it to a single shared BottomSheetScaffold. Users can swipe to dismiss natively without custom button overrides!To implement autocomplete in Compose, use ActivityResultContracts.StartActivityForResult with an Intent from Autocomplete.IntentBuilder. This is the recommended way to use the pre-built widget, as it handles session tokens and debouncing automatically.
@Composable
fun AutocompleteSearchButton() {
val context = LocalContext.current
val fields = listOf(Place.Field.ID, Place.Field.DISPLAY_NAME, Place.Field.FORMATTED_ADDRESS)
val intent = Autocomplete.IntentBuilder(AutocompleteActivityMode.OVERLAY, fields)
.build(context)
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val place = Autocomplete.getPlaceFromIntent(result.data!!)
Log.d("Autocomplete", "Place selected: ${place.name}")
}
}
Button(onClick = { launcher.launch(intent) }) {
Text("Search Places")
}
}
build.gradle.kts.build.gradle.kts.Application).