geocode_cache 1.0.0 copy "geocode_cache: ^1.0.0" to clipboard
geocode_cache: ^1.0.0 copied to clipboard

A Flutter package for caching geocoding and place search results locally using Hive CE storage with Haversine distance matching. Minimizes API calls by serving nearby coordinates from cache.

geocode_cache #

pub package License: MIT

A Flutter package that caches reverse geocoding and place search results locally using Hive CE. Reduces API calls by serving nearby coordinates from cache using Haversine distance matching.

Features #

  • Haversine proximity matching — coordinates within a configurable radius (default 10m) return cached results
  • Place search caching — Nominatim search results are cached per query
  • TTL support — optional time-to-live expiration for cache entries
  • Custom address formatting — override the default address format
  • FIFO eviction — automatic eviction when cache reaches max size
  • Manual cache management — clear all, clear by type, or evict stale entries
  • Zero configuration — works out of the box with sensible defaults

Installation #

Add to your pubspec.yaml:

dependencies:
  geocode_cache: ^1.0.0

Then run:

flutter pub get

The Hive type adapters are pre-generated and bundled — no build_runner step needed.

Quick Start #

import 'package:geocode_cache/geocode_cache.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialise the service (uses default options)
  await GeocodingService.instance.init();

  // Get address — automatically cached
  final address = await GeocodingService.instance
      .getAddressFromCoordinates(-8.6705, 115.2126);
  print(address); // "Jl. Raya Ubud, Ubud, Bali, Indonesia"

  // Second call with nearby coordinates → served from cache (no API call)
  final nearby = await GeocodingService.instance
      .getAddressFromCoordinates(-8.6706, 115.2127);
  print(nearby); // Same result, from cache
}

Configuration #

Call configure() before init() to customise behaviour:

GeocodingService.instance.configure(
  options: const GeocodeCacheOptions(
    cacheRadiusMeters: 20,        // match within 20m (default: 10m)
    maxAge: Duration(days: 7),    // expire after 7 days (default: never)
    maxCacheSize: 500,            // keep up to 500 entries (default: 250)
    userAgent: 'MyApp/1.0',       // for Nominatim requests
  ),
);

await GeocodingService.instance.init();

Custom Address Format #

GeocodingService.instance.configure(
  options: GeocodeCacheOptions(
    addressFormatter: (street, locality, state, country) {
      return '$locality, $country';
    },
  ),
);

Options Reference #

Option Type Default Description
cacheRadiusMeters double 10.0 Distance threshold for cache hits (meters)
boxName String 'geocode_cache' Hive box name for geocode entries
maxAge Duration? null Max age before entry expires. null = never
maxCacheSize int 250 Max entries before FIFO eviction kicks in
userAgent String 'geocode_cache/1.0' User-Agent for Nominatim HTTP requests
addressFormatter Function? null Custom address string builder

Usage #

Reverse Geocoding #

final address = await GeocodingService.instance
    .getAddressFromCoordinates(latitude, longitude);

if (address != null) {
  print('Resolved: $address');
} else {
  print('Could not resolve address');
}

Search for places using Nominatim with automatic caching:

final results = await GeocodingService.instance.searchPlaces('Ubud, Bali');

for (final place in results) {
  print('${place['display_name']} (${place['lat']}, ${place['lon']})');
}

Cache Management #

// Check cache sizes
print(GeocodingService.instance.cacheSize);            // geocode entries
print(GeocodingService.instance.placeSearchCacheSize); // place search entries

// Clear everything
await GeocodingService.instance.clearCache();

// Clear selectively
await GeocodingService.instance.clearGeocodeCache();
await GeocodingService.instance.clearPlaceSearchCache();

// Evict entries older than 30 days
final evicted = await GeocodingService.instance
    .evictEntriesOlderThan(const Duration(days: 30));
print('Evicted $evicted stale entries');

// Inspect cached entries
final entries = GeocodingService.instance.allCachedEntries;
for (final entry in entries) {
  print('${entry.latitude}, ${entry.longitude} → ${entry.address}');
}

Cleanup #

// Close Hive boxes and reset the singleton
await GeocodingService.instance.dispose();

After dispose(), calling GeocodingService.instance returns a fresh instance that can be configured and initialised again.

How It Works #

┌─────────────────────────────────────────────────────┐
│              getAddressFromCoordinates()             │
└─────────────────────┬───────────────────────────────┘
                      │
                      ▼
┌─────────────────────────────────────────────────────┐
│  Search cache for entry within cacheRadiusMeters    │
│  (Haversine distance, skip expired entries)         │
└──────────┬──────────────────────────┬───────────────┘
           │                          │
     Cache HIT                  Cache MISS
           │                          │
           ▼                          ▼
┌──────────────────┐    ┌─────────────────────────────┐
│  Return cached   │    │  Call platform geocoding API │
│  address         │    │  Save result to cache        │
└──────────────────┘    │  Return address              │
                        └─────────────────────────────┘

Platform Setup #

This package uses the geocoding package for reverse geocoding. Follow its platform setup:

Android #

Add to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

iOS #

Add to ios/Runner/Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs location access to resolve addresses.</string>

Web #

No additional setup required. The geocoding package uses the browser's built-in geocoding capabilities.

Example #

A complete example integrating with a Flutter app:

import 'package:flutter/material.dart';
import 'package:geocode_cache/geocode_cache.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  GeocodingService.instance.configure(
    options: const GeocodeCacheOptions(
      cacheRadiusMeters: 15,
      maxAge: Duration(days: 7),
    ),
  );
  await GeocodingService.instance.init();

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Geocode Cache Demo')),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              final address = await GeocodingService.instance
                  .getAddressFromCoordinates(-8.6705, 115.2126);
              debugPrint('Address: $address');
            },
            child: const Text('Get Address'),
          ),
        ),
      ),
    );
  }
}

Contributing #

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Commit your changes (git commit -am 'Add my feature')
  4. Push to the branch (git push origin feature/my-feature)
  5. Open a Pull Request

Development #

# Get dependencies
flutter pub get

# Run tests
flutter test

# Regenerate Hive adapters (only if models change)
dart run build_runner build --delete-conflicting-outputs

# Analyze code
flutter analyze

License #

MIT — see LICENSE for details.

0
likes
150
points
211
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter package for caching geocoding and place search results locally using Hive CE storage with Haversine distance matching. Minimizes API calls by serving nearby coordinates from cache.

Repository (GitHub)
View/report issues

Topics

#geocoding #cache #location #hive #maps

License

MIT (license)

Dependencies

flutter, geocoding, hive_ce, hive_ce_flutter, http

More

Packages that depend on geocode_cache