Maps, Location & Device Features

Geocoding: Converting Between Addresses & Coordinates

16 min Lesson 8 of 12

Geocoding: Converting Between Addresses & Coordinates

Geocoding is the process of converting a human-readable address (such as "1600 Amphitheatre Parkway, Mountain View, CA") into geographic coordinates (latitude and longitude). The reverse process — converting coordinates back into a readable address — is called reverse geocoding. Both operations are essential in any location-aware Flutter application that needs to display addresses on a map, search for places, or present location data in a user-friendly format.

The geocoding package is the most widely used Dart library for both forward and reverse geocoding. It wraps the platform-native geocoding services on Android and iOS, meaning it works offline or at low cost without requiring a third-party API key for basic usage.

Note: The geocoding package uses the device's built-in geocoding engine (Google Play Services on Android, CoreLocation on iOS). For server-side or web geocoding you would use the Google Maps Geocoding REST API or a similar service instead.

Adding the Dependency

Add geocoding to your pubspec.yaml under dependencies:

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  google_maps_flutter: ^2.5.0
  geolocator: ^11.0.0
  geocoding: ^3.0.0

Run flutter pub get to fetch the package. No additional platform permissions beyond location are required because geocoding uses text-based network calls or cached device maps data.

Forward Geocoding: Address → LatLng

Forward geocoding converts a text address string into one or more Location objects, each carrying a latitude and longitude. Use GeocodingPlatform.instance.locationFromAddress() (or the convenience alias locationFromAddress() after importing the package).

Forward Geocoding Example

import 'package:geocoding/geocoding.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

Future<LatLng?> addressToLatLng(String address) async {
  try {
    // Returns a List<Location> — the first result is usually the best match
    List<Location> locations = await locationFromAddress(address);

    if (locations.isEmpty) return null;

    final best = locations.first;
    return LatLng(best.latitude, best.longitude);
  } on NoResultFoundException {
    // The geocoder found no results for this address
    debugPrint('No geocoding result for: $address');
    return null;
  } catch (e) {
    debugPrint('Geocoding error: $e');
    return null;
  }
}

// Usage inside a widget
Future<void> _searchAndMoveCamera(String query) async {
  final coords = await addressToLatLng(query);
  if (coords == null) {
    // Show a SnackBar or dialog: address not found
    return;
  }

  _mapController.animateCamera(
    CameraUpdate.newLatLngZoom(coords, 15.0),
  );

  setState(() {
    _markers = {
      Marker(
        markerId: const MarkerId('search_result'),
        position: coords,
        infoWindow: InfoWindow(title: query),
      ),
    };
  });
}
Tip: locationFromAddress() accepts partial addresses and place names (e.g. "Eiffel Tower" or "Dubai Mall"). The more specific the input, the more accurate the result. Always take locations.first as the best match when only one pin is needed.

Reverse Geocoding: LatLng → Human-Readable Address

Reverse geocoding turns a latitude/longitude pair into a list of Placemark objects. Each Placemark contains rich address fields: street name, sublocality, locality (city), administrativeArea (state/region), postalCode, and country.

Reverse Geocoding Example

import 'package:geocoding/geocoding.dart';

Future<String> latLngToAddress(double lat, double lng) async {
  try {
    List<Placemark> placemarks = await placemarkFromCoordinates(lat, lng);

    if (placemarks.isEmpty) return 'Unknown location';

    final place = placemarks.first;

    // Build a readable address from available fields
    final parts = [
      place.street,
      place.subLocality,
      place.locality,
      place.administrativeArea,
      place.country,
    ].where((p) => p != null && p.isNotEmpty).toList();

    return parts.join(', ');
  } on NoResultFoundException {
    return 'No address found';
  } catch (e) {
    debugPrint('Reverse geocoding error: $e');
    return 'Error retrieving address';
  }
}

// Usage: on map tap, reverse-geocode the tapped position
void _onMapTapped(LatLng position) async {
  setState(() => _tappedPosition = position);

  final address = await latLngToAddress(
    position.latitude,
    position.longitude,
  );

  setState(() => _tappedAddress = address);
}

Displaying Results on the Map

A complete geocoding workflow typically involves three steps: obtaining coordinates (forward) or address (reverse), updating a Marker on the map, and showing the result in the UI. Below is a minimal but complete widget that combines both directions:

  • A TextField where the user types an address — triggers forward geocoding on submit
  • A GoogleMap that moves the camera to the found coordinates and places a marker
  • A tap handler on the map that reverse-geocodes the tapped point and shows the street address in a bottom sheet or overlay
  • A loading indicator while async geocoding operations are in-flight
Warning: Both locationFromAddress() and placemarkFromCoordinates() are async and can throw NoResultFoundException (no match found) or PlatformException (network or permission error). Always wrap them in try/catch — an unhandled exception will crash the widget.

Locale-Aware Geocoding

Both functions accept an optional localeIdentifier parameter (e.g. 'ar_AE', 'en_US') that requests results in a specific language. This is useful for apps that serve multiple languages.

Locale-Aware Reverse Geocoding

// Request Arabic place names for users in the UAE
List<Placemark> placemarks = await placemarkFromCoordinates(
  25.2048,   // Dubai latitude
  55.2708,   // Dubai longitude
  localeIdentifier: 'ar_AE',
);

// The returned Placemark.locality will be "دبي" instead of "Dubai"
final cityName = placemarks.first.locality ?? '';

Key Takeaways

Geocoding bridges the gap between human language and machine coordinates. The geocoding package makes both directions simple: forward geocoding turns a text address into a LatLng you can pan the camera to, while reverse geocoding turns a raw coordinate into a presentable street address. Combining these with google_maps_flutter and geolocator gives you a complete location stack: detect the device position, show it on a map, let users search by address, and display friendly place names anywhere in your UI.

Key Takeaway: Use locationFromAddress() for forward geocoding (address → coordinates) and placemarkFromCoordinates() for reverse geocoding (coordinates → address). Always handle NoResultFoundException gracefully, and use the optional localeIdentifier for multilingual apps.