In this workflow, you will learn how to prepare a web map for offline use, define areas in the map for offline use, then use it to create a partially offline app. This is also known as the ahead-of-time method because you are defining the offline areas in the map ahead of time.
Prerequisites
You need an account for ArcGIS Online or ArcGIS Enterprise to host data for offline use and get an access token. If you need an account, go to Get started.
Steps
1. Prepare the map and data
Create a web map
To create a web map with the Map Viewer, start by setting the basemap layer. Use the Streets vector tile basemap layer.
-
Open the Map Viewer and sign into your ArcGIS account.
-
In the left-panel, click Layers > Add.
- Click the My content dropdown and select ArcGIS Online.
- In the search box, type World Street Map (for Developers).
- Click on the resulting Tile Layer from Esri Vector Maps, then click Use as basemap.
-
In the left-panel, click Layers to close the window.
Set focus to an area of interest
To specify the viewpoint of the map to an area of interest, use the magnifier icon and set the map properties to preserve map scale.
-
In the bottom right panel, click the magnifier icon.
-
Type in
Santa Monica
in the search field and hit enter. This will set your map focus to an area of interest, which, in this case, is the city of Santa Monica, California. -
In the left panel, click Map properties.
-
Under Map view, toggle on the Preserve map scale. This will ensure that the map focus stays on the city of Santa Monica, California, even after you close the web map.
Your web map should look something like this.
Save the web map
Now that you have a web map, you need to save it to your portal.
-
In the left panel, click Save > Save as. At minimum, you need to provide a title and tags for your web map.
-
In the left panel, click Share map.
-
Select Everyone (public). Then, click Save.
Enable web map for offline use
-
In your web browser, find the item ID at the end of the URL for the web map you just saved.
- For example:
8ab76e9c5352400d87ca3315db9ba08e
- For example:
-
In a new browser tab, copy and paste the following URL and insert your item ID. This will return the item page for your web map, where you can configure it for offline use.
https
://www.arcgis.com/home/item.html?id= <ITEM _ID > - For example: https://www.arcgis.com/home/item.html?id=8ab76e9c5352400d87ca3315db9ba08e
-
Click Settings on the top bar of the item page.
-
Scroll down to the Offline menu.
-
If you don't see the Offline enabled icon at the top right corner, click Check Compatibility and turn on Offline.
-
Optionally, you can also manage advanced offline settings for your web map by clicking Options. These settings allow you to choose what data or updates mobile devices get and use a tile package for your offline basemap.
Under Features and attachments, you can configure download behaviors for both editable and read-only features. Adjusting how attachments and features are delivered can reduce the time it takes to synchronize edits, especially in areas of poor connectivity, as well as the amount of cellular data used.
Under Basemap and tile package, you can choose which basemap you want to use on your map. If you choose to use a local tile package, you will provide the filename of the package on your device. If you choose to use a tile package from your organization, you will browse a tile package from your ArcGIS organization.
-
Click Save. Your web map is enabled for offline use now.
Draw offline map areas
Now, you are going to define areas in your web map that you want to take offline, also known as offline map areas or preplanned map areas_.
-
Under Offline Map Areas, click Manage Offline Areas.
-
In the left panel, click Create offline area.
-
Draw an offline area on the map. You have two options to do this:
- To draw a box around the area to take offline, click the Sketch rectangular map area button and draw a box on the map.
- To draw a polygon to define the area you need to take offline, click the Sketch polygon map area button and draw the polygon on the map.
Manage offline map area settings
After defining your offline map areas, you can configure settings such as name, level of detail, and packaging schedule. Then, you will save the offline map area and an offline map package will be generated.
-
In the Name field in the left panel, type a descriptive name for the offline map area.
-
Open the Level of detail setting to change the quality and resolution of the downloaded raster or vector tile layers. You can move the slider to the right for more detail or to the left for less detail. Make sure that the small triangle icon is included in the scope of your slider.
Set a level of detail that is appropriate for the offline map area you create. If the level of detail is too great (for example, you set the level of detail to Streets but your offline map area is the size of Spain), you'll receive a warning indicating you must either reduce the offline map area or decrease the level of detail.
-
Open the Packaging schedule section to set the interval and time that you want the offline map area packages to be refreshed to capture changes to feature layer data. If you don't want to set an automatic refresh schedule, select Never from the drop-down menu.
-
Open the Optimizations section to create offline map area packages for read-only use. Then, switch on the Enable packaged updates toggle button. Read-only packages are created based on the schedule you set in the previous step.
-
Click Save.
The new offline map area appears in the Offline map areas list with a badge indicating the area is being packaged. Packaging can take several seconds or minutes, depending on the size of the data being packaged.
Packaging will fail if the size of the offline map area, when packaged, is larger than 2.5 GB. If packaging fails, try sketching a smaller area to include in the offline map package. If the map contains feature layers that have attachments, you can exclude attachments from the offline package to decrease the package size. If the map includes tile layers, you can decrease the size of the offline map area by adjusting the level of detail to include less detail.
-
To create more offline areas for this map, click Create offline area and repeat the previous steps starting from Draw offline map areas. You can create up to 16 offline map areas per web map.
2. Build the app
Setup offline app
-
Install and setup the ArcGIS Maps SDK for .NET on your development machine. Make sure you fulfill the SDK's system requirements.
-
Follow the Display a map tutorial or download the completed solution to get a starter code for this workflow.
-
Open the
.sln
file in Visual Studio.The Visual Studio solution, project, and the namespace for all classes currently use the name
Display
. Follow the steps below if you prefer the name to reflect the current tutorial. These steps are not required, your code will still work if you keep the original name.A Map -
Update the name for the solution and the project.
- In Visual Studio, in the Solution Explorer, right-click the solution name and choose Rename. Provide the new name for your solution.
- In the Solution Explorer, right-click the project name and choose Rename. Provide the new name for your project.
-
Rename the namespace used by classes in the project.
- In the Solution Explorer, expand the project node.
- Double-click MapViewModel.cs in the Solution Explorer to open the file.
- In the
Map
class, double-click the namespace name (View Model Display
) to select it, and then right-click and choose Rename....A Map - Provide the new name for the namespace.
- Click Apply in the Rename: DisplayAMap window that appears in the upper-right of the code window. This will rename the namespace throughout your project.
-
Build the project.
- Choose Build > Build solution (or press F6).
Download and display the offline map
-
In the Visual Studio > Solution Explorer, double-click MapViewModel.cs to open the file.
The project uses the Model-View-ViewModel (MVVM) design pattern to separate the application logic (view model) from the user interface (view).
Map
contains the view model class for the application, calledView Model.cs Map
. See the Microsoft documentation for more information about the Model-View-ViewModel pattern.View Model -
Add additional required
using
statements at the top of the class.MapViewModel.csUse dark colors for code blocks 2 3 4 5 6 7 8 9 10Add line. Add line. Add line. using System; using System.Collections.Generic; using Esri.ArcGISRuntime.Portal; using System.Text; using System.Threading.Tasks; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Linq; using Esri.ArcGISRuntime.Mapping; using Esri.ArcGISRuntime.Tasks.Offline;
-
Create an empty global variable
_download
to store the path to the downloaded map area later.Location MapViewModel.csUse dark colors for code blocks 30 31 32 33 34 35 36 37 38 39 40Add line. private string _downloadLocation; private Map? _map; public Map? Map { get { return _map; } set { _map = value; OnPropertyChanged(); } }
-
Modify the
Setup
function signature toMap private async
returning aTask
.MapViewModel.csUse dark colors for code blocks Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line Change line private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Remove the
Map
initializer from theSetup
function. Because the map area will be downloaded from the web map, this is no longer needed.Map MapViewModel.csUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Inside
Main
, remove the viewpoint configuration.Window.xaml.cs MainWindow.xaml.csUse dark colors for code blocks 37 38 39 40 43 44Remove line Remove line public MainWindow() { InitializeComponent(); MapPoint mapCenterPoint = new MapPoint(-118.805, 34.027, SpatialReferences.Wgs84); MainMapView.SetViewpoint(new Viewpoint(mapCenterPoint, 100000)); }
-
Get the web map item ID from your portal, for example
8ab76e9c5352400d87ca3315db9ba08e
. -
Create a
Map
from the web map using its item ID.MapViewModel.csUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Create an
Offline
referencing the web map. This task object reads the offline properties of the web map and manages downloading an offline map from it.Map Task MapViewModel.csUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Use the
Offline
to list any available ahead-of-time offline maps. In the ArcGIS Maps SDKs for Native Apps the ahead-of-time offline map areas are referred to as preplanned areas.Map Task MapViewModel.csUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Get a set of default
Download
. These parameters describe how the owner of the web map configured the offline map to be downloaded by default. You can modify the parameters to fine tune the downloaded offline map.Preplanned Offline Map Parameters MapViewModel.csUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Define a path to store the downloaded map area and store it in the global variable
_download
.Location MapViewModel.csUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Use the parameters to create a
Download
to download the offline map, specifying the download location.Preplanned Offline Map Job MapViewModel.csUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Start the job and wait for it to complete, returning a
Map
that is ready for use.MapViewModel.csUse dark colors for code blocks 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66private async Task GetOfflinePreplannedMap() { var portal = await ArcGISPortal.CreateAsync(); var portalItem = await PortalItem.CreateAsync(portal, "YOUR_ITEM_ID"); // Replace with your web map ID var map = new Map(portalItem); OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); IReadOnlyList<PreplannedMapArea> availableAreas = await offlineMapTask.GetPreplannedMapAreasAsync(); if (availableAreas?.FirstOrDefault() is PreplannedMapArea area) { DownloadPreplannedOfflineMapParameters downloadParameters = await offlineMapTask.CreateDefaultDownloadPreplannedOfflineMapParametersAsync(area); string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); _downloadLocation = System.IO.Path.Combine(documentsFolder, "OfflineMap"); DownloadPreplannedOfflineMapJob job = offlineMapTask.DownloadPreplannedOfflineMap(downloadParameters, _downloadLocation); DownloadPreplannedOfflineMapResult result = await job.GetResultAsync(); if (result?.OfflineMap is Map offlineMap) { this.Map = offlineMap; } } }
-
Click Debug > Start Debugging (or press F5 on the keyboard) to run the app.
Access the offline map
-
Inside
Map
, create aView Model.cs private async
function returning aTask
calledAccess
.Map() MapViewModel.csUse dark colors for code blocks Copy 68 69 70 71private async Task AccessMap() { }
-
Inside the function, create a
Mobile
that references the path to the downloaded offline map area.Map Package MapViewModel.csUse dark colors for code blocks 68 69 70 72 73Add line. private async Task AccessMap() { var mobileMapPackage = await MobileMapPackage.OpenAsync(_downloadLocation); }
-
Load the mobile map package and read the
Map
from it.MapViewModel.csUse dark colors for code blocks 68 69 70 71 72 74 76 77Add line. Add line. private async Task AccessMap() { var mobileMapPackage = await MobileMapPackage.OpenAsync(_downloadLocation); await mobileMapPackage.LoadAsync(); this.Map = mobileMapPackage.Maps.First(); }
-
The function is now ready to be called to access a previously downloaded offline map area. You can trigger this function from a UI button click or by calling it directly from the constructor.
-
Click Debug > Start Debugging (or press F5 on the keyboard) to run the app.