Google Places Autocomplete

Flutter 3.24+ pub package License: MIT

A powerful, UI-agnostic Flutter package for Google Places API integration. Get autocomplete predictions with distance from user, detailed place information, and full control over your UI.

✨ Features

  • 🎨 UI-Agnostic - Bring your own UI, we handle the data
  • πŸ“ Distance Support - Show distance from user to each prediction
  • πŸ” Platform-Native API Keys - Read from AndroidManifest/Info.plist (no hardcoded keys!)
  • 🌍 Cross-Platform - Android, iOS
  • ⚑ Performance Optimized - Built-in debouncing
  • πŸ”§ Highly Configurable - Filter by country, place type, language

πŸš€ Quick Start

1. Platform Setup

Android - Add to AndroidManifest.xml:

<application>
    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="YOUR_API_KEY" />
</application>

iOS - Add to Info.plist:

<key>GOOGLE_PLACES_API_KEY</key>
<string>YOUR_API_KEY</string>

2. Install

dependencies:
  google_places_autocomplete: ^2.0.1

3. Use

import 'package:google_places_autocomplete/google_places_autocomplete.dart';

final places = GooglePlacesAutocomplete(  
  // Optional - enables distance display in predictions
  originLat: userLatitude,
  originLng: userLongitude,
  
  predictionsListener: (predictions) {
    for (final p in predictions) {
      print('${p.title} - ${p.distanceMeters}m away');
    }
  },
  loadingListener: (isLoading) => print('Loading: $isLoading'),
);

await places.initialize(
   // Optional - reads from platform config if not provided
  // apiKey: 'YOUR_KEY',
);  // Important: await this!
places.getPredictions('coffee shop');

πŸ“– API Reference

Constructor Parameters

Parameter Type Required Description
predictionsListener Function(List<Prediction>) βœ… Callback for predictions
loadingListener Function(bool) ❌ Loading state callback
originLat double? ❌ User latitude for distance calculation
originLng double? ❌ User longitude for distance calculation
debounceTime int ❌ Debounce in ms (default: 300, min: 200)
countries List<String>? ❌ Country codes e.g. ['us', 'ca']
primaryTypes List<String>? ❌ Place types e.g. ['restaurant']
language String? ❌ Language code e.g. 'en'

Methods

// Initialize (required, async)
await places.initialize(
  // Optional - reads from platform config if not provided
  // apiKey: 'YOUR_KEY',
);

// Get predictions
places.getPredictions('search query');

// Get place details
final details = await places.getPredictionDetail('place_id');

// Update user location (for distance)
places.setOrigin(latitude: 37.7749, longitude: -122.4194);

// Clear origin (disable distance)
places.clearOrigin();

Prediction Model

class Prediction {
  final String? placeId;       // Use with getPredictionDetail()
  final String? title;         // Main text
  final String? description;   // Secondary text
  final int? distanceMeters;   // Distance from origin (if set)
  final List<String>? types;   // Place types
}

PlaceDetails Model

class PlaceDetails {
  final String? placeId;
  final String? name;
  final String? formattedAddress;
  final Location? location;              // .lat, .lng
  final List<AddressComponent>? addressComponents;  // Full list
  
  // Parsed from addressComponents:
  final String? city;
  final String? state;
  final String? country;
  final String? zipCode;
  final String? streetAddress;
  final String? streetNumber;
  
  // Contact
  final String? nationalPhoneNumber;
  final String? internationalPhoneNumber;
  final String? googleMapsUri;
  final String? websiteUri;
  
  // Business info
  final double? rating;
  final int? userRatingsTotal;
  final String? businessStatus;  // OPERATIONAL, CLOSED_TEMPORARILY, etc.
  final List<String>? types;
  
  // Additional
  final int? utcOffset;
  final PlusCode? plusCode;      // .globalCode, .compoundCode
  final Viewport? viewport;      // .northeast, .southwest
}

AddressComponent Model

class AddressComponent {
  final String longText;       // Full name: "California"
  final String? shortText;     // Abbreviated: "CA"
  final List<String> types;    // e.g., ["administrative_area_level_1"]
}

πŸ’‘ Examples

Display Distance Badge

ListTile(
  title: Text(prediction.title ?? ''),
  subtitle: Text(prediction.description ?? ''),
  trailing: prediction.distanceMeters != null
      ? Text(_formatDistance(prediction.distanceMeters!))
      : null,
);

String _formatDistance(int meters) {
  if (meters >= 1000) {
    return '${(meters / 1000).toStringAsFixed(1)} km';
  }
  return '$meters m';
}

Filter by Country

GooglePlacesAutocomplete(
  countries: ['pk', 'ae'],  // Pakistan & UAE only
  predictionsListener: (p) => setState(() => predictions = p),
);

Get Coordinates from Selection

onTap: () async {
  final details = await places.getPredictionDetail(prediction.placeId!);
  final lat = details?.location?.lat;
  final lng = details?.location?.lng;
  // Use coordinates...
}

πŸ“¦ Android Release Configuration

If you encounter errors in release builds (like ServiceConfigurationError or missing classes or the predictions did not fetch in production), add these rules to your android/app/proguard-rules.pro:

# Keep custom plugin classes
-keep class com.cuboid.google_places_autocomplete.** { *; }

# Google Places SDK - Required to prevent R8 from stripping reflection-based classes
# This fixes: ServiceConfigurationError: Provider com.google.android.libraries.places.internal.u1 could not be instantiated
-keep class com.google.android.libraries.places.** { *; }
-keepclassmembers class com.google.android.libraries.places.** { *; }
-dontwarn com.google.android.libraries.places.**

⚠️ Breaking Changes

v2.0.0

  • Minimum Android SDK: 28 (was 23)
  • Minimum iOS: 17.0
  • Java 17 required for Android builds

v0.1.1

Change Before After
Listener names predictionsListner predictionsListener
loadingListner loadingListener
Initialize initialize() (sync) await initialize() (async)
API key Required Optional (platform fallback)

πŸ”§ Troubleshooting

Issue Solution
No predictions Ensure Places API is enabled in Google Cloud Console
No distance shown Provide originLat and originLng
API key not found Check platform manifest/plist configuration

πŸ“„ License

MIT License - see LICENSE for details.