# Create an offline map

ArcGIS Runtime allows your users to continue working and interacting with their maps and data if network connectivity is poor or non-existent. You can provide this capability with one of the following patterns:

• The Services pattern: If you want to build apps that allow your users to take a map offline from ArcGIS Online or ArcGIS Enterprise, use the Services pattern. When you take a map offline this way, you download to the device a web map as a mobile map package (.mmpk file). Your users can interact with this offline map, edit operational data, and, when connectivity is restored, synchronize changes with the online services. These tasks are undertaken by the app that you build. The Services pattern supports two workflows: a preplanned workflow, where the map's author creates the offline map, and an on-demand workflow, where the field worker creates the map.
• The Desktop pattern: In this pattern, you use ArcGIS Pro to author and create a read-only mobile map package file that you can deliver to individual devices.

Both patterns use the mobile map package format to take maps offline and transfer the maps between different ArcGIS platforms. The mobile map package format can exist as a single, .mmpkfile or as an unpacked directory format. Both formats use a common map definition that specifies how the map is displayed and how it can be used in an app on the device.

For details on these patterns, see Offline. If you want to take individual layers offline instead of the map, see Create an offline layer.

## Services pattern

The Services pattern allows you to build apps that can download areas of ArcGIS Online or ArcGIS Enterprise web maps to your device. Each map is stored as a mobile map within an unpacked mobile map package. Since the mobile map conforms to the web map specification, it is used by the API to reconstruct the map using basemap data, operational layers, symbology definitions, pop-up configurations, and other data that'se stored within the mobile map package. This pattern allows your users to edit their operational data and synchronize it with the online service when connectivity is restored. There are two workflows available:

• The Preplanned workflow: where the map author defines a map area and generates the offline map ahead of time; so that your field workers can download the map and take into the field.
• The On-demand workflow: where the field worker defines the map area, generates the offline map content, and downloads the map to their device.

These are described more fully in the Offline topic.

When a web map is created to be taken offline, the author must ensure that all services used by the map have been enabled for offline use. If this is not done, your offline map may not contain all the layers and tables that you expect.

### Enable services for offline use

The author of the web map must ensure that all services contained in the web map can be taken offline. You can set these options when publishing, or later using any of the service management tools.

#### Raster and vector tiled services

You can allow tiled services data to be downloaded and used offline by following the instructions here:

#### Feature services

You can allow feature service data to be downloaded, edited, and changes synchronized by following the instructions here:

The map author must confirm that ArcGIS Online can access these tiled and feature services. The services must have public access and be shared with everyone.

You can now adopt the Preplanned or On-Demand workflow and create the mobile map.

##### Note:

As of the 100.2 release, the Services pattern supports taking the following services offline:

• Tiled and vector tiled services that have the exportTiles capability enabled.
• Feature services that have sync enabled.
• Feature collections that are read only and are stored along with the map information.

## Preplanned workflow

The Preplanned workflow allows an organization to prepare a mobile map in advance of a field worker entering the field. To do this the map owner must create a map area that defines a specific geographical area of work and then generate the individual data files that comprise the mobile map package. This mobile map package resides in ArcGIS Online until the field worker is ready to download it. Once the download job has completed the field worker can disconnect the device and work with the map offline. This workflow is discussed in detail in the following steps:

Here are the steps required for this workflow:

### Create preplanned map areas

The Preplanned workflow allows you to create a mobile map, in advance, so that it can be downloaded by the field worker when they need it. To do this you need to specify the area of interest, create a map area from a web map and generate the data packages for each of the services defined in the web map. Use the ArcGIS REST API to create a mobile map as follows:

1. To create a map area you must run the Create Map Area task providing a bookmark or geographical extent as the area of interest. Upon completion the task will generate a new portal item of type MapArea. This task requires that the web map is enabled for offline use and is only available to the owner of the web map and organization administrators.
2. To create the data defined by the map area you must run the Setup Map Area task providing the map area portal item ID. This will create a set of data files such as tile packages, vector tile packages and SQLite geodatabases. For good data management, we strongly recommend that you also provide a folder to organize these files. This task is only available to the map area portal item owner and organization administrators

##### Note:
The map's author can repeat these steps and create up to 16 individual map areas per web map.

The preplanned map areas and their related data are now ready to be downloaded to a device. This download phase is carried out by the Runtime app that you build.

### Identify a map area to download

As discussed above, each web map can provide one or more preplanned map areas. You may wish to build an app that allows the field worker to select and download a map area or you may wish to use the app logic to download a specific map area for the field worker. For either approach follow these steps:

1. Instantiate the offline map task by passing either a map (created from a web map) or a web map's portal item to the OfflineMapTask constructor.
2. Retrieve a list of the preplanned map areas from the web map.
3. Identify and select a map area.

// open map from a portal item
map = new ArcGISMap(portalItem);

// create an offline map task

//get all of the preplanned map areas in the web map
ListenableFuture<List<PreplannedMapArea>>  mapAreasFuture = offlineMapTask.getPreplannedMapAreasAsync();
try {
// get the list of areas
List<PreplannedMapArea> mapAreas = mapAreasFuture.get();

// loop through the map areas
for (PreplannedMapArea mapArea : mapAreas) {
// load each map area
// get the map area geometry so the is can used to display a graphic on the map
Geometry areaGeometry = mapArea.getAreaOfInterest();

// get the area title so it can be used in a UI component
String areaTitle = mapArea.getPortalItem().getTitle();

// UI code for showing map areas goes here:
});

}

} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
}

To download a preplanned map area, you need to run a job that will download the unpacked mobile map package to the device. You create this job by passing the preplanned map area, PreplannedMapArea, and a destination directory on disk to the downloadPreplannedOfflineMap method on OfflineMapTask. For more details on how to work with jobs, see the Tasks and jobs topic.

When the DownloadPreplannedOfflineMapJob is finished, it will return an instance of DownloadPreplannedOfflineMapResult. If the hasErrors property is set to true then there was at least one table or layer that failed to be taken offline and indicates that a more detailed inspection of the results is needed.

If you want to use the offline map immediately, you can use the DownloadPreplannedOfflineMapResult.offlineMap.

// create an offline map task

// create the job

//start the job

// listen for job complete

// check for errors
// code here to examine errors:

} else {
// no errors so use the map straight away

}
});

If you want to open the map offline while in the field, load the unpacked mobile map package stored in the downloadDirectory.

##### Note:

At ArcGIS Runtime SDK version 100.2, the Preplanned workflow is available in ArcGIS Online. This will become available in upcoming releases of ArcGIS Enterprise.

## On-demand workflow

The On-demand workflow allows a field worker to define the exact area of a map that they wish to take into the field. Although, the online map's author must create the web map and ensure that any services that are going to be taken offline have been enabled for offline use, the field worker controls area of interest, the max and min scale and many other parameters. Once the job to generate the map and download it to the device has completed the field worker can disconnect the device and work with the map offline. This workflow is discussed in detail in the following steps:

### Specify parameters

When you create an offline map, use the GenerateOfflineMapParameters class to control:

A set of default parameters (GenerateOfflineMapParameters) is created using the createDefaultGenerateOfflineMapParametersAsync method on OfflineMapTask. This method also loads the map's portal item, and copies its metadata to the itemInfo property, in preparation for copying it to an offline map.

// Create default parameters
final ListenableFuture<GenerateOfflineMapParameters> parametersFuture =
try {
GenerateOfflineMapParameters parameters = parametersFuture.get();

// Update the parameters if needed
// Limit maximum scale to 5000 but take all the scales above (use 0 as a MinScale)
parameters.setMaxScale(5000);

// only upload attachments from the client
// only include attachments with editable layers
parameters.setReturnLayerAttachmentOption(ReturnLayerAttachmentOption.EDITABLE_LAYERS);
// Request the table schema only (existing features won't be included)
parameters.setReturnSchemaOnlyForEditableLayers(true);

// Update the title to contain the region
parameters.getItemInfo().setTitle(parameters.getItemInfo().getTitle() + " (Central)");

// Override thumbnail with the new image based on the extent
final ListenableFuture<Image> exportImageFuture = mapView.exportImageAsync();
try {
Image exportImage = exportImageFuture.get();
// scale to thumbnail size
ImageView exportImageView = new ImageView(exportImage);
exportImageView.setFitWidth(200);
exportImageView.setFitHeight(133);
Image thumbnail = exportImageView.snapshot(null, null);
// convert to byte[]
BufferedImage thumbnailBuffered = SwingFXUtils.fromFXImage(thumbnail, null);
ByteArrayOutputStream thumbnailStream = new ByteArrayOutputStream();
ImageIO.write(thumbnailBuffered, "png", thumbnailStream);
byte[] thumbnailBytes = thumbnailStream.toByteArray();
thumbnailStream.close();

parameters.getItemInfo().setThumbnailData(thumbnailBytes);
} catch (Exception e) {
e.printStackTrace();
}
});

// ... add code below to:
//  - Create map's metadata properties
//  - Examine map's offline capabilities
//  - Generate and download the offline map
//  - Open and use the offline map
} catch (Exception e) {
e.printStackTrace();
}
});

#### Area of interest

The size of an offline map directly affects the time it takes to generate the offline map and download it to a device. Since the generation and download speed is directly proportional to the size of the map, you should limit the map's geographical area to just the area that you need. You can define this area by passing a Geometry object to the areaofInterest property.

##### Note:

We recommended that the area of interest is in the same spatial reference as the map to be taken offline. Without this, the layers may not be visible after the offline map is generated.

#### Scale range

Tiled layers are comprised of many tiles at different levels of detail. For a particular area of interest, the amount of space, generation time, and download time will increase significantly with every increased level of detail. It's strongly recommended that you only download the levels of detail that are relevant for your app. You can control this by setting the minimum and maximum scale parameters (minScale and maxScale). If possible, choose a maximum scale that is not too “zoomed in”, as this will generate a large number of unnecessary tiles.

##### Note:

Each service has a limit to the number of tiles which can be taken offline. It's recommended that you always set a scale range to avoid hitting this limit.

#### Inclusion of the map's basemap

In some workflows, you may want to exclude the basemap from the map and only take the operational layers offline. This provides a smaller file size, faster package generation, and a reduced download time. If you set the includeBasemap property to false, the OfflineMapTask will ignore all the layers included as part of the ArcGISMap's basemap.

If you exclude the basemap from your offline map, you will need to add a basemap into your map after it has been loaded. For example, if you have a workflow where you are sideloading a basemap to the device, there is no need to generate and download a basemap with every offline map. You can just add it as a basemap to your offline map.

#### Inclusion of feature attachments

Some feature services can add attachments (pictures, videos, and other documents) to individual features. Since these files can be large, you should consider your app's offline workflow to determine whether the attachments are needed by the app, and whether attachments need to be synchronized with the service when the app is next online. These two behaviors work in conjunction with each other, and are defined using the returnLayerAttachmentOption and attachmentSyncDirection properties on the GenerateOfflineMapParameters class.

• The return layer attachment property defines which layers should contain attachments in the offline map. The options are:
• NONE- None of the layers will contain any attachments.
• ALL_LAYERS - All layers will have their attachments included.
• READ_ONLY_LAYERS - Layers without editing enabled will have attachments included.
• EDITABLE_LAYERS - Layers with editing enabled will have attachments included.
• The attachment sync direction defines how the attachments are synchronized with the service. The options are:
• NONE - Attachments are not synchronized as part of the synchronization operation.
• UPLOAD - Attachments are uploaded from the client to the service, but any changes on the service are not downloaded to the client.
• BIDIRECTIONAL - Attachments are uploaded from client to the service, and changes on the service are pulled down to the client.
##### Note:

Attachment sync direction was introduced with ArcGIS Server 10.4.

Here are some workflows that describe how these two parameters affect each other.

• Workflow 1 - Download attachments for all layers in the map, allow the user to add or remove attachments from the layers, and then synchronize these changes between the service and the client when online. For example: multiple users collect data on the same area and they want to synchronize all the changes with the centralized services as well as sharing changes with other people in the field.
• returnLayerAttachmentOption.ALL_LAYERS
• attachmentSyncDirection.BIDIRECTIONAL
• Workflow 2 - Download attachments for all read-only layers and update these layers when online. For example: users are offline and viewing a layer of buildings with photos that show how the buildings look. If there are any new photos added to the service, these will be downloaded to the client during synchronization when online.
• attachmentSyncDirection.BIDIRECTIONAL
• Workflow 3 - Download attachments for editable layers only and upload them to the service when online. For example: users are offline and only need to view attachments for editable layers. If there are any read-only layers that provide context for the map, their attachments aren’t included to the local map. If users remove or add any new attachments, these changes can be synchronized to the service when online.
• returnLayerAttachmentOption.EDITABLE_LAYERS
• attachmentSyncDirection.BIDIRECTIONAL
• Workflow 4 - Do not download any attachments but allow any new attachments to be uploaded to the service when online. For example: users are offline and collecting new attachments in the field but do not need to view existing attachments.
• returnLayerAttachmentOption.NONE

#### Inclusion of features from editable feature layers

If users are collecting new information in the field where they do not need to access previously created features, you can create an offline map with empty editable feature layers. Do this by setting the GenerateOfflineMapParameters property returnSchemaOnlyForEditableLayers to true.

#### Inclusion of the map's metadata

You can access an online map's metadata from the itemInfo property. It includes portal item properties such as the title, description, short description, and thumbnail. This information is populated from the portal item that contains the map. Get this metadata by creating the GenerateOfflineMapParameters using the createDefaultGenerateOfflineMapParameters method on the OfflineMapTask. You can override any of these metadata properties before you take the map offline. For example, if you are creating offline maps of different areas of interest on the same map, you may want to change the map's title to indicate which area it contains.

You can also create a new OfflineMapItemInfo and manually set all the details.

// Create new item info
final OfflineMapItemInfo itemInfo = new OfflineMapItemInfo();

// Create new thumbnail from the map
final ListenableFuture<Image> exportImageFuture = myMapView.exportImageAsync();
try {
Image mapImage = exportImageFuture.get();
// scale to thumbnail size
ImageView mapImageView = new ImageView(mapImage);
mapImageView.setFitWidth(200);
mapImageView.setFitHeight(133);
Image thumbnail = mapImageView.snapshot(null, null);
// convert to byte[]
BufferedImage thumbnailBuffered = SwingFXUtils.fromFXImage(thumbnail, null);
ByteArrayOutputStream thumbnailStream = new ByteArrayOutputStream();
ImageIO.write(thumbnailBuffered, "png", thumbnailStream);
byte[] thumbnailBytes = thumbnailStream.toByteArray();
thumbnailStream.close();

// Set values to the itemInfo
itemInfo.setThumbnailData(thumbnailBytes);
itemInfo.setTitle("Water network (Central)");
itemInfo.setSnippet(webmapItem.getSnippet()); // Copy from the source map
itemInfo.setDescription(webmapItem.getDescription()); // Copy from the source map
itemInfo.setAccessInformation(webmapItem.getAccessInformation()); // Copy from the source map

// Set metadata to parameters
parameters.setItemInfo(itemInfo);
} catch (Exception e) {
e.printStackTrace();
}
});

##### Note:

Upon loading the offline map, this metadata is accessible using the ArcGISMap.item property. In some situations, you may want to access the metadata from the mobile map package without having to load the map itself. You can do this using the MobileMapPackage.item property.

### Examine offline capabilities

There are many things that determine whether a map or its layers and tables can be taken offline. Use the getOfflineMapCapabilitiesWithParameters method of the offline map task to explore this information. If there are layers or tables that cannot be taken offline you will get a reason why. For example, if the target map is using an ArcGIS map image layer (ArcGISMapImageLayer), then an error will be returned stating that the layer type is not supported by the OfflineMapTask.

Although this step is optional, it's recommended that you examine these capabilities as this will avoid unnecessary work on the services side. It's not recommended that you take a map offline unless all its layers and tables can be taken offline, because the map will not be complete as originally designed. If you do take a map offline anyway, you should be aware of which layers or tables are missing from the offline map.

final ListenableFuture<OfflineMapCapabilities> offlineMapCapabilitiesFuture =
try {
OfflineMapCapabilities offlineMapCapabilities = offlineMapCapabilitiesFuture.get();
if (offlineMapCapabilities.hasErrors()) {
// Handle possible errors with layers
for (java.util.Map.Entry<Layer, OfflineCapability> layerCapability : offlineMapCapabilities.getLayerCapabilities().entrySet()) {
if (!layerCapability.getValue().isSupportsOffline()) {
System.err.print(layerCapability.getKey().getName() + " cannot be taken offline.");
System.err.println("Error : " + layerCapability.getValue().getError().getMessage());
}
}

// Handle possible errors with tables
for (java.util.Map.Entry<FeatureTable, OfflineCapability> tableCapability : offlineMapCapabilities.getTableCapabilities().entrySet()) {
if (!tableCapability.getValue().isSupportsOffline()) {
System.err.println(tableCapability.getKey().getTableName() + " cannot be taken offline.");
System.err.println("Error : " + tableCapability.getValue().getError().getMessage());
}
}
} else {
// All layers and tables can be taken offline!
System.out.println("All layers are good to go!");
}
} catch (Exception e) {
e.printStackTrace();
}
});

### Generate and download the offline map

You need to run a job to generate an offline map. You can create this job by passing the GenerateOfflineMapParameters and a destination path on disk to the generateOfflineMapJob method on OfflineMapTask. Running this job will create an offline map, using the specified parameters, to the path on disk. To see more details on how to work with jobs in general, see the Tasks and jobs topic.

When the GenerateOfflineMapJob is finished, it will return an instance of GenerateOfflineMapResult. If the hasErrors property is set to true then there was at least one table or layer that failed to be taken offline. This indicates whether a more detailed inspection of the results is needed.

If you want to use the offline map immediately, you can use the GenerateOfflineMapResult.offlineMap.

// Create default parameters
// GenerateOfflineMapParameters parametersFuture
final ListenableFuture<GenerateOfflineMapParameters> parametersFuture =
try {
GenerateOfflineMapParameters generateOfflineMapParameters = parametersFuture.get();

// Create and start a job to generate the offline map
final GenerateOfflineMapJob generateOfflineJob =
generateOfflineJob.start();
// Generate the offline map and download it
GenerateOfflineMapResult result = generateOfflineJob.getResult();

if (!result.hasErrors()) {
MobileMapPackage mobileMapPackage = result.getMobileMapPackage();
// Job is finished and all content was generated
System.err.println("Map " + mobileMapPackage.getItem().getTitle() +
" saved to " + mobileMapPackage.getPath());

// Show offline map in a MapView
myMapView.setMap(result.getOfflineMap());
} else {
// Job is finished but some of the layers/tables had errors
if (result.getLayerErrors().size() > 0) {
for (java.util.Map.Entry<Layer, ArcGISRuntimeException> layerError : result.getLayerErrors().entrySet()) {
System.err.print("Error occurred when taking " + layerError.getKey().getName() + " offline.");
System.err.println("Error : " + layerError.getValue().getMessage());
}
}
if (result.getTableErrors().size() > 0) {
for (java.util.Map.Entry<FeatureTable, ArcGISRuntimeException> tableError : result.getTableErrors().entrySet()) {
System.err.print("Error occurred when taking " + tableError.getKey().getTableName() + " offline.");
System.err.println("Error : " + tableError.getValue().getMessage());
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
});

If you want to open a map offline in the field, open the unpacked mobile map package stored in the downloadDirectory and access the map.

### Limitations

• Advanced symbols are supported only if they are defined in the original service. Any overrides with advanced symbols will result in empty symbols in an offline map.
• Area-of-interest geometries that cross the dateline are not currently supported.
• If more than one feature layer in a map refers to the same feature service endpoint, only one feature layer will be taken offline. The other feature layers will raise an error.

## Open Services based mobile map packages

Offline maps created by the Preplanned workflow, the On-demand workflow are stored in an unpacked mobile map package. When your app goes into the field you will need to open the map directly from the mobile map package directory stored on your device. To create the mobile map package object, pass the mobile map package directory path to the MobileMapPackage constructor.

// Create a MobileMapPackage from the offline map directory path
final MobileMapPackage offlineMapPackage = new MobileMapPackage(mMobileMapPackage);
@Override
public void run() {
// Get the title from the package metadata
System.out.println("Title: " + offlineMapPackage.getItem().getTitle());

// Get the map from the package and set it to the MapView
mMapView.setMap(offlineMapPackage.getMaps().get(0));
}
});

See Display a map for more details on how to access and display maps stored in mobile map packages.

## Desktop pattern

The desktop pattern is based on self-contained read-only mobile map packages files that you create with ArcGIS Pro. The mobile map package (*.mmpk file) can contain many maps, their layers and their associated data such as geodatabases, tile packages, raster datasets, as well as network datasets and locators. Each mobile map package adheres to a common map definition thus allowing it to operate as a transfer mechanism to transports maps and data across the ArcGIS platforms. For more details on creating mobile map packages using ArcGIS Pro see Create Mobile Map Package.

##### Note:
If you'd like ready-to-use and regularly updated basemaps, locators, or network datasets for your area of interest, you can license StreetMap Premium data in mobile map package format. For details, see Add StreetMap Premium data.

### Access the mobile map package

Mobile map packages created by ArcGIS Pro can be opened directly from the mobile map package file (*.mmpk) or from an unpacked directory. If the mobile map package does not contain a raster dataset then you can open the mobile map package directly from the file. If the mobile map package contains a raster dataset then you must unpack the mobile map package to a directory first before you open it into your app.

##### Note:

You can package a raster dataset into a mobile map package with version 2.1 or higher of ArcGIS Pro. These mobile map packages can be read with version 100.2.1 or higher of ArcGIS Runtime.

Most mobile map package files do not contain a raster dataset so they can be read directly by instantiating the mobile map package directly from the file. You can confirm whether you can read the mobile map package directly by checking the value returned by MobileMapPackage.isDirectReadSupportedAsync. We recommend that you check this before attempting to open the mobile map package. Reading the file directly will save space on the device and time for the unpack process to complete.

An error will be thrown if you try to load a mobile map package file where direct read is not supported. The supplied error message will advise you to unpack the mobile map package file.

### Unpack

If your mobile map package contains a raster dataset it cannot be read directly. It must be unpacked into a directory location first. Check this by examining the value of MobileMapPackage.isDirectReadSupportedAsync. If direct reading is not supported call the unpack method to unpack the mobile map package file (*.mmpk) into a directory. You can then instantiate mobile map package using this mobile map package directory location.

Unpacking a mobile map package file into a directory obviously occupies space. To avoid an unpacking error you may want to confirm that the device has sufficient space before you unpack the mobile map package file. To save space you could delete the original mobile map package file after unpacking completes (unless you need this file for another purpose).

## Open Desktop based mobile map packages

If a mobile map package file has been provided by ArcGIS Pro (Desktop pattern) we strongly recommend that you confirm whether the mobile map package can be read directly before you attempt to read it. If it cannot be read directly then you must unpack the mobile map package into a directory before accessing it.

// Check whether the mobile map package supports direct read
@Override public void run() {
// Get the result of the future
boolean directReadSupported = false;
try {
} catch (InterruptedException | ExecutionException e) {
dealWithException(e);
}

// If the mobile map package supports direct read
// Create the mobile map package from the .mmpk file
MobileMapPackage mobileMapPackage = new MobileMapPackage(mmpkFileURL);
} else {

// If the mobile map package file does NOT support direct read
// Unpack the mobile map package file into a directory
MobileMapPackage.unpackAsync(mmpkFileURL, mmpkDirectoryURL);

// Create the mobile map package from the unpack directory
MobileMapPackage mobileMapPackage = new MobileMapPackage(mmpkDirectoryURL);
}
}
});

Once you have instantiated and loaded the mobile map package you can access any of the maps within the package and display them by passing them to the map view.

mobileMapPackage.addDoneLoadingListener(new Runnable() {
@Override public void run() {
mobileMapPackage.loadAsync();