Consider taking individual layers offline as offline data if you want to construct the map or scene yourself and provide users with up-to-date information from ArcGIS Online or ArcGIS Enterprise. This topic describes how to generate and download offline data to use the following layers offline:
- Feature and annotation layers — Download a specific geographical area from a sync-enabled feature service into a mobile geodatabase. Edits can be synchronized with other users when connectivity is restored. This synchronization process allows the app to maintain an up-to-date view of the feature data.
- Tiled layers
- Vector tiled data — ArcGIS vector tile services or vector basemaps in ArcGIS Online
- Image tiled data — Tiled ArcGIS map services, tiled ArcGIS image services, tiled basemaps or elevation sources in ArcGIS Online
You can export and download tiled layer caches locally and access them while your device is offline. It is important to note that you cannot edit tiled layer data (vector tiled data and image tiled data). If you require updates to the tiled layer data, you must export and download them again.
Feature and annotation layers
You can take features (including annotation, related records, and attachments) offline, from a feature service, by downloading them to geodatabase feature tables within a mobile geodatabase. To do this, the feature service must be hosted on ArcGIS Enterprise 10.2.2 or later for features or from a service hosted in ArcGIS Online, provided that the feature service has been sync enabled (allow disconnected editing with synchronization).
You can use an existing feature service or create feature services for your own data. To enable synchronization for a feature service, do the following:
- ArcGIS Online — Edit the feature service item and check the Sync check box.
- ArcGIS Enterprise — See Prepare data for offline use in the ArcGIS Server documentation.
To create the mobile geodatabase, you must do the following:
- Generate geodatabase parameters and define the area of interest, the layers, any expression filters, and so on, if required.
- Create the geodatabase, populate it with all the relevant features, and download it to the user's device.
Generate geodatabase parameters
When you create a mobile geodatabase, you must provide a set of parameters, described below, to define exactly which data is downloaded.
- The geographical area of interest. You typically supply the area of interest as an extent (in other words, an envelope) but point, line, and polygon (including multipart) geometries are also supported. This allows you to create more detailed areas of interest. Regardless of the geometry, any features that intersect with the supplied area of interest are extracted.
- The spatial reference of the mobile geodatabase.
- Individual layers can be managed using the
GenerateGeodatabaseParameters::layerOptions
property:- Determine which layers are included in the mobile geodatabase.
- Subset the features by providing an expression that filters features by attribute values, such as
ZON
.E = ' CO M' - The synchronization model controls how edits made to the mobile geodatabase are applied back to the feature service during synchronization. The model supported is defined by the data that was used to create the sync-enabled feature service. If the data is nonversioned, the synchronization model is per layer. This is the most flexible model, allowing you to synchronize on a layer-by-layer basis, based on the layers you specify. If the data is versioned, the synchronization model is per geodatabase. This synchronizes the entire geodatabase, including all layers and tables, at once.
- Specify whether to include feature attachments in the mobile geodatabase and whether they can be uploaded during synchronization.
- Identify whether tables related to the layer are also included in the geodatabase.
You can obtain a default set of parameters (GenerateGeodatabaseParameters
) using the createDefaultGenerateGeodatabaseParameters
method on the GeodatabaseSyncTask
. If you provide the area of interest, the default parameters will be generated taking into account the capabilities supported by the ArcGIS feature service. You can update these default parameter values before creating the geodatabase.
// Get the path to the feature service Url.
const QUrl featureServiceUrl = QUrl
("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Sync/SaveTheBaySync/FeatureServer");
// Create a new GeodatabaseSyncTask to create a local version of feature service data.
GeodatabaseSyncTask* geodatabaseSyncTask = new GeodatabaseSyncTask(featureServiceUrl, this);
// Get the viewpoint from the map view's current view point.
const Viewpoint viewpoint = m_mapView->currentViewpoint(ViewpointType::BoundingGeometry);
// Cast the view point's geometry to an envelope.
const Envelope envelope = static_cast<Envelope>(viewpoint.targetGeometry());
// Execute the geodatabase's create default generate geodatabase async method using
// the supplied envelope. It returns a generate geodatabase parameters object.
geodatabaseSyncTask->createDefaultGenerateGeodatabaseParametersAsync(envelope).then(this,
[this, geodatabaseSyncTask] (const GenerateGeodatabaseParameters& defaultGenerateGdbParams)
{
// Test if the generate geodatabase parameters is valid.
if (m_generateGeodatabaseParameters.isEmpty())
{
return;
}
// Copy the returned parameters to a member variable for use outside this scope.
m_generateGeodatabaseParameters = defaultGenerateGdbParams;
// Set the synchronization model to per layer.
m_generateGeodatabaseParameters.setSyncModel(SyncModel::Layer);
// Define the layers and features to include.
constexpr int marineLayerId = 0;
constexpr int birdsLayerId = 1;
const QString dolphinsOnlyWhereClause = "type = 11";
// Clear existing and set new layer options.
m_generateGeodatabaseParameters.setLayerOptions(QList<GenerateLayerOption>{
GenerateLayerOption(marineLayerId, dolphinsOnlyWhereClause),
GenerateLayerOption(birdsLayerId)});
// Do not return attachments.
m_generateGeodatabaseParameters.setReturnAttachments(false);
// Create the generate geodatabase job, pass in the parameters and an output path for
// the local geodatabase.
GenerateGeodatabaseJob* generateGeodatabaseJob = geodatabaseSyncTask->generateGeodatabase(
m_generateGeodatabaseParameters, "path/to/geodatabse/file");
// Provide some feedback.
qDebug() << generateGeodatabaseJob->result()->loadStatus();
});
Create the geodatabase
Obtain a job to generate and download the geodatabase by passing the GenerateGeodatabaseParameters
to the GeodatabaseSyncTask::generateGeodatabase()
method on the GeodatabaseSyncTask
class. Run the job to generate and download the geodatabase to the device.
void OfflineMapsScenesAndData::setupOfflineLayerTask()
{
// Create a new geodatabase sync task to generate the offline geodatabase using the supplied Url.
m_geodatabaseSyncTask = new GeodatabaseSyncTask(m_featureServiceUrl, this);
// After the task loads, get the default parameters for generating a geodatabase.
connect(m_geodatabaseSyncTask, &GeodatabaseSyncTask::doneLoading, this, [this](Error error)
{
if (!error.isEmpty()) // Test if there are any errors and relay that info.
{
qDebug() << "Error loading GeodatabaseSyncTask:" << error.message() << ":" <<
error.additionalMessage();
}
else // No errors, continue.
{
// Get the viewpoint of the map.
const Viewpoint viewpoint = m_map->initialViewpoint();
// Get the geometry of the viewpoint.
const Geometry geometry = viewpoint.targetGeometry();
// Get the envelope from the geometry's extent.
const Envelope envelope = geometry.extent();
// Execute the geodatabase sync task's create default generate geodatabase parameters
// async method using the supplied envelope. It returns a generate geodatabase
// parameters object.
m_geodatabaseSyncTask->createDefaultGenerateGeodatabaseParametersAsync(envelope).then(this,
[this] (const GenerateGeodatabaseParameters& parameters)
{
// Call the custom generate function.
generate(parameters);
});
}
});
// Call the geodatabase sync task load event.
m_geodatabaseSyncTask->load();
}
void OfflineMapsScenesAndData::generate(GenerateGeodatabaseParameters generateGeodatabaseParameters)
{
// Create the marine animal layer option object.
GenerateLayerOption marineAnimalLayerOption;
// Set the marine animal layer option's layer id to 0.
marineAnimalLayerOption.setLayerId(0);
// Set the marine animal layer option's where clause to the string "type = 11".
marineAnimalLayerOption.setWhereClause(QString("type = 11")); // dolphins only
// Create the bird layer option object.
GenerateLayerOption birdLayerOption;
// Set the bird layer option's layer id to 0.
birdLayerOption.setLayerId(1);
// Set the generate geodatabase parameters layer option to the QList of the two
// generate layer options.
generateGeodatabaseParameters.setLayerOptions(QList {marineAnimalLayerOption, birdLayerOption});
// Set the generate geodatabase parameter's sync model to 'Layer' - we want to support
// per-layer sync with this geodatabase.
generateGeodatabaseParameters.setSyncModel(SyncModel::Layer);
// Don't need attachments from the service in the geodatabase.
generateGeodatabaseParameters.setReturnAttachments(false);
// Create the job and start it. Output geodatabase goes into a specified file.
m_generateGeodatabaseJob = m_geodatabaseSyncTask->generateGeodatabase(
generateGeodatabaseParameters, m_pathToGeodatabaseFile);
// Connect to the generate geodatabse job's job done event.
connect(m_generateGeodatabaseJob, &GenerateGeodatabaseJob::jobDone, this, [this]()
{
// Test if have any errors and broadcast it to the user.
if (!m_generateGeodatabaseJob->error().isEmpty())
{
qDebug() << "Job completed with error:" << m_generateGeodatabaseJob->error().message()
<< ":" << m_generateGeodatabaseJob->error().additionalMessage();
}
else
{
// The job done event completed successfully.
qDebug() << "Job complete, geodatabase at " << m_pathToGeodatabaseFile;
}
});
// Connect to the generate geodatabase job's error occured event.
connect(m_generateGeodatabaseJob, &GenerateGeodatabaseJob::errorOccurred, this, [](Error error)
{
// Test if have any errors and broadcast the issue.
if (!error.isEmpty())
{
qDebug() << "Error running job:" << error.message() << ":" << error.additionalMessage();
}
});
// Call the generate geodatabase job start event.
m_generateGeodatabaseJob->start();
// Provide some feedback.
qDebug() << "Job is starting";
}
If you generate the geodatabase using these methods, it will automatically register the geodatabase with its original service. This allows the data in the geodatabase to be synchronized with the original service. If you want to load this geodatabase onto a number of devices and allow those users to synchronize changes with the original service, you must register these individual geodatabases with the original service.
Create layers from geodatabase feature tables
Now that you have a geodatabase on your local machine or device, you'll create the relevant layer from the geodatabase feature tables.
- Get the geodatabase from the generate geodatabase job.
- Load the geodatabase.
- Create feature layers from the geodatabase feature tables.
- Create annotation layers from the geodatabase annotation tables.
// Create the generate geodatabase job, pass in the parameters and an output path for the
// local geodatabase.
GenerateGeodatabaseJob* generateGeodatabaseJob = m_geodatabaseSyncTask->generateGeodatabase(params,
"path/to/geodatabse/file");
// Connect to the generate geodatabse job's job done event.
connect(generateGeodatabaseJob, &Job::jobDone, this, [generateGeodatabaseJob, this]()
{
// Get the local geodatabase from the job result.
Geodatabase* geodatabase = generateGeodatabaseJob->result();
// Loop thru each feature table in the geodatabase feature tables.
for (FeatureTable* featureTable : geodatabase->geodatabaseFeatureTables())
{
// Create a new feature layer from the feature table.
FeatureLayer* featureLayer = new FeatureLayer(featureTable, this);
// Get the layer list model from the map's operational layers.
LayerListModel* layerListModel = m_map->operationalLayers();
// Add the feature layer to the layer list model.
layerListModel->append(featureLayer);
}
// Loop thru each ArcGIS feature table in the geodatabase annotation tables.
for (ArcGISFeatureTable* arcgisFeatureTable : geodatabase->geodatabaseAnnotationTables())
{
// Create an annotation layer for each feature table that contains annotation
// (annotation is stored in a ArcGISFeatureTable rather than the more generic FeatureTable).
AnnotationLayer* annotationLayer = new AnnotationLayer(arcgisFeatureTable, this);
// Get the layer list model from the map's operational layers.
LayerListModel* layerListModel = m_map->operationalLayers();
// Add the annotation layer to the layer list model.
layerListModel->append(annotationLayer);
}
});
// Call the generate geodatabase job start event.
generateGeodatabaseJob->start();
Tiled layers
Tiled layers typically provide geographical context to your map or scene as basemaps that display beneath your data layers. Tiled layers may also provide offline elevation data for visualizing 3D terrain in a scene. You can export and download tile caches directly to your device from any tiled data source that is export enabled. Esri provides a number of vector and raster basemaps for you to export and download:
- Download vector tiled data — ArcGIS vector tile services or vector basemaps in ArcGIS Online
- Download image tiled data — Tiled ArcGIS map services, tiled ArcGIS image services, or tiled basemaps and elevation sources in ArcGIS Online
Download vector tiled data
You can take vector tiled data offline by exporting it from an ArcGIS vector tile service and downloading it as a vector tile package (.vtpk
) using the ExportVectorTilesTask
class. The vector tile service used for this operation must support the creation of an offline vector tile cache; specifically, it must enable the export
operation. Vector tiles contain vector representations of data that can be restyled for different purposes, such as day and night viewing. You can download default styling resources along with the vector tiles and custom style resources from ArcGIS Portal items that host vector tile layers.
You have a number of workflows available to you depending on whether your vector tiled data has custom style resources, whether you want to download many custom styles that you can apply to a number of tile caches, or whether you just want to obtain the default tile cache.
To create a vector tile package (.vtpk
file) and vector tile style resources, do the following:
- Instantiate the export vector tiles task and check whether the vector tiles have custom style resources.
- Specify the export vector tiles task parameters for a specific maximum scale and area of interest.
- Export the vector tiles. The vector tile package is populated with vector tiles and the default style resources from the ArcGIS vector tile service.
Instantiate the export vector tiles task
Instantiate the ExportVectorTilesTask
using a URL to the portal item that represents an ArcGIS vector tiled layer. Load the task, and upon completion, check whether the vector tiles have custom style resources by checking the hasStyleResources
Boolean value.
// Connect to a portal (ArcGIS Online) to access a portal item ("Colored pencil" vector tile layer).
m_portal = new Portal(QUrl("https://www.arcgis.com"), this);
m_portalItem = new PortalItem(m_portal, "4cf7e1fb9f254dcda9c8fbadb15cf0f8", this);
// Initialize and load the export vector tile task with the portal item for a vector
// tiled layer.
m_exportVectorTilesTask = new ExportVectorTilesTask(m_portalItem, this);
// Wait for the task to be loaded, then query its members.
connect(m_exportVectorTilesTask, &ExportVectorTilesTask::doneLoading, this, [this]()
{
// Check if the vector tile layer has style resources.
bool hasStylesResources = m_exportVectorTilesTask->hasStyleResources();
if (hasStylesResources)
{
// Retrieve the export vector tiles parameters and export the vector
// tiles with custom style resources...
}
else
{
// Retrieve the export vector tiles parameters and export the vector
// tiles (with their default style)...
}
});
// Call the export vector tiles task load event.
m_exportVectorTilesTask->load();
Specify the export vector tiles task parameters
To obtain a default set of parameters, call the createDefaultExportVectorTilesParameters
method and provide an area of interest (polygon or envelope) and a maximum scale. When you provide the maximum scale, you must be aware that there won't be any tiles when the map is zoomed in beyond this scale. If you set the maximum scale to 0, the export will include all levels of detail in the service.
This method returns the set of default parameters, ExportVectorTilesParameters
, required to export the vector tiles to a vector tile package. The LODs have been calculated to support the maximum scale that you specified.
// Get a polygon from the map view's visible area.
const Polygon polygon = m_mapView->visibleArea();
// Get the map scale from the map view.
const double mapScale = m_mapView->mapScale();
// Execute the export vector tiles task's create default export vector tiles parameters async method
// using the supplied polygon and map scale. It returns an export vector tiles parameters object.
m_exportVectorTilesTask->createDefaultExportVectorTilesParametersAsync(polygon, mapScale).then(this,
[this](const ExportVectorTilesParameters& parameters)
{
// Define the path to the tile cache (.vtpk file).
const QString tileCachePath(QDir::toNativeSeparators(QDir::homePath() + "/VectorMapTiles.vtpk"));
// Broadcast some feedback.
qDebug() << QString("Saving the vector tiles in the path " + tileCachePath);
// Create the job from the default parameters and path to the local cache.
m_exportVectorTilesJob = m_exportVectorTilesTask->exportVectorTiles(parameters, tileCachePath);
// Export the vector tiles...
});
Export the vector tiles
Obtain a job to generate and download a vector tile package and its default style resources by passing the ExportVectorTilesParameters
to the exportVectorTiles
method on the ExportVectorTilesTask
class. You must also provide a download path to store the vector tile package and its default style resources.
Run the ExportVectorTilesJob
to export and download the vector tile package (.vtpk
).
// Start the export vector tiles job. Handle the job status change and examine
// the results when the job is done.
connect(m_exportVectorTilesJob, &ExportVectorTilesJob::jobDone, this, [this]()
{
// When the job succeeds, display the local vector tiles.
if (!m_exportVectorTilesJob->error().isEmpty())
{
// Broadcast any errors that occur.
qDebug() << m_exportVectorTilesJob->error().message() << ": " <<
m_exportVectorTilesJob->error().additionalMessage();
}
// Test if the export vector tales job succeded.
if (m_exportVectorTilesJob->jobStatus() == JobStatus::Succeeded)
{
// Create a vector tile cache and item resource cache from the result.
ExportVectorTilesResult* exportVectorTilesResult = m_exportVectorTilesJob->result();
VectorTileCache* vectorTileCache = exportVectorTilesResult->vectorTileCache();
// Create new vector tiled layer using the tile and resource caches.
m_arcgisVectorTileLayer = new ArcGISVectorTiledLayer(vectorTileCache, this);
// Create a new map with a basemap based on the ArcGIS vector tile layer.
m_map = new Map(new Basemap(m_arcgisVectorTileLayer, this), this);
// Set the new map on the map view.
m_mapView->setMap(m_map);
}
});
// Start the job.
m_exportVectorTilesJob->start();
Export the vector tiles with custom style resources
Obtain a job to generate and download a vector tile package containing tiles and associated style resources by passing the ExportVectorTilesParameters
to the exportVectorTiles
method on the ExportVectorTilesTask
class. The portal item's associated style resources will be downloaded and saved separately. You must also provide a download path to store the vector tile package and a separate download path for the style resources.
Run the job to export and download the vector tile package (.vtpk
) and the style resources to the device.
// Create a new export vector tiles task using a portal item.
m_exportVectorTilesTask = new ExportVectorTilesTask(m_portalItem, this);
// Get a polygon from the map view's visible area.
const Polygon polygon = m_mapView->visibleArea();
// Get the map scale from the map view.
const double mapScale = m_mapView->mapScale();
// Execute the export vector tiles task's create default export vector tiles parameters async method
// using the supplied polygon and map scale. It returns an export vector tiles parameters object.
m_exportVectorTilesTask->createDefaultExportVectorTilesParametersAsync(polygon, mapScale).then
(this, [this](const ExportVectorTilesParameters& parameters)
{
// Destination paths for the vector tile cache (.vtpk) and empty style resources folder.
const QString folder(QDir::toNativeSeparators(QDir::homePath()));
const QString tileCachePath(QDir::toNativeSeparators(folder + QString("/VectorMapTiles.vtpk")));
const QString resourcePath(QDir::toNativeSeparators(folder + QString(("/resources"))));
// Create the job from the parameters and paths to the local cache and resources.
ExportVectorTilesJob* exportVectorTilesJob = m_exportVectorTilesTask->
exportVectorTiles(parameters, tileCachePath, resourcePath);
// Handle job status change to check the status.
connect(exportVectorTilesJob, &ExportVectorTilesJob::jobDone, this, [this, exportVectorTilesJob]()
{
// Broadcast any errors that occur.
if (!exportVectorTilesJob->error().isEmpty())
qDebug() << exportVectorTilesJob->error().message() << ":" <<
exportVectorTilesJob->error().additionalMessage();
// Show the job status and progress.
if (exportVectorTilesJob->jobStatus() == JobStatus::Succeeded)
{
// Get the result from the job.
ExportVectorTilesResult* exportVectorTilesResult = exportVectorTilesJob->result();
// Create a vector tile cache and item resource cache from the result.
VectorTileCache* vectorTileCache = exportVectorTilesResult->vectorTileCache();
ItemResourceCache* itemResourceCache = exportVectorTilesResult->itemResourceCache();
// Create new vector tiled layer using the tile and resource cache.
ArcGISVectorTiledLayer* arcGISVectorTiledLayer = new ArcGISVectorTiledLayer(vectorTileCache,
itemResourceCache, this);
// Create a new basemap based on the ArcGIS vector tile layer.
Basemap* basemap = new Basemap(arcGISVectorTiledLayer, this);
// Create a new map using the basemap.
m_map = new Map(basemap, this);
// Set the map in the map view.
m_mapView->setMap(m_map);
}
});
// Start the job.
exportVectorTilesJob->start();
});
Export custom style resources
Obtain a job to download any custom style resources associated with the tasks vector tiles by passing a download path to the exportStyleResourceCache
method on the ExportVectorTilesTask
class.
Run the job to export the style resources. Obtain the itemResourceCache
property from the ExportVectorTilesResult
class.
// Create a new export vector tiles task with the portal item for a vector tiled layer.
m_exportVectorTilesTask = new ExportVectorTilesTask(m_portalItem, this);
// Create the destination path for the empty style resources folder.
const QString folder(QDir::toNativeSeparators(QDir::homePath()));
const QString resourcePath(QDir::toNativeSeparators(folder + QString("/resources")));
// Create the job from the path to the local resources.
ExportVectorTilesJob* exportVectorTilesJob = m_exportVectorTilesTask->
exportStyleResourceCache(resourcePath);
// Retrieve the local style resource cache when the job has completed.
connect(exportVectorTilesJob, &ExportVectorTilesJob::jobDone, this, [exportVectorTilesJob]()
{
// Broadcast any errors that occur.
if (!exportVectorTilesJob->error().isEmpty())
{
qDebug() << exportVectorTilesJob->error().message() << ": " << exportVectorTilesJob->
error().additionalMessage();
}
// Test if the export vector tiles job succedded.
if (exportVectorTilesJob->jobStatus() == JobStatus::Succeeded)
{
// Obtain the export vector tiles result from the export vector tiles job.
ExportVectorTilesResult* exportVectorTilesResult = exportVectorTilesJob->result();
// Get the item resource cache from the export vector tiles result.
ItemResourceCache* itemResourceCache = exportVectorTilesResult->itemResourceCache();
// Provide some feedback.
qDebug() << itemResourceCache->path();
}
});
// Call the export vector tiles job start event.
exportVectorTilesJob->start();
Download image tiled data
You can take image tiled data offline by exporting and downloading the image tiled data as a tile package (.tpk
or .tpkx
) using the ExportTileCacheTask
class. This task requires that the tiled map or image service support the creation of an offline tile cache; specifically, it must enable the export
operation. This can be found at the bottom of the service's HTML page. Esri provided basemaps and elevation sources will be swapped for their export-enabled services. To create the tile cache, do the following:
- Generate the default export image tile cache parameters and set any of the properties.
- Export and download the image tile cache using the methods on the
ExportTileCacheTask
.
Generate default export image tile cache parameters
Construct a default set of parameters (ExportTileCacheParameters
) by passing an area of interest (polygon or envelope) along with the minimum and maximum scale thresholds to the createDefaultExportTileCacheParameters
method on the ExportTileCacheTask
class.
This method will return a set of parameters for the area of interest and will calculate the levels of detail (LODs) required to support the minimum and maximum scale for the service's tiling scheme. You can adjust these LOD levels or remove some before you download the cache.