11import 'dart:async' ;
22import 'dart:math' ;
33
4- import 'package:collection/collection.dart' show MapEquality;
4+ import 'package:collection/collection.dart' show MapEquality, ListEquality ;
55import 'package:flutter/foundation.dart' ;
66import 'package:flutter/material.dart' ;
77import 'package:flutter_map/flutter_map.dart' ;
@@ -12,6 +12,7 @@ import 'package:flutter_map/src/layer/tile_layer/tile_image_manager.dart';
1212import 'package:flutter_map/src/layer/tile_layer/tile_range.dart' ;
1313import 'package:flutter_map/src/layer/tile_layer/tile_range_calculator.dart' ;
1414import 'package:flutter_map/src/layer/tile_layer/tile_scale_calculator.dart' ;
15+ import 'package:flutter_map/src/layer/tile_layer/unblock_osm.dart' ;
1516import 'package:flutter_map/src/misc/extensions.dart' ;
1617import 'package:http/http.dart' ;
1718import 'package:http/retry.dart' ;
@@ -343,6 +344,41 @@ class TileLayer extends StatefulWidget {
343344}
344345
345346class _TileLayerState extends State <TileLayer > with TickerProviderStateMixin {
347+ static const _openStreetMapUrls = {
348+ 'tile.openstreetmap.org' ,
349+ 'tile.osm.org' ,
350+ };
351+ bool get _isOpenStreetMapUrl =>
352+ widget.urlTemplate != null &&
353+ _openStreetMapUrls.any ((target) => widget.urlTemplate! .contains (target));
354+
355+ static const _unblockOpenStreetMapUrlEnv =
356+ String .fromEnvironment ('flutter.flutter_map.unblockOSM' );
357+ static bool get _unblockOpenStreetMapUrl => const ListEquality <int >()
358+ .equals (_unblockOpenStreetMapUrlEnv.codeUnits, unblockOSM);
359+
360+ static final _blockOpenStreetMapUrl =
361+ // ignore: dead_code
362+ false && (kReleaseMode || kProfileMode) && ! _unblockOpenStreetMapUrl;
363+ void _warnOpenStreetMapUrl () {
364+ if (! _isOpenStreetMapUrl || ! kDebugMode || _unblockOpenStreetMapUrl) return ;
365+ Logger (printer: PrettyPrinter (methodCount: 0 )).e (
366+ '''\x 1B[1m\x 1B[3mflutter_map\x 1B[0m
367+ flutter_map wants to help keep map data available for everyone.
368+ We use the public OpenStreetMap tile servers in our code examples & demo app,
369+ but they are NOT free to use by everyone.
370+ In an upcoming non-major release, requests to 'tile.openstreetmap.org' or
371+ 'tile.osm.org' will be blocked by default in release mode.
372+ Please review https://operations.osmfoundation.org/policies/tiles/ to see if
373+ your project is compliant with their Tile Usage Policy.
374+ For more information, see https://docs.fleaflet.dev/tile-servers/using-openstreetmap-direct.
375+ It describes in additional detail why we feel it is important to do this, how
376+ you can unblock the tile servers if your use-case is acceptable, the timeframes
377+ for this new policy, and how we're working to reduce requests without any extra
378+ work from you.''' ,
379+ );
380+ }
381+
346382 bool _initializedFromMapCamera = false ;
347383
348384 final _tileImageManager = TileImageManager ();
@@ -371,6 +407,7 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
371407 super .initState ();
372408 _resetSub = widget.reset? .listen (_resetStreamHandler);
373409 _tileRangeCalculator = TileRangeCalculator (tileDimension: _tileDimension);
410+ _warnOpenStreetMapUrl ();
374411 }
375412
376413 // This is called on every map movement so we should avoid expensive logic
@@ -428,6 +465,8 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
428465 super .didUpdateWidget (oldWidget);
429466 var reloadTiles = false ;
430467
468+ _warnOpenStreetMapUrl ();
469+
431470 // There is no caching in TileRangeCalculator so we can just replace it.
432471 _tileRangeCalculator = TileRangeCalculator (tileDimension: _tileDimension);
433472
@@ -505,6 +544,10 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
505544
506545 if (_outsideZoomLimits (map.zoom.round ())) return const SizedBox .shrink ();
507546
547+ if (_isOpenStreetMapUrl && _blockOpenStreetMapUrl) {
548+ return const SizedBox .shrink ();
549+ }
550+
508551 final tileZoom = _clampToNativeZoom (map.zoom);
509552 final tileBoundsAtZoom = _tileBounds.atZoom (tileZoom);
510553 final visibleTileRange = _tileRangeCalculator.calculate (
@@ -667,6 +710,10 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
667710 DiscreteTileRange tileLoadRange, {
668711 required bool pruneAfterLoad,
669712 }) {
713+ if (_isOpenStreetMapUrl && _blockOpenStreetMapUrl) {
714+ return ;
715+ }
716+
670717 final tileZoom = tileLoadRange.zoom;
671718 final expandedTileLoadRange = tileLoadRange.expand (widget.panBuffer);
672719
0 commit comments