Use one of the ArcGIS Maps SDKs for Native Apps to define an area within the web map to take offline and display it in your offline application.
Prerequisites
- You need an ArcGIS Online or ArcGIS Enterprise account.
- You need to complete Step 3. Get an access token.
Steps
Set up offline app
In this step, choose the appropriate ArcGIS Maps SDK for your platform and set up your development environment.
-
Install and setup the ArcGIS Maps SDK for .NET on your development machine. Make sure you fulfill the SDK's system requirements.
-
Go to the Display a map tutorial and download the completed solution to get a starter code for this workflow.
You do not need to create another API key credential. -
Open the
.slnfile 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
Mapclass, 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).
-
Install and setup the ArcGIS Maps SDK for Kotlin on your development machine. Make sure you fulfill the SDK's system requirements.
-
Go to the Display a map tutorial and download the completed solution to get a starter code for this workflow.
You do not need to create another API key credential. -
Modify the old project for use in this new tutorial. Expand More info for instructions.
-
On your file system, delete the .idea folder, if present, at the top level of your project.
-
In the Android tool window, open app > res > values > strings.xml.
In the
<string name="appelement, change the text content to a title that suits your app objective._name" > -
In the Android tool window, open Gradle Scripts > settings.gradle.kts.
Change the value of
rootto a title that suits your app objective.Project.name -
The UI theme composable in Display a map tutorial was
Display. Rename the theme composable throughout the tutorial by refactoringA Map Theme Display.A Map Theme Right-click the function name
Displayand select Refactor -> Rename. Replace the name with a name that suits your app objective.A Map Theme -
Click File > Sync Project with Gradle files. Android Studio will recognize your changes and create a new .idea folder.
-
-
Install and setup the ArcGIS Maps SDK for Swift on your development machine. Make sure you fulfill the SDK's system requirements.
-
Go to the Display a map tutorial and download the completed solution to get a starter code for this workflow.
You do not need to create another API key credential.
-
Install and setup the ArcGIS Maps SDK for Qt on your development machine. Make sure you fulfill the SDK's system requirements.
-
Start Qt Creator.
-
Click File > New File or Project. Under Projects, select ArcGIS.
-
Select the ArcGIS Maps 200.4.0 Qt Quick C++ app project template (or a later version) and click Choose.
You may have several selections for the ArcGIS project type. Be sure to select ArcGIS Maps 200.4.0 Qt Quick C++ app (or a later version).
-
In the Project Location dialog, name your project something that fits your scenario, e.g. Display_an_offline_map. Click Next.
-
In the Define Build System dialog, select qmake for your build system. Click Next.
-
In the Define Project Details dialog, give this app a description or leave as is. Leave the rest of this dialog as is.
-
Leave the 3D project box unchecked. At the ArcGIS Online Basemap dropdown menu, select Streets. Then click Next.
-
On the Kit Selection dialog, check the kit(s) you previously set up when you installed the API. You should select a Desktop kit to run this tutorial. Then click Next.
-
At the Project Management dialog, the option to Add as a subproject to root project is only available if you have already created a root project. Ignore this dialog for this tutorial. Click Next.
-
Make sure your development machine meets the system requirements. Choose an applicable development platform to get started with installing Flutter, if necessary.
-
Go to the Display a map tutorial and download the completed solution to use as a starting point for this workflow.
You do not need to create another API key credential.
Set the access token
-
Paste the access token you copied in the previous step into your code.
App.xaml.csUse dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); // Note: it is not best practice to store API keys in source code. // The API key is referenced here for the convenience of this example. Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ApiKey = "YOUR_ACCESS_TOKEN"; } } }
-
Paste the access token you copied in the previous step into your code.
MainActivity.ktExpand Use dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32private fun setApiKey() { ArcGISEnvironment.apiKey = ApiKey.create("YOUR_ACCESS_TOKEN") }Expand
-
Paste the access token you copied in the previous step into your code.
MainApp.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36@main struct MainApp: App { init() { ArcGISEnvironment.apiKey = APIKey("YOUR_ACCESS_TOKEN") } var body: some SwiftUI.Scene { WindowGroup { ContentView() .ignoresSafeArea() } } }
-
Paste the access token you copied in the previous step into your code.
main.cppUse dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40// Use of Esri location services, including basemaps and geocoding, requires // an access token, see the doc: API key authentication // (https://developers.arcgis.com/documentation/security-and-authentication/types-of-authentication/) const QString apiKey = QString(""); // YOUR_ACCESS_TOKEN should be set here if (apiKey.isEmpty()) { qWarning() << "Use of Esri location services, including basemaps, requires" << "you to authenticate with an access token."; } else { ArcGISRuntimeEnvironment::setApiKey(apiKey); }
-
Paste the access token you copied in the previous step into your code.
main.dartUse dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179void main() { ArcGISEnvironment.apiKey = 'YOUR-ACCESS-TOKEN'; // Your access token here. runApp( const MaterialApp( home: CreateAppUsingWebMapOnDemand(), ), ); }
Download and display the offline map
Load the web map from your portal. Then, download and display it as an offline map in your app. The existing map from the downloaded solution will be replaced by 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).
Mapcontains 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
usingstatements at the top of the class.MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154using System; using System.Collections.Generic; using System.Text; using Esri.ArcGISRuntime.Geometry; using Esri.ArcGISRuntime.Mapping; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Esri.ArcGISRuntime.Portal; using Esri.ArcGISRuntime.Symbology; using Esri.ArcGISRuntime.Tasks.Offline; using Esri.ArcGISRuntime.UI; using System.Windows; using System.Diagnostics; using System.Drawing; -
Get the web map item ID from your portal, for example
4c4c3a28388446a19278b3a17051730e. -
In MapViewModel.cs, modify the
Setupfunction to update the web map's item IDMap() An item ID is a unique identifier representing a single item stored, managed, and accessed in a portal, such as a web map, hosted layer, or file.Learn more to that of the Santa Monica Parcels.The existing code creates a
Portalusing the item IDItem An item ID is a unique identifier representing a single item stored, managed, and accessed in a portal, such as a web map, hosted layer, or file.Learn more and aPortalreferencing ArcGIS OnlineArcGIS Online is a GIS mapping, analytics, data hosting, and content management software as a service (SaaS) product. It includes applications, tools, APIs, and location services for users and developers. It is subscription-based and requires an ArcGIS Online account.Learn more . It sets theMapproperty to a newView Model. Map Mapcreated using thePortal.Item MapViewModel.csUse dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154private async Task SetupMap() { // Create a portal pointing to ArcGIS Online. ArcGISPortal portal = await ArcGISPortal.CreateAsync(); // Create a portal item for a specific web map id. string webMapId = "YOUR_ITEM_ID"; // Replace with your web map ID PortalItem mapItem = await PortalItem.CreateAsync(portal, webMapId); // Create the map from the item. Map map = new Map(mapItem); // Set the view model "Map" property. this.Map = map; -
In the MapViewModel class, create a new property named
Graphics. This will be a collection ofOverlays Graphicsto display a graphicOverlay A graphic is a visual element composed of a geometry, symbol, and attributes that is displayed on a map or scene.Learn more of the area to take offline.Expand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154private Map? _map; public Map? Map { get { return _map; } set { _map = value; OnPropertyChanged(); } } private GraphicsOverlayCollection? _graphicsOverlays; public GraphicsOverlayCollection? GraphicsOverlays { get { return _graphicsOverlays; } set { _graphicsOverlays = value; OnPropertyChanged(); } }Expand -
Modify the
Setupfunction. Use anMap() Envelopeto create a newBuilder Envelopethat defines an area to take offline.MapViewModel.csExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154// Set the view model "Map" property. this.Map = map; // Define area of interest (envelope) to take offline. EnvelopeBuilder envelopeBldr = new EnvelopeBuilder(SpatialReferences.Wgs84) { XMin = -118.5064, XMax = -118.4800, YMin = 34.0094, YMax = 34.0259 }; Envelope offlineArea = envelopeBldr.ToGeometry();Expand -
Display a graphic of the area to take offline.
Use a
Simpleand aLine Symbol Simpleto display a newFill Symbol Graphicof theofflinewith a red outline. Add the graphic to a newArea Graphicsand set theOverlay Mapproperty to display it in the map view.View Model. Graphics Overlays MapViewModel.csExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154Envelope offlineArea = envelopeBldr.ToGeometry(); // Create a graphic to display the area to take offline. SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle.Solid, Color.Red, 2); SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle.Solid, Color.Transparent, lineSymbol); Graphic offlineAreaGraphic = new Graphic(offlineArea, fillSymbol); // Create a graphics overlay and add the graphic. GraphicsOverlay areaOverlay = new GraphicsOverlay(); areaOverlay.Graphics.Add(offlineAreaGraphic); // Add the overlay to a new graphics overlay collection. GraphicsOverlayCollection overlays = new GraphicsOverlayCollection { areaOverlay }; // Set the view model's "GraphicsOverlays" property (will be consumed by the map view). this.GraphicsOverlays = overlays;Expand -
In the Visual Studio > Solution Explorer, double-click MainWindow.xaml to open the file.
-
Use data binding to bind the
Graphicsproperty of theOverlays Mapto theView Model Mapcontrol.View Data binding and the Model-View-ViewModel (MVVM) design pattern allow you to separate the logic in your app (the view model) from the presentation layer (the view).
MainWindow.xamlExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25<esri:MapView x:Name="MainMapView" Map="{Binding Map, Source={StaticResource MapViewModel}}" GraphicsOverlays="{Binding GraphicsOverlays, Source={StaticResource MapViewModel}}" />Expand -
Return to the MapViewModel.cs file and add code to the
Setupfunction to create anMap Offlinethat references the online map by calling the staticMap Task Offlinemethod.Map Task. Create Async MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154// Set the view model's "GraphicsOverlays" property (will be consumed by the map view). this.GraphicsOverlays = overlays; // Create an offline map task using the current map. OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); -
Get default parameters to generate and download the offline map
An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more . Modify them to download a read-only offline map.This tutorial does not involve editing and updating the contents of the offline map. When an offline map is editable, metadata is stored in ArcGIS to track and synchronize edits. Setting the
GeneratetoOffline Map Update Mode Noavoids the overhead of maintaining this metadata in ArcGIS.Updates MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154// Create an offline map task using the current map. OfflineMapTask offlineMapTask = await OfflineMapTask.CreateAsync(map); // Create a default set of parameters for generating the offline map from the area of interest. GenerateOfflineMapParameters parameters = await offlineMapTask.CreateDefaultGenerateOfflineMapParametersAsync(offlineArea); parameters.UpdateMode = GenerateOfflineMapUpdateMode.NoUpdates; -
Set a download location for the offline map
An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more .MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154// Create a default set of parameters for generating the offline map from the area of interest. GenerateOfflineMapParameters parameters = await offlineMapTask.CreateDefaultGenerateOfflineMapParametersAsync(offlineArea); parameters.UpdateMode = GenerateOfflineMapUpdateMode.NoUpdates; // Build a folder path named with today's date/time in the "My Documents" folder. string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string downloadDirectory = System.IO.Path.Combine(documentsFolder, "OfflineMap_" + DateTime.Now.ToFileTime().ToString());This tutorial code creates a new unique folder in the documents folder using the current date and time.
-
Create a new
Generateusing theOffline Map Job parametersanddownload.Directory MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154// Build a folder path named with today's date/time in the "My Documents" folder. string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string downloadDirectory = System.IO.Path.Combine(documentsFolder, "OfflineMap_" + DateTime.Now.ToFileTime().ToString()); GenerateOfflineMapJob generateJob = offlineMapTask.GenerateOfflineMap(parameters, downloadDirectory); -
Create a function called
Generate. This function will respond when the job completes or fails and will track the percent complete as the job runs. Add aJob _Progress Changed try/catchblock to handle exceptions and start by getting a reference to theGenerate, passed in as theOffline Map Job senderargument.MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154// Build a folder path named with today's date/time in the "My Documents" folder. string documentsFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string downloadDirectory = System.IO.Path.Combine(documentsFolder, "OfflineMap_" + DateTime.Now.ToFileTime().ToString()); GenerateOfflineMapJob generateJob = offlineMapTask.GenerateOfflineMap(parameters, downloadDirectory); } private async void GenerateJob_ProgressChanged(object? sender, EventArgs e) { try { var generateJob = sender as GenerateOfflineMapJob; if(generateJob == null) { return; } } catch (Exception ex) { MessageBox.Show($"Error generating offline map: {ex.Message}"); } } -
If the job succeeds, set the
Mapproperty with the offline map result. If it fails, notify the user. If the job is running, write the percent complete to the console.View Model. Map MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154try { var generateJob = sender as GenerateOfflineMapJob; if(generateJob == null) { return; } // If the job succeeds, show the offline map in the map view. if (generateJob.Status == Esri.ArcGISRuntime.Tasks.JobStatus.Succeeded) { var result = await generateJob.GetResultAsync(); this.Map = result.OfflineMap; Debug.WriteLine("Generate offline map: Complete"); } // If the job fails, notify the user. else if (generateJob.Status == Esri.ArcGISRuntime.Tasks.JobStatus.Failed) { MessageBox.Show($"Unable to generate a map for that area: {generateJob?.Error?.Message}"); } else { int percentComplete = generateJob.Progress; Debug.WriteLine($"Generate offline map: {percentComplete}%"); } } catch (Exception ex) { MessageBox.Show($"Error generating offline map: {ex.Message}"); } -
Return to your code in
Setupand assign theMap Generatefunction to handle theJob _Progress Changed Job.event.Progress Changed() MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154GenerateOfflineMapJob generateJob = offlineMapTask.GenerateOfflineMap(parameters, downloadDirectory); generateJob.ProgressChanged += GenerateJob_ProgressChanged; -
Start the
generateby calling itsJob Startmethod.MapViewModel.csExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154GenerateOfflineMapJob generateJob = offlineMapTask.GenerateOfflineMap(parameters, downloadDirectory); generateJob.ProgressChanged += GenerateJob_ProgressChanged; generateJob.Start(); }Expand -
Click Debug > Start Debugging (or press F5 on the keyboard) to run the app.
-
In the Android tool window, open app > kotlin+java > com.example.app > screens > MainScreen.kt. Expand the code block below, and replace the existing import statements in your project with the imports needed for this tutorial.
MainScreen.ktExpand Use dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250import com.arcgismaps.geometry.Envelope import com.arcgismaps.geometry.Point import com.arcgismaps.geometry.SpatialReference import com.arcgismaps.mapping.ArcGISMap import com.arcgismaps.mapping.BasemapStyle import com.arcgismaps.mapping.MobileMapPackage import com.arcgismaps.mapping.PortalItem import com.arcgismaps.mapping.Viewpoint import com.arcgismaps.portal.Portal import com.arcgismaps.tasks.geodatabase.SyncDirection import com.arcgismaps.tasks.offlinemaptask.OfflineMapSyncTask import com.arcgismaps.tasks.offlinemaptask.OfflineMapTask import com.arcgismaps.toolkit.geoviewcompose.MapViewExpand -
Delete code from the Display a map tutorial that will not be used in this workflow.
Display a Map tutorialUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24@Composable fun MainScreen() { val map = remember { createMap() } Scaffold( topBar = { TopAppBar(title = { Text(text = stringResource(id = R.string.app_name)) }) } ) { MapView( modifier = Modifier.fillMaxSize().padding(it), arcGISMap = map ) } } fun createMap(): ArcGISMap { return ArcGISMap(BasemapStyle.ArcGISTopographic).apply { initialViewpoint = Viewpoint( latitude = 34.0270, longitude = -118.8050, scale = 72000.0 ) } } -
Create a
Mapclass. Inside it, create the properties shown in the code below.View Model map, which is initialized using thebykeyword and a mutable state ofArcGIS. The initial viewpoint is a zoomed out view, centered on Santa Monica.Map contextfor the application context.downloadto hold the path where the downloaded map will be stored on the file system of your device.Location download, which creates a directory using the download location and deletes the contents, if any, of the directory.Directory TAGto pass to the logging functions.
MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250class MapViewModel( private val application: Application, private val coroutineScope: CoroutineScope, ): AndroidViewModel(application) { var map by mutableStateOf(ArcGISMap(BasemapStyle.ArcGISStreets).apply { initialViewpoint = Viewpoint(Point(y = 34.008954, x = -118.496132, spatialReference = SpatialReference.wgs84()), scale = 100_000.0) }) val context = application.applicationContext private val downloadLocation by lazy { context.getExternalFilesDir(null)?.path + File.separator + "offlineMapOnDemand" } // Use the download path to create a directory. If the directory already exists, clear its contents. val downloadDirectory = File(downloadLocation).apply { // ensure the directory is empty before starting job if (isDirectory && exists()) { deleteRecursively() } } private val TAG = this.javaClass.name } -
In
Main, create the variables shown below. Note that theScreen mapvariable instantiates theView Model Mapclass.View Model MainScreenUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250@Composable fun MainScreen() { val application = LocalContext.current.applicationContext as Application val coroutineScope = rememberCoroutineScope() val mapViewModel = remember { MapViewModel(application, coroutineScope) } } -
In
Main, callScreen Scaffold, passing a top bar that displays the name of the app. Inside the content block, callColumn, which will hold the map view and three buttons.MainScreenUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250@Composable fun MainScreen() { val application = LocalContext.current.applicationContext as Application val coroutineScope = rememberCoroutineScope() val mapViewModel = remember { MapViewModel(application, coroutineScope) } Scaffold( topBar = { TopAppBar(title = { Text(text = stringResource(id = R.string.app_name)) }) } ) { Column( modifier = Modifier.fillMaxSize().padding(it) ) { } } -
Inside the content block for
Column, callMapand pass in the map from the map view model.View MainScreenUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250Scaffold( topBar = { TopAppBar(title = { Text(text = stringResource(id = R.string.app_name)) }) } ) { Column( modifier = Modifier.fillMaxSize().padding(it) ) { MapView( modifier = Modifier.fillMaxSize().weight(1f), arcGISMap = mapViewModel.map, ) } -
Add three buttons and call the appropriate map view model functions in the
oncallback. We will code those three functions in the rest of this workflow.Click MainScreenUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250MapView( modifier = Modifier.fillMaxSize().weight(1f), arcGISMap = mapViewModel.map, ) Button( onClick = { coroutineScope.launch { mapViewModel.downloadOfflineMapArea() } } ) { Text(text = "Download offline map area") } Button( onClick = { coroutineScope.launch { mapViewModel.accessOfflineMap() } } ) { Text(text= "Access offline map from local file") } Button( onClick = { coroutineScope.launch { mapViewModel.syncOfflineMap() } } ) { Text(text= "Synchronize") } -
The first button will download an area of interest from the Santa Monica Parcels web map.
-
Get the web map item ID from your portal, e.g.
4c4c3a28388446a19278b3a17051730e. -
In the
Mapclass, create a suspend function namedView Model Download. Inside the function, create the variables shown in the code below.Offline Map Area() - An arcgis.com
Portal. - A
Portalwith portal and the item ID.Item - An
Offlinewith the portal item.Map Task - An
area, which is anOf Interest Envelopespecifying the area of the web map to be taken offline.
- An arcgis.com
MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250suspend fun downloadOfflineMapArea() { val portal = Portal( url = "https://www.arcgis.com", connection = Portal.Connection.Anonymous ) val portalItem = PortalItem( portal = portal, itemId = "YOUR_ITEM_ID" // Replace with your web map ID ) val offlineMapTask = OfflineMapTask(portalItem) // Create an envelope that defines the area to take offline val areaOfInterest = Envelope( xMin = -118.5064, yMin = 34.0094, xMax = -118.4800, yMax = 34.0259, spatialReference = SpatialReference.wgs84() ) } -
-
Create default parameters for generating an offline map area on the server and and downloading the area to the file system of your device.
MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250val params = offlineMapTask.createDefaultGenerateOfflineMapParameters(areaOfInterest).getOrElse { error -> return showMessage(context, "No default parameters for generate offline map were created: ${error.message}") } -
Create a job that will generate the offline map area.
- Call
createand pass the default parameters and the path of the download directory.Generate Offline Map Job - In a coroutine scope, set up logging for the progress of the job.
- Start the job.
MainViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250// Create a job with GenerateOfflineMapParameters and a download directory path val generateOfflineMapJob = offlineMapTask.createGenerateOfflineMapJob( parameters = params, downloadDirectoryPath = downloadDirectory.path.toString() ) coroutineScope.launch { generateOfflineMapJob.progress.collect { progress -> Log.i(TAG, "Downloading offline map. Job progress: $progress%") } } // Start the job to download the offline map generateOfflineMapJob.start() - Call
-
From the result of the generate offline map job, get the downloaded offline map. Assign it to the
mapproperty ofMap.View Model MapViewModelExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250val jobResult = generateOfflineMapJob.result().getOrElse { error -> return showMessage(context, "Generate offline map job failed: ${error.message}") } map = jobResult.offlineMapExpand -
(Optional) The code in this workflow displays messages to the user and logs activity in Logcat. Here is a possible implementation.
MapViewModelExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250private fun showMessage(context: Context, message: String) { Toast.makeText(context, message, Toast.LENGTH_LONG).show() Log.i(TAG, message) }Expand -
Click Run > Run > app to run the app.
Initially, you should see the web map centered on Santa Monica, CA, zoomed in to a scale of 1:100,000.
Click the Download offline map area button. The download might take from a few seconds to a few minutes, depending on your internet connection and the load on the server.
After the offline map
An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more area is downloaded to the Android device, you will see an area of Santa Monica near the beach, zoomed in closer than the original view point.
-
In Xcode, in the Project Navigator, click ContentView.swift.
-
Create a
@Main Actor Modeland reference it fromView.ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123@MainActor private class Model: ObservableObject { } struct CreateAppBasemapOnDemandView: View { @StateObject private var model = Model() @State private var map = { let map = Map(basemapStyle: .arcGISTopographic) map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000) return map }() var body: some View { } } -
Move
maptoModeland use it inside theMap. Change theView Viewpointof the map to a latitude of34.0200, a longitude of-118.4685, and a scale of36._111.909643 ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123@MainActor private class Model: ObservableObject { @Published var map = { let map = Map(basemapStyle: .arcGISTopographic) map.initialViewpoint = Viewpoint(latitude: 34.0200, longitude: -118.4685, scale: 36_111.909643) return map }() } struct CreateAppBasemapOnDemandView: View { @StateObject private var model = Model() @State private var map = { let map = Map(basemapStyle: .arcGISTopographic) map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000) return map }() var body: some View { MapView(map: model.map) } } -
Inside
Model, create a function calledrunthat takes a path to store the downloaded web map as a parameter.Offline Map Task ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123func runOfflineMapTask(offlineMapURL: URL) async throws { } -
Define the area that you want to take offline on your web map using a
Polygon.ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123let areaOfInterest = Polygon(points: [ Point(x: -118.5064, y: 34.0259, spatialReference: .wgs84), Point(x: -118.4800, y: 34.0259, spatialReference: .wgs84), Point(x: -118.4800, y: 34.0094, spatialReference: .wgs84), Point(x: -118.5064, y: 34.0094, spatialReference: .wgs84) ]) -
Create a portal item representing the web map you just created, e.g.
4c4c3a28388446a19278b3a17051730e.ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123private let santaMonicaWebMap = PortalItem( portal: .arcGISOnline(connection: .anonymous), id: PortalItem.ID("YOUR_ITEM_ID")! // Replace with your web map ID ) -
Create an
Offlinereferencing the portal item. This task object reads the offline properties of the web map and manages downloading an offline mapMap Task An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more from it.ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123func runOfflineMapTask(offlineMapURL: URL) async throws { let offlineMapTask = OfflineMapTask(portalItem: santaMonicaWebMap) } -
Get a set of default
Generate Offline Map Parameters. These parameters describe how the owner of the web map configured the offline map to be generated and downloaded. You can modify the parameters to fine tune the downloaded offline map.Options include whether to download the basemap or use one that has already been downloaded, how to handle attachments, how to handle related records, whether to include data content for editable layers (useful if an offline application focuses on collection new data), and whether to disable offline editing even if the source web map supports editing.
If the map includes layers that use image tiles, then it is important to specify a scale range for downloaded image tiles. Use the overload constructor and specify minimum scale and maximum scale.
ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123func runOfflineMapTask(offlineMapURL: URL) async throws { let offlineMapTask = OfflineMapTask(portalItem: santaMonicaWebMap) let parameters = try await offlineMapTask.makeDefaultGenerateOfflineMapParameters(areaOfInterest: areaOfInterest) } -
Use the parameters to create a
Generate Offline Map Jobto download the offline mapAn offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more , specifying the download location.ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123func runOfflineMapTask(offlineMapURL: URL) async throws { let offlineMapTask = OfflineMapTask(portalItem: santaMonicaWebMap) let parameters = try await offlineMapTask.makeDefaultGenerateOfflineMapParameters(areaOfInterest: areaOfInterest) let job = offlineMapTask.makeGenerateOfflineMapJob(parameters: parameters, downloadDirectory: offlineMapURL) } -
Start the job and wait for it to complete, returning a
map, which is ready for use.ContentView.swiftExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123func runOfflineMapTask(offlineMapURL: URL) async throws { let offlineMapTask = OfflineMapTask(portalItem: santaMonicaWebMap) let parameters = try await offlineMapTask.makeDefaultGenerateOfflineMapParameters(areaOfInterest: areaOfInterest) let job = offlineMapTask.makeGenerateOfflineMapJob(parameters: parameters, downloadDirectory: offlineMapURL) let progressTask = Task { while !Task.isCancelled && job.status != .succeeded && job.status != .failed { print("Progress: \(Int(job.progress.fractionCompleted * 100))%") try? await Task.sleep(for: .seconds(1)) } } print("Starting download...") job.start() do { let output = try await job.output progressTask.cancel() print("Download complete!") print("Offline map loaded.") map = output.offlineMap } catch { progressTask.cancel() print(error) throw error } }Expand -
The function is now ready to be called to download an offline map area. You can trigger this function from the view's
.taskmodifier.ContentView.swiftExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123MapView(map: model.map) .task { do { let offlineMapURL = FileManager.default.temporaryDirectory .appendingPathComponent(UUID().uuidString) try await model.runOfflineMapTask(offlineMapURL: offlineMapURL) } catch { print("Offline map failed:", error) } }Expand
-
In Projects, double-click Headers > Display_an_offline_map.h to open the file. Add the following classes to the header file.
Display_an_offline_map.hUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71namespace Esri::ArcGISRuntime { class Map; class MapQuickView; class PortalItem; class OfflineMapTask; } -
Add the
generatefunction declaration and member variablesMap By Extent() mand_portal Item m. Save and close the file._offline Map Task Display_an_offline_map.hUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr; void generateMapByExtent(); Esri::ArcGISRuntime::PortalItem* m_portalItem = nullptr; Esri::ArcGISRuntime::OfflineMapTask* m_offlineMapTask = nullptr; }; -
In Projects, double-click Sources > Display_an_offline_map.cpp to open the file. Remove the
#includestatement forMapbecause the map will be provided by the offline map.Types.h Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203#include "Map.h" #include "MapQuickView.h" -
Add the following
#includestatements. These classes are needed for this application.Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203#include "MapQuickView.h" #include "Envelope.h" #include "EnvelopeBuilder.h" #include "Error.h" #include "GenerateOfflineMapParameters.h" #include "GenerateOfflineMapJob.h" #include "GenerateOfflineMapResult.h" #include "Graphic.h" #include "GraphicListModel.h" #include "GraphicsOverlay.h" #include "GraphicsOverlayListModel.h" #include "OfflineMapTask.h" #include "Portal.h" #include "PortalItem.h" #include "SimpleFillSymbol.h" #include "SimpleLineSymbol.h" #include "SpatialReference.h" #include "SymbolTypes.h" #include "TaskTypes.h" #include <QFuture> #include <QDir> #include <QUuid> -
Delete the comma after
Qand remove theObject(parent) Mapfrom the constructor.Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30using namespace Esri::ArcGISRuntime; Display_an_offline_map::Display_an_offline_map(QObject *parent): QObject(parent), m_map(new Map(BasemapStyle::ArcGISStreets, this)) -
Get the web map item ID from your portal, e.g.
4c4c3a28388446a19278b3a17051730e -
Instantiate a
Portaland from that, aPortalusing the web map item ID. Use that to create a newItem Map. Then create a newOfflinereferencing that portal item.Map Task Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203Display_an_offline_map::Display_an_offline_map(QObject *parent) : QObject{parent} { // Create a new portal using login required as false. Portal* portal = new Portal(false, this); // Create a new portal item using the portal and your web map item id. m_portalItem = new PortalItem(portal, "YOUR_ITEM_ID", this); // Create a new map using the portal item. m_map = new Map(m_portalItem, this); // Create a new offline map task using the portal item member variable. m_offlineMapTask = new OfflineMapTask(m_portalItem, this); -
Add the call to
generate.Map By Extent Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203// Set the view (created in QML) void Display_an_offline_map::setMapView(MapQuickView* mapView) { // Return if there is a problem with the map view member variable. if (!mapView || mapView == m_mapView) { return; } // Set the map view member variable to the map view. m_mapView = mapView; // Set the map on the map view member variable's to the map member variable. m_mapView->setMap(m_map); // Call the generateMapByExtent() function. generateMapByExtent(); -
Begin to implement the
generatefunction. UseMap By Extent() Envelopeto set four parameters and then callBuilder toto create the envelope.Envelope() Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203// Set the view (created in QML) void Display_an_offline_map::setMapView(MapQuickView* mapView) { // Return if there is a problem with the map view member variable. if (!mapView || mapView == m_mapView) { return; } // Set the map view member variable to the map view. m_mapView = mapView; // Set the map on the map view member variable's to the map member variable. m_mapView->setMap(m_map); // Call the generateMapByExtent() function. generateMapByExtent(); emit mapViewChanged(); } void Display_an_offline_map::generateMapByExtent() { // Create a new envelope builder (to define an area of interest) using the supplied // spatial reference. EnvelopeBuilder* envelopeBuilder = new EnvelopeBuilder(SpatialReference::wgs84(), this); // Set the boundary of the envelope builder. envelopeBuilder->setXMin(-118.5064); envelopeBuilder->setXMax(-118.4800); envelopeBuilder->setYMin(34.0094); envelopeBuilder->setYMax(34.0259); // Create an envelope (for the offline area) from the envelope builder. const Envelope envelope = envelopeBuilder->toEnvelope(); } -
Add a graphic to
generateto show the area you will take offline.Map By Extent() Create a
Graphicusing the envelope,SimpleandFill Symbol Simple. From this create aLine Symbol Graphicsand add it to theOverlay map.View Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203void Display_an_offline_map::generateMapByExtent() { // Create a new envelope builder (to define an area of interest) using the supplied // spatial reference. EnvelopeBuilder* envelopeBuilder = new EnvelopeBuilder(SpatialReference::wgs84(), this); // Set the boundary of the envelope builder. envelopeBuilder->setXMin(-118.5064); envelopeBuilder->setXMax(-118.4800); envelopeBuilder->setYMin(34.0094); envelopeBuilder->setYMax(34.0259); // Create an envelope (for the offline area) from the envelope builder. const Envelope envelope = envelopeBuilder->toEnvelope(); // Create a new simple line symbol using the supplied simple line symbol style, // color, and width. SimpleLineSymbol* simpleLineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, Qt::red, 3, this); // Create a new simple fill symbol using the supplied simple fill symbol style, color // (transparent), and simple line symbol. SimpleFillSymbol* simpleFillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, Qt::transparent, simpleLineSymbol, this); // Create a new graphic using the supplied envelope and simple fill symbol. Graphic* graphic = new Graphic(envelope, simpleFillSymbol, this); // Create a new graphics overlay using the default constructor. GraphicsOverlay* graphicsOverlay = new GraphicsOverlay(this); // Get the graphic list model from the graphics overlay. GraphicListModel* graphicListModel = graphicsOverlay->graphics(); // Append the graphic to the graphic list model. graphicListModel->append(graphic); // Get the graphics overlay list model from the map view. GraphicsOverlayListModel* graphicsOverlayListModel = m_mapView->graphicsOverlays(); // Add the graphics overlay to the graphic overlay list model. graphicsOverlayListModel->append(graphicsOverlay); -
Add the following
createmethod that creates aDefault Generate Offline Map Parameters Async Generateobject. These offline map parameters will serves as the input to create aOffline Map Parameters Generate. Store the resulting offline mobile map package (MMPK) at a desired local folder.Offline Map Job Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203// Create a new simple line symbol using the supplied simple line symbol style, // color, and width. SimpleLineSymbol* simpleLineSymbol = new SimpleLineSymbol(SimpleLineSymbolStyle::Solid, Qt::red, 3, this); // Create a new simple fill symbol using the supplied simple fill symbol style, color // (transparent), and simple line symbol. SimpleFillSymbol* simpleFillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle::Solid, Qt::transparent, simpleLineSymbol, this); // Create a new graphic using the supplied envelope and simple fill symbol. Graphic* graphic = new Graphic(envelope, simpleFillSymbol, this); // Create a new graphics overlay using the default constructor. GraphicsOverlay* graphicsOverlay = new GraphicsOverlay(this); // Get the graphic list model from the graphics overlay. GraphicListModel* graphicListModel = graphicsOverlay->graphics(); // Append the graphic to the graphic list model. graphicListModel->append(graphic); // Get the graphics overlay list model from the map view. GraphicsOverlayListModel* graphicsOverlayListModel = m_mapView->graphicsOverlays(); // Add the graphics overlay to the graphic overlay list model. graphicsOverlayListModel->append(graphicsOverlay); // Execute the offline map tasks job's create default generate offline map parameters // async method. It returns a generate offline map parameters object. m_offlineMapTask->createDefaultGenerateOfflineMapParametersAsync(envelope).then(this, [this](const GenerateOfflineMapParameters& generateOfflineMapParameters) { // Create a QString for the path where the .mmpk will be written. const QString qStringOutputPath = QDir::homePath() + "/ArcGIS/Maps/SDK/Data/offlinemap.mmpk"; // Get the generate offline map job from the offline map task. GenerateOfflineMapJob* generateOfflineMapJob = m_offlineMapTask->generateOfflineMap( generateOfflineMapParameters, qStringOutputPath); // If we have a problem creating the generate offline map job exit the create default // generate offline map parameters async method. if (!generateOfflineMapJob) return; -
Add a
connectthat monitors the status of theGenerateand returns changes to status.Offline Map Job Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203// Execute the offline map tasks job's create default generate offline map parameters // async method. It returns a generate offline map parameters object. m_offlineMapTask->createDefaultGenerateOfflineMapParametersAsync(envelope).then(this, [this](const GenerateOfflineMapParameters& generateOfflineMapParameters) { // Create a QString for the path where the .mmpk will be written. const QString qStringOutputPath = QDir::homePath() + "/ArcGIS/Maps/SDK/Data/offlinemap.mmpk"; // Get the generate offline map job from the offline map task. GenerateOfflineMapJob* generateOfflineMapJob = m_offlineMapTask->generateOfflineMap( generateOfflineMapParameters, qStringOutputPath); // If we have a problem creating the generate offline map job exit the create default // generate offline map parameters async method. if (!generateOfflineMapJob) return; // Connect to the generate offline map job's status changed event. connect(generateOfflineMapJob, &GenerateOfflineMapJob::statusChanged, this, [this, generateOfflineMapJob]() { // Test if the generate offline map job's status succeeded. if (generateOfflineMapJob->jobStatus() == JobStatus::Succeeded) { // Provide a status message to the user the offline map is being created. qDebug() << "generating offline map"; // Get the generate offline map result from the generate offline map job. GenerateOfflineMapResult* generateOfflineMapResult = generateOfflineMapJob->result(); // Get the map (offline version) from the generate offline map result. Map* map = generateOfflineMapResult->offlineMap(this); // Set the map on the map view. m_mapView->setMap(map); // If there are no errors, provide additional status infomation on the // offline map's creation. qDebug() << (generateOfflineMapJob->error().isEmpty() ? "No errors" : (generateOfflineMapJob->error().message() + generateOfflineMapJob->error().additionalMessage())); } // Creating the offline map failed. else if (generateOfflineMapJob->jobStatus() == JobStatus::Failed) { // Provide a status message to the user what went wrong in the offline // map's creation. qWarning() << generateOfflineMapJob->error().message() << generateOfflineMapJob->error().additionalMessage(); } }); -
Add another
connect(optional) that displays progress of theGenerateas the job executes. Add the final codeOffline Map Job generateand the final closing code (required) to complete the first connect function.Job- >start() Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203// Connect to the generate offline map job's status changed event. connect(generateOfflineMapJob, &GenerateOfflineMapJob::statusChanged, this, [this, generateOfflineMapJob]() { // Test if the generate offline map job's status succeeded. if (generateOfflineMapJob->jobStatus() == JobStatus::Succeeded) { // Provide a status message to the user the offline map is being created. qDebug() << "generating offline map"; // Get the generate offline map result from the generate offline map job. GenerateOfflineMapResult* generateOfflineMapResult = generateOfflineMapJob->result(); // Get the map (offline version) from the generate offline map result. Map* map = generateOfflineMapResult->offlineMap(this); // Set the map on the map view. m_mapView->setMap(map); // If there are no errors, provide additional status infomation on the // offline map's creation. qDebug() << (generateOfflineMapJob->error().isEmpty() ? "No errors" : (generateOfflineMapJob->error().message() + generateOfflineMapJob->error().additionalMessage())); } // Creating the offline map failed. else if (generateOfflineMapJob->jobStatus() == JobStatus::Failed) { // Provide a status message to the user what went wrong in the offline // map's creation. qWarning() << generateOfflineMapJob->error().message() << generateOfflineMapJob->error().additionalMessage(); } }); // Connect to the generate offline map job's progress changed event. connect(generateOfflineMapJob, &GenerateOfflineMapJob::progressChanged, this, [generateOfflineMapJob]() { // Display generate offline map job's status to the user. qDebug() << "Job status:" << generateOfflineMapJob->progress() << "%"; }); // Call the generate offline map job's start method. generateOfflineMapJob->start(); }); -
Press Ctrl + R to run the app.
Initially, you should see the map Santa Monica, CA, with a red outline as before. At the Application Output tab in Creator, the Job status percentage should increment up to 100%, and then you should see the offline map for the specified area of Santa Monica, CA. Remove your network connection and you will still be able to use the mouse to drag, scroll, and double-click the map view to explore this offline map.
-
Open the project solution using Visual Studio Code, then open the
lib > main.dartfile. -
You will need to store a downloaded map to your device. Add the
pathpackage to the project as a dependency to access local files on a device. In the Visual Studio Code menu bar, select Terminal > New Terminal and run_provider flutter pub add path._provider -
Import
pathand_provider dart.io(included with core Dart) into themain.dartfile.main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179import 'dart:io'; import 'package:path_provider/path_provider.dart'; import 'package:arcgis_maps/arcgis_maps.dart'; import 'package:flutter/material.dart'; void main() { -
Get the web map item ID from your portal, for example
4c4c3a28388446a19278b3a17051730e. -
In
on, denote the method as asynchronous.Map View Ready() main.dartUse dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179void onMapViewReady() async { -
Replace all the code contained in
onto instead create a portal item using the item ID and create a map with this item.Map View Ready() main.dartUse dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179void onMapViewReady() async { // Create the map from a portal item using the item ID. final portalItem = PortalItem.withPortalAndItemId( portal: Portal.arcGISOnline(), itemId: 'YOUR_ITEM_ID', ); final map = ArcGISMap.withItem(portalItem); } -
Define the area of interest to be taken offline using an
Envelopegeometry.main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Create the map from a portal item using the item ID. final portalItem = PortalItem.withPortalAndItemId( portal: Portal.arcGISOnline(), itemId: 'YOUR_ITEM_ID', ); final map = ArcGISMap.withItem(portalItem); // Create an envelope geometry to represent the area of interest. final envelopeBldr = EnvelopeBuilder( // Set the spatial reference using the predefined reference. spatialReference: SpatialReference.wgs84, ); // Add the lower left and upper right coordinates. envelopeBldr.xMin = -118.5064; envelopeBldr.xMax = -118.4800; envelopeBldr.yMin = 34.0094; envelopeBldr.yMax = 34.0259; -
Display the envelope using a graphic. The fill graphic should be transparent and have a red outline to indicate the area to be taken offline.
main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Create an envelope geometry to represent the area of interest. final envelopeBldr = EnvelopeBuilder( // Set the spatial reference using the predefined reference. spatialReference: SpatialReference.wgs84, ); // Add the lower left and upper right coordinates. envelopeBldr.xMin = -118.5064; envelopeBldr.xMax = -118.4800; envelopeBldr.yMin = 34.0094; envelopeBldr.yMax = 34.0259; // Define a red line symbol to act as the outline border // for the area of interest. final lineSymbol = SimpleLineSymbol( style: SimpleLineSymbolStyle.solid, color: Colors.red, width: 2, ); // Define a fill symbol that is transparent, setting the // outline to the line symbol final fillSymbol = SimpleFillSymbol( style: SimpleFillSymbolStyle.solid, color: Colors.transparent, outline: lineSymbol, ); // Create a graphic with the envelope geometry, transparent fill // symbol with a red border outline. final graphic = Graphic( geometry: envelopeBldr.toGeometry(), symbol: fillSymbol, ); -
Add the graphic to the graphics overlay, add the graphics overlay to the map view controller, and set its view point to the extent of the graphic. Lastly, set the map view controller's ArcGIS map property to the offline map.
main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Create a graphic with the envelope geometry, transparent fill // symbol with a red border outline. final graphic = Graphic( geometry: envelopeBldr.toGeometry(), symbol: fillSymbol, ); // Add the graphic to a graphics overlay. final graphicsOverlay = GraphicsOverlay(); graphicsOverlay.graphics.add(graphic); // Add the graphics overlay to the map view controller. _mapViewController.graphicsOverlays.add(graphicsOverlay); // Set the view point to the graphic's extent. _mapViewController.setViewpoint( Viewpoint.fromTargetExtent( graphic.geometry!.extent, ), ); // Set the map to the map view controller. _mapViewController.arcGISMap = map; -
Create the asynchronous
Offlinefor the online map.Map Task main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Set the map to the map view controller. _mapViewController.arcGISMap = map; // Create an offline map task for the map. final offlineMapTask = OfflineMapTask.withOnlineMap(map); -
Use the previously defined graphic to create parameters that define the region of the map to take offline.
main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Create an offline map task for the map. final offlineMapTask = OfflineMapTask.withOnlineMap(map); // Create parameters specifying the region to take offline using the // graphic's geometry. Provide a minimum scale to avoid requesting // a huge download. Do not continue execution if there is failure // while taking the map offline. Lastly, disable data synchronization // for the generated offline maps. final parameters = await offlineMapTask.createDefaultGenerateOfflineMapParameters( areaOfInterest: graphic.geometry!, minScale: 10000, ) ..continueOnErrors = false ..updateMode = GenerateOfflineMapUpdateMode.noUpdates; -
Prepare an empty directory to store the offline map.
main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Create parameters specifying the region to take offline using the // graphic's geometry. Provide a minimum scale to avoid requesting // a huge download. Do not continue execution if there is failure // while taking the map offline. Lastly, disable data synchronization // for the generated offline maps. final parameters = await offlineMapTask.createDefaultGenerateOfflineMapParameters( areaOfInterest: graphic.geometry!, minScale: 10000, ) ..continueOnErrors = false ..updateMode = GenerateOfflineMapUpdateMode.noUpdates; // Prepare an empty directory to store the offline map. final documentsUri = (await getApplicationDocumentsDirectory()).uri; final downloadDirectoryUri = documentsUri.resolve('offline_map'); if (Directory.fromUri(downloadDirectoryUri).existsSync()) { Directory.fromUri(downloadDirectoryUri).deleteSync( recursive: true, ); } Directory.fromUri(downloadDirectoryUri).createSync(); -
Use the
Offlineto create a job to generate the offline map.Map Task main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Prepare an empty directory to store the offline map. final documentsUri = (await getApplicationDocumentsDirectory()).uri; final downloadDirectoryUri = documentsUri.resolve('offline_map'); if (Directory.fromUri(downloadDirectoryUri).existsSync()) { Directory.fromUri(downloadDirectoryUri).deleteSync( recursive: true, ); } Directory.fromUri(downloadDirectoryUri).createSync(); // Create a job to generate the offline map passing in the parameters // and download directory. final generateOfflineMapJob = offlineMapTask.generateOfflineMap( parameters: parameters, downloadDirectoryUri: downloadDirectoryUri, ); -
Create a
generateand allow it to listen to and print theOffline Map Job progressvalue.main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Create a job to generate the offline map passing in the parameters // and download directory. final generateOfflineMapJob = offlineMapTask.generateOfflineMap( parameters: parameters, downloadDirectoryUri: downloadDirectoryUri, ); // Listen for progress updates. generateOfflineMapJob.onProgressChanged.listen((progress) { debugPrint(progress.toString()); }); -
Run the job to get the resulting offline map and display it. Show details if an error occurs.
main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179// Listen for progress updates. generateOfflineMapJob.onProgressChanged.listen((progress) { debugPrint(progress.toString()); }); try { // Run the generate offline map job. final result = await generateOfflineMapJob.run(); // Get the offline map and display it with the map view controller. _mapViewController.arcGISMap = result.offlineMap; } on ArcGISException catch (e) { debugPrint('Error generating offline map: ${e.message}'); } -
Run the app. Expand More info for instructions.
-
In the Visual Studio Code's terminal, run:
Use dark colors for code blocks Copy 1flutter pub upgrade -
Run:
Use dark colors for code blocks Copy 1dart run arcgis_maps install -
Make sure you have an Android emulator, iOS simulator or physical device configured and running.
-
In the menu bar, select Run > Run Without Debugging.
-
An area of the map will start downloading automatically upon app launch. Select View > Debug Console to see the download progress.
Once the map has finished downloading, you will see an area of Santa Monica near the beach, zoomed in closer than the original view point.
-
Access the offline map
Create a function to load the previously downloaded offline map from its stored location, so it can be reused without redownloading.
-
Inside
Map, create aView Model.cs private asyncfunction returning aTaskcalledAccess.Map() MapViewModel.csUse dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98private async Task AccessMap() { } -
Inside the function, create a
Mobilethat references the path to the downloaded offline map areaMap Package An offline map area, also known as a preplanned map area, is an area in a web map used to create an offline map.Learn more .MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98private async Task AccessMap() { var mobileMapPackage = await MobileMapPackage.OpenAsync(_downloadLocation); } -
Load the mobile map package and read the
Mapfrom it.MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98private 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.
-
Create a function called
access. Inside it, check if the offline map package exists on the device file system.Offline Map() MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250suspend fun accessOfflineMap() { if (!File(downloadLocation).exists()) { return showMessage(context, "No offline map!") } } -
Create a
Mobilereferencing the path to the offline map. Then load the mobile map package.Map Package MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250suspend fun accessOfflineMap() { if (!File(downloadLocation).exists()) { return showMessage(context, "No offline map!") } val mobileMapPackage = MobileMapPackage(downloadLocation) mobileMapPackage.load().onFailure { error -> return showMessage(context, "Mobile map package failed to load: ${error.message}") } } -
Read the first
mapfrom the mobile map package.MapViewModelExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250suspend fun accessOfflineMap() { if (!File(downloadLocation).exists()) { return showMessage(context, "No offline map!") } val mobileMapPackage = MobileMapPackage(downloadLocation) mobileMapPackage.load().onFailure { error -> return showMessage(context, "Mobile map package failed to load: ${error.message}") } map = mobileMapPackage.maps.first() }Expand
-
Create a function called
makewhich accepts a file path of the downloaded offline map as a parameter.Mobile Map Package ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119func makeMobileMapPackage(offlineMapURL: URL) async throws { } -
Create a
Mobilereferencing the downloaded offline mapMap Package An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more .ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119func makeMobileMapPackage(offlineMapURL: URL) async throws { let mobileMapPackage = MobileMapPackage(fileURL: offlineMapURL) } -
Load the mobile map package and read the
mapfrom it.ContentView.swiftExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119func makeMobileMapPackage(offlineMapURL: URL) async throws { let mobileMapPackage = MobileMapPackage(fileURL: offlineMapURL) try await mobileMapPackage.load() let map = mobileMapPackage.maps.first }Expand -
The function is now ready to be called to access a previously downloaded offline map area. You can trigger this function from a button click or from the main function.
-
In Projects, double-click Headers > Display_an_offline_map.h to open the file. Add the
accessfunction declaration.Offline Map() Display_an_offline_map.hUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr; void generateMapByExtent(); Esri::ArcGISRuntime::PortalItem* m_portalItem = nullptr; Esri::ArcGISRuntime::OfflineMapTask* m_offlineMapTask = nullptr; void accessOfflineMap(); }; -
In Projects, double-click Sources > Display_an_offline_map.cpp to open the file. Then, add the following
#includestatement.Display_an_offline_map.hUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203#include "Envelope.h" #include "EnvelopeBuilder.h" #include "Error.h" #include "GenerateOfflineMapParameters.h" #include "GenerateOfflineMapJob.h" #include "GenerateOfflineMapResult.h" #include "Graphic.h" #include "GraphicListModel.h" #include "GraphicsOverlay.h" #include "GraphicsOverlayListModel.h" #include "OfflineMapTask.h" #include "Portal.h" #include "PortalItem.h" #include "SimpleFillSymbol.h" #include "SimpleLineSymbol.h" #include "SpatialReference.h" #include "SymbolTypes.h" #include "TaskTypes.h" #include <QFuture> #include <QDir> #include <QUuid> #include "MobileMapPackage.h" -
Create a
Mobilethat references the path where the downloaded web mapMap Package A web map is a map stored as a JSON object that defines properties such as the basemap layer, data layers, layer styles, and pop-up styles. Its JSON structure is defined by the web map specification.Learn more area is located.Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264void Display_an_offline_map::accessOfflineMap() { // Create a new mobile map package using the path to the .mmpk file on the device. MobileMapPackage* mobileMapPackage = new MobileMapPackage("path//to//mmpk", this); // Return from the function. return; } -
Call
load()on the mobile map package and display the map area once the load finishes.Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264void Display_an_offline_map::accessOfflineMap() { // Create a new mobile map package using the path to the .mmpk file on the device. MobileMapPackage* mobileMapPackage = new MobileMapPackage("path//to//mmpk", this); // Connect to the mobile map package's done loading event. connect(mobileMapPackage, &MobileMapPackage::doneLoading, this, [this, mobileMapPackage](const Error& e) { // Test if there are any errors from the job. if (e.isEmpty()) // Success { // Get the QList of maps from the mobile map package. QList<Map*> qListMaps = mobileMapPackage->maps(); // Set the map member variable to the first map in the QList of maps. m_map = qListMaps.at(0); // Set the map view's map property to the map. m_mapView->setMap(m_map); } else // An error occurred. { // Display to the user the error that occured. qDebug() << e.message() << e.additionalMessage(); } }); // Call the mobile map packages's load method. mobileMapPackage->load(); // Return from the function. return; } -
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 from another function.
-
Press Ctrl + R to run the app.
-
After the
onmethod, create an asynchronous function that accepts a file path of the downloaded offline map as a parameter.Map View Ready main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138void accessMap(Uri fileUri) async { } -
Create a
Mobile, referencing the downloaded offline map.Map Package main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138void accessMap(Uri fileUri) async { final mobileMapPackage = MobileMapPackage.withFileUri(fileUri); } -
Load the mobile map package and read the first
map.main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138void accessMap(Uri fileUri) async { final mobileMapPackage = MobileMapPackage.withFileUri(fileUri); await mobileMapPackage.load(); _mapViewController.arcGISMap = mobileMapPackage.maps.first; } -
The method is now ready to be called to access a previously downloaded offline map area. You can trigger this function from a button click or from the main function.
Configure synchronization
Create a function to synchronize the offline map with its feature service so server changes can be downloaded when connectivity is restored.
-
Inside
Map, create aView Model.cs private asyncfunction returning aTaskcalledSynchronize.Map() MapViewModel.csUse dark colors for code blocks Copy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98private async Task SynchronizeMap() { } -
Create an
Offlinereferencing the offline mapMap Sync Task An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more .MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98private async Task SynchronizeMap() { OfflineMapSyncTask offlineMapSyncTask = await OfflineMapSyncTask.CreateAsync(Map); } -
Use the
Offlineto get defaultMap Sync Task Offline. Optionally modify these (for example, by specifying a synchronization direction).Map Sync Parameters MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98private async Task SynchronizeMap() { OfflineMapSyncTask offlineMapSyncTask = await OfflineMapSyncTask.CreateAsync(Map); OfflineMapSyncParameters syncParameters = await offlineMapSyncTask.CreateDefaultOfflineMapSyncParametersAsync(); } -
Use the parameters to create an
Offline.Map Sync Job MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98private async Task SynchronizeMap() { OfflineMapSyncTask offlineMapSyncTask = await OfflineMapSyncTask.CreateAsync(Map); OfflineMapSyncParameters syncParameters = await offlineMapSyncTask.CreateDefaultOfflineMapSyncParametersAsync(); OfflineMapSyncJob syncJob = offlineMapSyncTask.SyncOfflineMap(syncParameters); } -
Start the
Offline. If it completes without errors, the offline mapMap Sync Job An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more and web mapA web map is a map stored as a JSON object that defines properties such as the basemap layer, data layers, layer styles, and pop-up styles. Its JSON structure is defined by the web map specification.Learn more will be in sync.MapViewModel.csUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98private async Task SynchronizeMap() { OfflineMapSyncTask offlineMapSyncTask = await OfflineMapSyncTask.CreateAsync(Map); OfflineMapSyncParameters syncParameters = await offlineMapSyncTask.CreateDefaultOfflineMapSyncParametersAsync(); OfflineMapSyncJob syncJob = offlineMapSyncTask.SyncOfflineMap(syncParameters); OfflineMapSyncResult syncResult = await syncJob.GetResultAsync(); } -
The function is now ready to be called to synchronize an offline map. 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.
-
Create a function called
sync. Inside it, check if the offline map package exists on the device file system.Offline Map() MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250suspend fun syncOfflineMap( ) { if (!File(downloadLocation).exists()) { return showMessage(context, "No offline map!") } } -
Create a
Mobilereferencing the path to the offline map. Then load the mobile map package and get the first map from it.Map Package MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250suspend fun syncOfflineMap( ) { if (!File(downloadLocation).exists()) { return showMessage(context, "No offline map!") } val offlineMapPackage = MobileMapPackage(downloadLocation) coroutineScope.launch { offlineMapPackage.load().onFailure { error -> return@launch showMessage(context, "Mobile map package failed to load: ${error.message}") } val offlineMap = offlineMapPackage.maps.first() } } -
Create an
Offlinereferencing the offline mapMap Sync Task An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more .MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250suspend fun syncOfflineMap( ) { if (!File(downloadLocation).exists()) { return showMessage(context, "No offline map!") } val offlineMapPackage = MobileMapPackage(downloadLocation) coroutineScope.launch { offlineMapPackage.load().onFailure { error -> return@launch showMessage(context, "Mobile map package failed to load: ${error.message}") } val offlineMap = offlineMapPackage.maps.first() val offlineMapSyncTask = OfflineMapSyncTask(offlineMap) } } -
Use the
Offlineto get defaultMap Sync Task Offline. Optionally, you can modify these, e.g. specifying a synchronization direction.Map Sync Parameters MapViewModelUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250val offlineMapSyncTask = OfflineMapSyncTask(offlineMap) val offlineMapSyncParameters = offlineMapSyncTask.createDefaultOfflineMapSyncParameters().getOrElse { error -> return@launch showMessage( context, "Unable to generate default offline map sync parameters. ${error.message}" ) } offlineMapSyncParameters.syncDirection = SyncDirection.Bidirectional } } -
Use the parameters to create an
Offline Map Sync Job. Then start the job.If job completes without errors, the offline map
An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more and web mapA web map is a map stored as a JSON object that defines properties such as the basemap layer, data layers, layer styles, and pop-up styles. Its JSON structure is defined by the web map specification.Learn more will be in sync. You can also log out the sync results.MapViewModelExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250offlineMapSyncParameters.syncDirection = SyncDirection.Bidirectional val syncJob = offlineMapSyncTask.createOfflineMapSyncJob(offlineMapSyncParameters) syncJob.start() val offlineMapSyncResult = syncJob.result().getOrElse { error -> return@launch showMessage(context, "The sync job failed: ${error.message}") } Log.i( TAG, "The offlineMapSyncResult.layerResults.size is ${offlineMapSyncResult.layerResults.size}") Log.i( TAG, "offlineMapSyncResult.layerResults.hasError: ${offlineMapSyncResult.hasErrors}") offlineMapSyncResult.layerResults.forEach { layer, offlineMapSyncLayerResult -> Log.i( TAG, "Layer name: ${layer.name}") Log.i( TAG, " has errors: ${offlineMapSyncLayerResult.hasErrors} ") Log.i( TAG, "Offline map sync result error: ${offlineMapSyncLayerResult.error?.message}") } } }Expand
-
Create a function called
makethat takes a web map as a parameter.Offline Sync Task ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119func makeOfflineSyncTask(offlineMap: Map) async throws { } -
Create an
Offlinereferencing the offline mapMap Sync Task An offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more .ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119func makeOfflineSyncTask(offlineMap: Map) async throws { let offlineMapSyncTask = OfflineMapSyncTask(map: offlineMap) } -
Use the
Offlineto get defaultMap Sync Task Offline. Optionally, you can modify these, e.g. specifying a synchronization direction.Map Sync Parameters ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119func makeOfflineSyncTask(offlineMap: Map) async throws { let offlineMapSyncTask = OfflineMapSyncTask(map: offlineMap) let parameters = try await offlineMapSyncTask.makeDefaultOfflineMapSyncParameters() // Modify parameters if necessary, e.g. sync direction. } -
Use the parameters to create an
Offline Map Sync Job.ContentView.swiftUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119func makeOfflineSyncTask(offlineMap: Map) async throws { let offlineMapSyncTask = OfflineMapSyncTask(map: offlineMap) let parameters = try await offlineMapSyncTask.makeDefaultOfflineMapSyncParameters() // Modify parameters if necessary, e.g. sync direction. let offlineMapSyncJob = offlineMapSyncTask.makeSyncOfflineMapJob(parameters: parameters) } -
Start the
Offline Map Sync Job. If it completes without errors, the offline mapAn offline map is a map area and its data content downloaded from an offline-enabled web map for use in offline applications built with ArcGIS Maps SDKs for Native Apps.Learn more and web mapA web map is a map stored as a JSON object that defines properties such as the basemap layer, data layers, layer styles, and pop-up styles. Its JSON structure is defined by the web map specification.Learn more will be in sync.ContentView.swiftExpand Use dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119func makeOfflineSyncTask(offlineMap: Map) async throws { let offlineMapSyncTask = OfflineMapSyncTask(map: offlineMap) let parameters = try await offlineMapSyncTask.makeDefaultOfflineMapSyncParameters() // Modify parameters if necessary, e.g. sync direction. let offlineMapSyncJob = offlineMapSyncTask.makeSyncOfflineMapJob(parameters: parameters) offlineMapSyncJob.start() }Expand -
The function is now ready to be called to synchronize an offline map. You can trigger this function from a UI button click or by calling it directly in the main function.
-
In Projects, double-click Headers > Display_an_offline_map.h to open the file. Add the following classes to the header file.
Display_an_offline_map.hUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71namespace Esri::ArcGISRuntime { class Map; class MapQuickView; class PortalItem; class OfflineMapTask; class OfflineMapSyncTask; class OfflineMapSyncJob; } -
Add the
synchronizefunction declaration and the necessary member variables. Save and close the file.Offline Map() Display_an_offline_map.hUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71private: Esri::ArcGISRuntime::MapQuickView* mapView() const; void setMapView(Esri::ArcGISRuntime::MapQuickView* mapView); Esri::ArcGISRuntime::Map* m_map = nullptr; Esri::ArcGISRuntime::MapQuickView* m_mapView = nullptr; void generateMapByExtent(); Esri::ArcGISRuntime::PortalItem* m_portalItem = nullptr; Esri::ArcGISRuntime::OfflineMapTask* m_offlineMapTask = nullptr; void accessOfflineMap(); void synchronizeOfflineMap(); Esri::ArcGISRuntime::OfflineMapSyncTask* m_offlineSyncTask = nullptr; Esri::ArcGISRuntime::OfflineMapSyncJob* m_syncJob = nullptr; QMetaObject::Connection m_syncJobConnection; }; -
In Projects, double-click Sources > Display_an_offline_map.cpp to open the file.
-
Add the following
#includestatements.Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203#include "MapQuickView.h" #include "Envelope.h" #include "EnvelopeBuilder.h" #include "Error.h" #include "GenerateOfflineMapParameters.h" #include "GenerateOfflineMapJob.h" #include "GenerateOfflineMapResult.h" #include "Graphic.h" #include "GraphicListModel.h" #include "GraphicsOverlay.h" #include "GraphicsOverlayListModel.h" #include "OfflineMapTask.h" #include "Portal.h" #include "PortalItem.h" #include "SimpleFillSymbol.h" #include "SimpleLineSymbol.h" #include "SpatialReference.h" #include "SymbolTypes.h" #include "TaskTypes.h" #include <QFuture> #include <QDir> #include <QUuid> #include "MobileMapPackage.h" #include "OfflineMapSyncTask.h" -
Start implementing the
synchronize. Create anOffline Map() Offlinereferencing the offline map and store it into the member variableMap Sync Task m._offline Sync Task Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264void Display_an_offline_map::synchronizeOfflineMap() { // Create a new offline map sync task using the map member variable. OfflineMapSyncTask* offlineMapSyncTask = new OfflineMapSyncTask(m_map, this); // Set the offline map sync task variable to the offline map sync task. m_offlineMapSyncTask = offlineMapSyncTask; // If there is a problem with the offline map sync task, return (ie. exit the function). if (!m_offlineMapSyncTask) return; } -
Use the
Offlineto get defaultMap Sync Task ::create Default Offline Map Sync Parameters Async() Offline. Optionally modify these (for example, by specifying a synchronization direction).Map Sync Parameters Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264void Display_an_offline_map::synchronizeOfflineMap() { // Create a new offline map sync task using the map member variable. OfflineMapSyncTask* offlineMapSyncTask = new OfflineMapSyncTask(m_map, this); // Set the offline map sync task variable to the offline map sync task. m_offlineMapSyncTask = offlineMapSyncTask; // If there is a problem with the offline map sync task, return (ie. exit the function). if (!m_offlineMapSyncTask) return; // Execute the offline map sync task's create default offline map sync parameters async method. // It returns an offline map sync parameters object. m_offlineMapSyncTask->createDefaultOfflineMapSyncParametersAsync().then(this, [this](OfflineMapSyncParameters offlineMapSyncParameters) { }); } -
Use the parameters to create an
Offlineand start the job.Map Sync Job Display_an_offline_map.cppUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264void Display_an_offline_map::synchronizeOfflineMap() { // Create a new offline map sync task using the map member variable. OfflineMapSyncTask* offlineMapSyncTask = new OfflineMapSyncTask(m_map, this); // Set the offline map sync task variable to the offline map sync task. m_offlineMapSyncTask = offlineMapSyncTask; // If there is a problem with the offline map sync task, return (ie. exit the function). if (!m_offlineMapSyncTask) return; // Execute the offline map sync task's create default offline map sync parameters async method. // It returns an offline map sync parameters object. m_offlineMapSyncTask->createDefaultOfflineMapSyncParametersAsync().then(this, [this](OfflineMapSyncParameters offlineMapSyncParameters) { // Test if the offline map sync job member variable exists. if (m_offlineMapSyncJob) { // Delete the existing offline map sync job and close the connection. delete m_offlineMapSyncJob; disconnect(m_connection); } // Get the offline map sync job from the offline sync task's sync offline map method. m_offlineMapSyncJob = m_offlineMapSyncTask->syncOfflineMap(offlineMapSyncParameters); // Set the connection member variable to the connect for the offline map sync job's done loading event. m_connection = connect(m_offlineMapSyncJob, &OfflineMapSyncJob::jobDone, this, []() { // Display back to the use the offline map sync job completed. qDebug() << "Job complete"; }); // Call the offline map sync job's start method. m_offlineMapSyncJob->start(); }); } -
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 from another function.
-
Press Ctrl + R to run the app.
-
In the
main.dartfile, create an asynchronous function that accepts anArcGISas a parameter.Map main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138void synchronizeMap(ArcGISMap map) async { } -
Create an
Offline, referencing the downloaded offline map.Map Sync Task main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138void synchronizeMap(ArcGISMap map) async { final offlineMapSyncTask = OfflineMapSyncTask.withMap(map); } -
Use the offline map sync task to create default
Offline.Map Sync Parameters main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138void synchronizeMap(ArcGISMap map) async { final offlineMapSyncTask = OfflineMapSyncTask.withMap(map); final offlineMapSyncParameters = await offlineMapSyncTask.createDefaultOfflineMapSyncParameters(); } -
Use the parameters to create an
Offline.Map Sync Job main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138void synchronizeMap(ArcGISMap map) async { final offlineMapSyncTask = OfflineMapSyncTask.withMap(map); final offlineMapSyncParameters = await offlineMapSyncTask.createDefaultOfflineMapSyncParameters(); final offlineMapSyncJob = offlineMapSyncTask.syncOfflineMap( parameters: offlineMapSyncParameters, ); } -
Use the offline map sync job to get the result.
main.dartUse dark colors for code blocks 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138void synchronizeMap(ArcGISMap map) async { final offlineMapSyncTask = OfflineMapSyncTask.withMap(map); final offlineMapSyncParameters = await offlineMapSyncTask.createDefaultOfflineMapSyncParameters(); final offlineMapSyncJob = offlineMapSyncTask.syncOfflineMap( parameters: offlineMapSyncParameters, ); final syncResult = offlineMapSyncJob.result; } -
The function is now ready to be called to synchronize an offline map. You can trigger this function from a button click or from the main function.
Congratulations!
You have completed the Create an offline app with user-defined areas how-to. The application uses the ArcGIS Maps SDKs for Native Apps to generate and download a map area on demand, then displays it offline. The map also includes a feature layer that is enabled for synchronization, allowing edits to be made and synced when connectivity is restored.
What's next?
To explore additional ArcGIS offline capabilities, go to Tutorials for more how-to's, tutorials, and samples.
