Learn how to download and display an offline map for a user-defined geographical area of a web map.
Offline maps allow users to continue working when network connectivity is poor or lost. If a web map is enabled for offline use, a user can request that ArcGIS generates an offline map for a specified geographic area of interest.
In this tutorial, you will download an offline map for an area of interest from the web map of the stormwater network within Naperville, IL, USA . You can then use this offline map without a network connection.
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Your system meets the system requirements.
Steps
Open the Xcode project
-
To start the tutorial, complete the Display a web map tutorial or download and unzip the solution.
-
Open the
.xcodeproj
file in Xcode. -
If you downloaded the solution, get an access token and set the API key.
An API Key gives your app access to secure resources used in this tutorial.
-
Go to the Create an API key tutorial to obtain a new API key access token. Ensure that the following privilege is enabled: Location services > Basemaps > Basemap styles service. Copy the access token as it will be used in the next step.
-
In Xcode, in the Project Navigator, click MainApp.swift.
-
In the Editor, set the
ArcGISEnvironment.apiKey
property on theArcGIS
with your access token.Environment MainApp.swiftUse dark colors for code blocks init() { ArcGISEnvironment.apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>") }
-
Get the web map item ID
You can use ArcGIS tools to create and view web maps. Use the Map Viewer to identify the web map item ID. This item ID will be used later in the tutorial.
-
Go to the Naperville water network in the Map Viewer in ArcGIS Online. This web map displays a stormwater network within Naperville, Illinois, USA.
-
Make a note of the item ID at the end of the browser's URL.
The item ID should be 5a030a31e42841a89914bd7c5ecf4d8f.
Display the web map
You can display a web map using the web map's item ID. Create an Map
from the web map's PortalItem
, and display it in your app's MapView
.
-
In Xcode, in the Project Navigator, click ContentView.swift.
-
In the editor, modify the
map
variable. Provide the web map's item ID.The code creates an
PortalItem
using thePortal
that references ArcGIS Online, and the web map'sitem
. TheID portal
is used to create anItem Map
that is displayed in the app'sMapView
.ContentView.swiftUse dark colors for code blocks 103 104 105 106 108 109 110Change line @State private var map = Map( item: PortalItem( portal: .arcGISOnline(connection: .anonymous), id: PortalItem.ID("5a030a31e42841a89914bd7c5ecf4d8f")! ) )
-
Create a private class named
Model
of typeObservable
and add aObject @
variable of theState Object Model
to theContent
. Make theView Model
the@
. See the programming patterns page for more information on how to manage states.Main Actor ContentView.swiftUse dark colors for code blocks 16 17 18 23 24 25 27 28 29 30 31 32 33 34 35Add line. Add line. Add line. Add line. Add line. import SwiftUI import ArcGIS @MainActor private class Model: ObservableObject { } struct ContentView: View { @StateObject private var model = Model() @State private var map = Map( item: PortalItem( portal: .arcGISOnline(connection: .anonymous), id: PortalItem.ID("5a030a31e42841a89914bd7c5ecf4d8f")! ) )
-
In the
Model
, create a@
variable namedPublished offline
of typeMap Map
to store the output of the downloaded map.ContentView.swiftUse dark colors for code blocks 19 20 21 23 24Add line. @MainActor private class Model: ObservableObject { @Published private(set) var offlineMap: Map! }
-
In the
Content
, modify the map view to display the model's offline map or the online map. IfView offline
has no value, then the map view should display the online map.Map ContentView.swiftUse dark colors for code blocks 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 113 114 115 116Change line struct ContentView: View { @StateObject private var model = Model() @State private var map = Map( item: PortalItem( portal: .arcGISOnline(connection: .anonymous), id: PortalItem.ID("5a030a31e42841a89914bd7c5ecf4d8f")! ) ) var body: some View { MapView(map: model.offlineMap ?? map) } }
Specify an area of the web map to take offline
Specify an area of the web map to take offline using either an Envelope
or a Polygon
. Use views
to obtain data about the map view and an overlay
to indicate the area on the map to be downloaded.
-
In the
Content
, wrap the map view inside aView MapViewReader
and expose theMapViewProxy
in its closure. Name itmap
.View Map
provides operations that can be performed on the map view, such asView Proxy envelope(from
. For more information see Perform GeoView operations.View Rect :) ContentView.swiftUse dark colors for code blocks 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 117 118 119 120Add line. Add line. Add line. Add line. Add line. struct ContentView: View { @StateObject private var model = Model() @State private var map = Map( item: PortalItem( portal: .arcGISOnline(connection: .anonymous), id: PortalItem.ID("5a030a31e42841a89914bd7c5ecf4d8f")! ) ) var body: some View { MapViewReader { mapView in MapView(map: model.offlineMap ?? map) } } }
-
Wrap the map view reader inside a
Geometry
and expose theReader Geometry
in its closure. Name itProxy geometry
.Geometry
provides access to the size and coordinate space (for anchor resolution) of the views enclosed in the geometry reader.Proxy ContentView.swiftUse dark colors for code blocks 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 121 122 123 124Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. struct ContentView: View { @StateObject private var model = Model() @State private var map = Map( item: PortalItem( portal: .arcGISOnline(connection: .anonymous), id: PortalItem.ID("5a030a31e42841a89914bd7c5ecf4d8f")! ) ) var body: some View { GeometryReader { geometry in MapViewReader { mapView in MapView(map: model.offlineMap ?? map) } } } }
-
Add an
.overlay
modifier to the map view. The overlay contains a red rectangle that encompasses an area to be downloaded.ContentView.swiftUse dark colors for code blocks 112 113 114 115 116 117 118 119 126 127 128 129 130 131Add line. Add line. Add line. Add line. Add line. Add line. var body: some View { GeometryReader { geometry in MapViewReader { mapView in MapView(map: model.offlineMap ?? map) .overlay { Rectangle() .stroke(.red, lineWidth: 2) .padding(EdgeInsets(top: 60, leading: 20, bottom: 100, trailing: 20)) .opacity(model.offlineMap == nil ? 1 : 0) } } } }
Download and display the offline map
Generate and download an offline map for a specified area of interest using an asynchronous task. When complete, it will provide the offline map that can be displayed in a map view.
-
In the
Model
, create a@
Published GenerateOfflineMapJob
variable calledgenerate
and aOffline Map Job OfflineMapTask
variable calledoffline
. These objects will contain the job and task needed to perform the download function. Learn more about Tasks and jobs.Map Task ContentView.swiftUse dark colors for code blocks 19 20 21 22 23 26 27Add line. Add line. @MainActor private class Model: ObservableObject { @Published private(set) var offlineMap: Map! @Published private(set) var generateOfflineMapJob: GenerateOfflineMapJob! private var offlineMapTask: OfflineMapTask! }
-
Create a
@
Boolean variable calledPublished is
and set it to true. Create a variable calledGenerate Disabled is
and set it to false. These variables will be used to determine if the download button is enabled and if the completion alert is present.Showing Alert ContentView.swiftUse dark colors for code blocks 19 20 21 22 23 24 25 26 29 6Add line. Add line. @MainActor private class Model: ObservableObject { @Published private(set) var offlineMap: Map! @Published private(set) var generateOfflineMapJob: GenerateOfflineMapJob! private var offlineMapTask: OfflineMapTask! @Published private(set) var isGenerateDisabled = true @Published var isShowingAlert = false }
-
Create a private
URL
property namedtemporary
. This property will generate a uniqueDirectory URL URL
at which to store the offline map on the device.ContentView.swiftUse dark colors for code blocks 19 20 21 22 23 24 25 26 27 28 29 39