Skip to content

Instantly share code, notes, and snippets.

Last active Jul 29, 2016
What would you like to do?
.NET Xamarin gist to download ArcGIS basemap tiles for offline use.
using Esri.ArcGISRuntime.ArcGISServices;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Tasks.Offline;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
namespace JcaFormsMapsShared.ArcGisRendering
/// <summary>
/// taken from
/// Download basemap tile caches, can only download a max of 100,000 tiles.
/// Right now the min/max scale of the download is fixed to provide a high enough level of detail,
/// without an overly large file size or download duration.
/// </summary>
public class OffLineMap
// Default export paths
private static string defaultFilePath_ = "/storage/emulated/0/SmartMaps/";
private static string defaultFileName_ = "tile-cache.tpk";
// ArgGIS map server for imagery data
private const string ONLINE_BASEMAP_URL = "";
// Folder location for export
public string OfflineMapLocation { get; set; }
// File name for export
public string OfflineMapName { get; set; }
// Current map view and extent set by the user. This view
// will be used to export chosen tiles.
public Envelope MapViewEnvelope { get; set; }
// Export tile operation
private static ExportTileCacheTask exportTileTask_ = null;
// Tile export parameters
private static ExportTileCacheParameters tileParameters_ = null;
/// <summary>
/// Tile size estimate.
/// </summary>
public struct TileSizeEstimate
public int TileCount;
public double TileSize;
public string ErrorMessage;
/// <summary>
/// Download basemap tiles from argGIS server for offline use. The tiles can be imagery, topographic etc.
/// Downloading the tiles requires an Esri account with sufficient privileges to download tiles. See here:
/// for more information.
/// </summary>
public async void DownLoadOffLineMap()
// Establish Esri login token
var options = new Esri.ArcGISRuntime.Security.GenerateTokenOptions()
Referer = new Uri(ONLINE_BASEMAP_URL)
// Use an Esri account to generate a security credential. Account must be a developer account
// have access to map export services.
var cred = await Esri.ArcGISRuntime.Security.AuthenticationManager.Current.GenerateCredentialAsync(
new Uri(""),
<Username>, <password>,
//Check the credential and add to the identity manager
if (cred != null)
// Get URI from server URL
Uri server = new Uri(ONLINE_BASEMAP_URL);
//Create the service for the export, this requires the credential
var tileService = await ArcGISMapServiceInfo.CreateAsync(server, cred);
// Create the export task
exportTileTask_ = new ExportTileCacheTask(server);
// Get map scales from tile service. In this case take the smallest scales available
// (smallest map area) that we can reasonably export.
int arrayLength = tileService.TileInfo.LevelsOfDetail.ToArray().Length;
double minScale = tileService.TileInfo.LevelsOfDetail.ToArray()[arrayLength - 10].Scale;
double maxScale = tileService.TileInfo.LevelsOfDetail.ToArray()[arrayLength - 5].Scale;
// Get export parameters, using the current map viewpoint and the chosen scales.
tileParameters_ = await exportTileTask_.CreateExportTileCacheParametersAsync(MapViewEnvelope,
// Download tile cache
var cache = await downloadTileCache(OfflineMapLocation, OfflineMapName, MapViewEnvelope);
catch (Exception ex)
var errorMessage = ex.Message;
Debug.WriteLine("An error has occurred while exporting tiles");
/// <summary>
/// Download basemap tile cache from online source. Download is limited to 100,000 tiles.
/// </summary>
/// <param name="mapLocation">Folder location for the tile cache</param>
/// <param name="mapName">Out put name of the tile cache</param>
/// <param name="mapExtent">Current view extent of the map to be exported</param>
/// <returns>Tile cache task that contains the status of the exported tile cache</returns>
public static async Task<TileCache> downloadTileCache(string mapLocation, string mapName, Envelope mapExtent)
// Build and check output file path. Use default if not specified
string exportPath = defaultFilePath_ + defaultFileName_;
if (mapLocation == null || mapName == null)
mapLocation = defaultFilePath_;
mapName = defaultFileName_;
exportPath = System.IO.Path.Combine(mapLocation, mapName);
// Try and create the directory if it doesn't exist.
if (!System.IO.Directory.Exists(exportPath))
catch (Exception ex)
Debug.WriteLine("Error, could not create directory for tile cache");
return null;
// Download tile cache and export to file
Job<TileCache> exportJob = exportTileTask_.ExportTileCache(tileParameters_, exportPath);
//Create the handler for status updates
exportJob.JobChanged += (object sender, EventArgs evt) => {
Debug.WriteLine("[EXPORT STATUS MESSAGE] " + exportJob.Status.ToString());
//Get the result
TileCache cache = await exportJob.GetResultAsync();
await cache.LoadAsync();
//Check the result
if (cache == null)
Debug.WriteLine("Tile cache export failed");
Debug.WriteLine("Tile cache export success!");
return cache;
} // class
} // namespace
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment