Viewing version 2.1.0. Open the latest package page.

flutter_map_cache

2.1.0

A slim yet powerful caching plugin for flutter_map tile layers.

Download archive

Readme

flutter_map_cache

A slim yet powerful caching plugin for flutter_map tile layers.

Pub Version likes Pub Points Pub Downloads

GitHub last commit stars GitHub issues codecov

Motivation

  • Many tile providers require users in their tile usage policy to cache tile requests. This decreases the load on those servers and is important especially if they are donation based like the OpenStreetMap.
  • Commercial tile providers normally charge per tile request. By caching tiles you can reduce the amount of tile requests and lower your costs.
  • Caching map tiles provides a better user experience since the region the user visited loads nearby instantly. Most of the time a user visits the same regions often, e.g. because it is the region he lives in.
  • Especially raster tiles that are used by default on flutter_map, the data consumption can be high quite fast. Caching tiles lowers the amount of used mobile data and bandwidth.

flutter_map introduced a caching mechanism in version 8.2.0 that solves these topics. This package is for users that need advanced use cases that are not covered by the default caching mechanism of flutter_map and legacy support for flutter_map versions < 8.2.0.

Features

The package uses dio with the dio_cache_interceptor package and supports the storage backend that you like.

Supported storage backends are:

Storage backend Description
In-Memory - For testing purposes- flutter_map has memory caching itself
File System - Easy to setup, no additional storage backend package required- potentially slower than using a database
Drift - SQLite database- good platform support
Hive CE - key-value database- easy to integrate
ObjectBox - NoSQL database- More complex integration
Isar - NoSQL database- More complex integration
Sembast - NoSQL database

Other storage backends will be supported as soon as the underlying package dio_cache_interceptor supports them.

Getting started

  1. Add the packages you want to use to your pubspec.yaml file. Only add the packages for the backend you want to use.
dependencies:
  flutter_map: ^8.1.1 # in case you don't have it yet 
  flutter_map_cache: ^2.0.0 # this package
  path_provider: ^2.1.2 # in case the storage backend requires a path

  # drift
  http_cache_drift_store: ^7.0.0
  sqlite3_flutter_libs: ^0.5.15

  # file system
  http_cache_file_store: ^2.0.0

  # hive
  http_cache_hive_store: ^5.0.0

  # objectbox
  http_cache_objectbox_store: ^2.0.0
  objectbox_flutter_libs: ^1.4.1

  # isar
  http_cache_isar_store: ^2.0.0
  isar: ^3.1.0+1
  isar_flutter_libs: ^3.1.0+1

  # sembast
  http_cache_sembast_store: ^1.0.0
  sembast: ^3.8.4+1
  sembast_web: ^2.4.1
  1. ⚠️ Some storage backends have their own required setups. Please check them out in their package documentations.

Usage

Using the cache is easy. Here are examples how to use some of the storage backends:

Hive

  1. First get the cache directory of the app (i.e. with the path_provider package).
import 'package:path_provider/path_provider.dart';

Future<String> getPath() async {
  final cacheDirectory = await getTemporaryDirectory();
  return cacheDirectory.path;
}
  1. Then use the directory path to initialize the HiveCacheStore. You can wrap FlutterMap inside a FutureBuilder to use the getPath() method.
@override
Widget build(BuildContext context) {
  return FlutterMap(
    options: MapOptions(),
    children: [
      TileLayer(
        urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
        tileProvider: CachedTileProvider(
          // maxStale keeps the tile cached for the given Duration and 
          // tries to revalidate the next time it gets requested
          maxStale: const Duration(days: 30),
          store: HiveCacheStore(
            path,
            hiveBoxName: 'HiveCacheStore',
          ),
        ),
      ),
    ],
  );
}

In Memory (for testing)

import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_cache/flutter_map_cache.dart';

class MyMap extends StatelessWidget {
  MyMap({super.key});

  // create the cache store as a field variable
  final _cacheStore = MemCacheStore();

  @override
  Widget build(BuildContext context) {
    return FlutterMap(
      options: MapOptions(),
      children: [
        TileLayer(
          urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
          tileProvider: CachedTileProvider(
            // use the store for your CachedTileProvider instance
            store: _cacheStore,
          ),
        ),
      ],
    );
  }
}

File System

import 'dart:io';

import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:http_cache_file_store/http_cache_file_store.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_cache/flutter_map_cache.dart';
import 'package:path_provider/path_provider.dart';

class MyMap extends StatefulWidget {
  const MyMap({super.key});

  @override
  State<MyMap> createState() => _MyMapState();
}

class _MyMapState extends State<MyMap> {
  // create the cache store as a field variable
  final Future<CacheStore> _cacheStoreFuture = _getCacheStore();

  /// Get the CacheStore as a Future. This method needs to be static so that it
  /// can be used to initialize a field variable.
  static Future<CacheStore> _getCacheStore() async {
    final dir = await getTemporaryDirectory();
    // Note, that Platform.pathSeparator from dart:io does not work on web,
    // import it from dart:html instead.
    return FileCacheStore('${dir.path}${Platform.pathSeparator}MapTiles');
  }

  @override
  Widget build(BuildContext context) {
    // show a loading screen when _cacheStore hasn't been set yet
    return FutureBuilder<CacheStore>(
      future: _cacheStoreFuture,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          final cacheStore = snapshot.data!;
          return FlutterMap(
            options: MapOptions(),
            children: [
              TileLayer(
                urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
                tileProvider: CachedTileProvider(
                  // use the store for your CachedTileProvider instance
                  store: cacheStore,
                ),
              ),
            ],
          );
        }
        if (snapshot.hasError) {
          return Center(child: Text(snapshot.error.toString()));
        }
        return const Center(child: CircularProgressIndicator());
      },
    );
  }
}

More examples

You can find additional example implementations for other storage backends in the example app on GitHub.

Common use cases & frequent questions

How about web?

This package supports the web as long as you use a storage backend that supports web.

  • In Memory works out of the box
  • Hive uses for its web support IndexedDB under the hood to support web.
  • Drift (SqLite) requires additional setup steps for web

Does this package support cancellation of tile requests?

Yes. This package includes the tile cancellation out of the box. There is no need for flutter_map_cancellable_tile_provider when using this package.


Remove the api key from the url before it gets used for caching

Commercial tile providers often use an api key that is attached as a parameter to the url. While this shouldn't be a problem when the api key stays the same you might want to make it immune to api key changes anyway.

final _uuid = Uuid();

CachedTileProvider(
  keyBuilder: (request) {
    return _uuid.v5(
      Uuid.NAMESPACE_URL,
      request.uri.replace(queryParameters: {}).toString(),
    );
  },
),

Can I use this package for an offline map?

This package does not provide support to download tiles automatically. Only tiles that were previously visited with an active internet connection show up on the map.

If you need to have the map completely offline, I recommend to check out the file formats MBTiles or PMTiles.


What if I want to use sqflite?

Because dio_cache_interceptor already supports Drift as a SQLite solution it's unlikely that sqflite will be supported any day soon.

If you still are required to use only sqflite, I recommend to create your own tile provider by using the cached_network_image package.


Additional information

Pull requests are welcome. If you want to add support for another storage backend you can check out dio_cache_interceptor.

If you need help you can open an issue or join the flutter_map discord server.

Changelog

[2.1.0] 2026-04-11

  • Add headers parameter to CachedTileProvider to allow adding custom headers to tile requests.

[2.0.0+1] 2025-04-18

  • Update "Getting started" documentation

[2.0.0] 2025-04-06

Please update your integration and used store packages according to the Getting Started section. More information can be found in the dio_cache_interceptor changelog.

[1.5.2] 2025-02-05

  • Support for flutter_map v6, v7 and v8

[1.5.1] 2024-05-27

  • Support for flutter_map v6 and v7

[1.5.0] 2024-02-19

  • fix: assertion error when the total amount of bytes is unknown (thanks to @Thelm76).
  • add: optional cachePolicy parameter (thanks to @Thelm76).
  • Update README

[1.4.4] 2024-02-10

  • Add web as supported platform
  • Update docs
  • Add tests

[1.4.3] 2024-02-06

  • Fix: CachedTileProvider.dio had its BaseOptions overridden (#12, thanks to @Thelm76)
  • Add tests

[1.4.2] 2024-02-01

  • Migrate GitHub repository to a multi-package repo.
  • Update README and package links.

[1.4.1] 2024-01-24

  • Fix description of Isar in the README file.

[1.4.0] 2024-01-24

  • Add dio as a parameter to CachedTileProvider. You're now able to provide and reuse your own Dio instance (thanks to @PatrickWulfe).
  • Deprecate the dioOptions parameter. Prefer creating your own Dio instance and provide it to the dio parameter.
  • Update the README file (for example add isar to the list of supported storage backends).

[1.3.1] 2023-10-20

[1.3.0] 2023-10-09

[1.2.0] 2023-06-28

CachedTileProvider

  • Add the List<Interceptor>? interceptors as a Parameter and remove the verbose parameter. The interceptors will get applied before the cache interceptor.
  • The store parameter is now required.
  • Add the option to override the hitCacheOnErrorExcept parameter. By default, a cached request will not get used if the server returns with status code 401 or 403.
  • Remove the dio parameter but set dio as a public field variable so that it can get modified after creation.
  • Add BaseOptions? dioOptions as a parameter.

Fixes

  • Use cache when device has no internet connection and a SocketException gets thrown.

[1.1.1] 2023-06-22

  • Update documentation and example project
  • Use the user agent header provided by the TileLayer

[1.1.0] 2023-06-09

  • Add maxStale and keyBuilder as optional parameters to CachedTileProvider:

[1.0.0] 2023-06-09

  • Initial version.

Installing

export PUB_HOSTED_URL=https://pub.mirror.p-hatan.com
flutter pub add 'flutter_map_cache:2.1.0'
pubspec.yaml
name: flutter_map_cache
description: A slim yet powerful caching plugin for flutter_map tile layers.
version: 2.1.0
repository: https://github.com/josxha/flutter_map_plugins
issue_tracker: https://github.com/josxha/flutter_map_plugins/issues
resolution: workspace
topics: [ flutter-map, map, cache, dio ]
funding:
  - https://paypal.me/joschaeckert
  - https://github.com/sponsors/josxha

platforms:
  android:
  ios:
  linux:
  macos:
  web:
  windows:

environment:
  sdk: ">=3.6.0 <4.0.0"

dependencies:
  dio: ^5.2.0+1
  dio_cache_interceptor: ^4.0.0
  flutter:
    sdk: flutter
  flutter_map: ">=6.0.0 <9.0.0"

dev_dependencies:
  flutter_test:
    sdk: flutter
  http_mock_adapter: ^0.6.1
  latlong2: ^0.9.0
  test: ^1.24.9
  very_good_analysis: ^10.0.0

Version history

VersionPublishedArchiveSHA-256
1.0.0On demandDownload6b7c4d97…6118f8
1.1.0On demandDownloadad789669…c9a418
1.1.1On demandDownloadb0f11c4e…bc6eae
1.2.0On demandDownloadb272440c…5a2279
1.3.0On demandDownload4fa3dabd…9b2e3a
1.3.1On demandDownloadf8d178ef…b130c2
1.4.0On demandDownloadc5fa2ae3…e0d68f
1.4.1On demandDownloadb6fba2e8…859918
1.4.2On demandDownload3612aab9…c9d6fe
1.4.3On demandDownload319779c8…50bd96
1.4.4On demandDownload84c2f7cc…b4b96c
1.5.0On demandDownload5539033b…38aa5a
1.5.1On demandDownload47607b8d…6c2f43
1.5.2On demandDownload5b30c9b0…6e03ef
2.0.0On demandDownload8d3aa34f…5d7dd1
2.0.0+1On demandDownloadfc969776…5c7246
2.1.0Cached · Upstream SHA-256 matchedDownload4ec2f24d…82f026
2.1.1On demandDownloade48e8be8…82b2b4

Dependencies

dio "^5.2.0+1"

dio_cache_interceptor "^4.0.0"

flutter { "sdk": "flutter" }

flutter_map "\u003e=6.0.0 \u003c9.0.0"