The tiles are first searched in the memory cache (the tiles displayed recently), the local cache, archive local then on the internet if need.
Local cache
By assigning a directory to LocalCache property internet downloaded tiles are saved locally and are available offline.Under android you will have to ask permission to read and write your data.
1...
System.Permissions,
{$IFDEF ANDROID}
Androidapi.Jni.Os,
Androidapi.jni.javatypes,
Androidapi.Helpers,
{$ENDIF}
...
{$IFDEF ANDROID}
PermissionsService.RequestPermissions([JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE),
JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)],
procedure(const APermissions: TArray< string >;
const AGrantResults: TArray<TPermissionStatus>)
begin
if (Length(AGrantResults) = 2) and
(AGrantResults[0] = TPermissionStatus.Granted) and (AGrantResults[1] = TPermissionStatus.Granted)
then map.LocalCache := TPath.Combine(TPath.GetSharedDocumentsPath, 'cache')
else
map.LocalCache := '';
end)
{$ELSE}
map.LocalCache := TPath.Combine(TPath.GetSharedDocumentsPath, 'cache');
{$ENDIF}
Use the MaxDayInCache property to specify the duration of retention in the cache by default 30 days, 0 for an infinite cache.
LocalTileCache
This property of type TCustomTileCache allows you to save and load local tiles, instead of placing them in a subdirectory, for example, you can store them in a database.
You must therefore create a class descended from TCustomTileCache and redefine certain methods.
See the unit TileCacheSQLite.FireDAC which contains TTileCacheSQLite, it stores your tiles in a SQLite database saved in your directory LocalCache.
...
//Define a local directory in which to store the database
map.LocalCache := ExtractfilePath(ParamStr(0)) + 'cache' ;
// Create TTileCacheSQLite,
// which handles DB creation on server changeover,
// and tile saving and reading on demand
map.LocalTileCache := TTileCacheSQLite.create(map);
private
...
protected
// overload to react to server changes,
// here we'll open a database with the server's name
procedure doChangeTileServer(sender: TObject); override;
// override to save the XYZ tile contained in Stream,
// AHandle must be True if registration is ok
procedure doSaveLocalStream(const sender: TObject; const x, y, z: Integer;
const stream: TMemoryStream; var AHandled: boolean); override;
// override to load the XYZ tile in Stream,
// AHandle must be True if is ok
procedure doLoadLocalStream(const sender: TObject; const x, y, z: Integer;
const stream: TMemoryStream; var AHandled: boolean); override;
LocalTileCache is automatically released when the map is destroyed or when you change it, set it to nil to return to classic directory storage.
MBTiles
A MBTiles file is a file format for storing map tiles in a single file, technically a SQLite database.
To use it, add the file uecMBTiles.FireDAC (FMX.uecMBTiles.FireDAC under Firemonkey) to your uses.
FireDAC is used to access the SQLite database, so it's only compatible with recent versions of Delphi.
1... System.Permissions,System.IOUtils,
FMX.uecNativeMapControl,FMX.uecMBTiles.FireDAC;
{$IFDEF ANDROID}
const
PermissionReadExternalStorage = 'android.permission.READ_EXTERNAL_STORAGE';
PermissionWriteExternalStorage = 'android.permission.WRITE_EXTERNAL_STORAGE';
{$ENDIF}
procedure TForm23.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID} // android permissions management
PermissionsService.RequestPermissions
([PermissionReadExternalStorage,
PermissionWriteExternalStorage],
nil);
{$ENDIF}
{$IF DEFINED(iOS) or DEFINED(ANDROID)}
FDataBase := TPath.Combine(TPath.GetSharedDocumentsPath, 'countries-raster.mbtiles');
{$ELSE}
FDataBase := 'H:\#DATA\MBTiles\countries-raster.mbtiles';
{$ENDIF}
// connect the component Map to the MBTiles server
FecMBTiles := TecMBTiles.Create(Map);
// open DataBase, true if ok
if not FecMBTiles.Connect(FDataBase) then
begin
ShowMessage(FecMBTiles.MessageError);
end;
// call FecMBTiles.Disconnect for disconnect
end;
procedure TForm23.FormDestroy(Sender: TObject);
begin
FecMBTiles.Free;
end;
The demo uses the MBTiles raster file which can be found at //github.com/klokantech/vector-tiles-sample
1Archive local
An MBTiles file is much more efficient than a simple zip.
2An archive local is the local cache in a Zip, this simplifies deployment of the tiles and other files.
To improve the speed, the tiles are extracted from archive and placed in the local cache during the first request, you must set a local cache to use an archive.
map.TileServer := tsOSM;
map.LocalArchive := ExtractfilePath(ParamStr(0))+'ile_de_re.zip';
If roads or geolocations of addresses are saved in archive recovery is completely transparent
2// if an archive is connected and contains the route, no internet connection is made to return the way
map.Routing.Request('saint-martin de ré', 'la couarde sur mer');
You can store your images or data files (kml, geojson etc...), to load start the name of the file by /
map.Shapes.LoadFromFile('/DATA/tdf.kml');
map.LoadFromFile('/DATA/tarbes.txt');
// load image in marker
marker.filename := '/IMAGE/node.png';
Use MapArchive to directly manipulate your archive and retrieve other data.
try
map.MapArchive.ReadStream('DATA/mydata.txt',m);
memo1.Lines.LoadFromStream(m);
finally
m.Free;
end;
MapArchiveCreator
This small utility allows you to create your archives, you can download areas of tiles, save routes, add images and files.
You can ban any internet connection for the tiles and geocoding using the property OnlyLocal
3map.onlyLocal := true;
Download full a zone
The TECDownLoadTiles class allows you to download in the background one complete zone, the EcNativeMapFiremonkeyDemo shows you how to preload the viewable area on the screen.
FECDownLoadTiles:=TECDownLoadTiles.create;
FECDownLoadTiles.OnDownLoad := doDownLoadtiles;
FECDownLoadTiles.OnEndDownLoad :=
doEndDownLoadtiles;
// tiles are saved in
DirectoryTiles
FECDownLoadTiles.DirectoryTiles := map.LocalCache;
FECDownLoadTiles.TileServer := map.TileServer;
FECDownLoadTiles.TileSize := map.TileSize;
// download visible area from
zoom+1 to MaxZoom
FECDownLoadTiles.DownLoadTiles(map.Zoom+1,map.MaxZoom,
map.NorthEastLatitude,map.NorthEastLongitude,
map.SouthWestLatitude,map.SouthWestLongitude);
...
// for abort
FECDownLoadTiles.Cancel;
// for pause
FECDownLoadTiles.Pause := true;
// restart
FECDownLoadTiles.Pause := false;
// see ECNativeMapFiremokeyDemo for
complete use
Make sure that your provider of tile allows it !
3Resume downloading later
You must save the following properties to be able to resume downloading at a specific location.
property StartY : integer
property StartZoom : byte
property StartCountTiles : integer
property StartDownLoadTiles : integer
property FromZoom : integer
property ToZoom : Integer
property NorthEastLatitude : double
property NorthEastLongitude : double
property SouthWestLatitude : double
property SouthWestLongitude : double
For the restart you will need to call this version of DownLoadTiles
const NorthEastLatitude, NorthEastLongitude,
SouthWestLatitude,SouthWestLongitude: double;
const StartX,StartY:integer;
const StartZoom:byte;
const StartCountTiles,
StartDownLoadtiles:integer);
Fill the Stream of tiles
You can also directly return a stream containing the jpeg or png of your tiles, useful if you have your tiles in a database.
// manual
management tiles as stream
map.TileServerInfo.getTileStream := getTileStream;
// the name will be uses as
subdirectory in cache
map.TileServerInfo.Name := 'MyMAP';
// important to specify a manual
management tiles
map.TileServer := tsOwnerDraw;
// asks for a tile
procedure
TForm2.getTileStream(const
ThreadIndex:integer;var
TileStream: TMemoryStream;
const x, y, z:
integer);
begin
// here fill tileStream with
tileXYZ
end;
Also allows to use a Server's remote tiles.
1