Can't load an offline map after saving it

887
3
Jump to solution
07-23-2021 07:10 PM
ThomasKellough
New Contributor

I'm having difficulties loading an offline map and can't find anything in the docs explaining how.

I'm able to successfully save an offline map with this message

 

21:01:48.591  DEBUG GISMapDetailViewController.saveMapForOffline():224 - Job message: 54: Job succeeded.

21:01:48.592  DEBUG GISMapDetailViewController.saveMapForOffline():229 - Finished downloading!: <AGSGenerateOfflineMapResult: 0x2801cbbc0>

 

However, if I try to load the map from File Manager I get this error.

 

21:02:51.114  ERROR GISMapDetailViewController.togglePrint():322 - Error loading offline map: The file “offlineString” couldn’t be opened because you don’t have permission to view it.

 

I've tried multiple simulators, cleaned, deleted derived data, and tried on two different real devices.

How can I load up a map after downloading it? One of the docs I'm looking at is here. https://developers.arcgis.com/ios/swift/sample-code/generate-offline-map/

But even in the instructions it says "When complete, the offline map will replace the online map in the map view."

I need to be able to go do a different area in the map, view my offline maps, then show them after downloading them, not just replace the current screen. 

0 Kudos
1 Solution

Accepted Solutions
Nicholas-Furness
Esri Regular Contributor

Hi.

You don't use the FileManager. See here for more details about how to re-open the downloaded map.

Can you explain more about what you want the user experience to be when you say "I need to be able to go do a different area in the map, view my offline maps, then show them after downloading them, not just replace the current screen."? Are you using preplanned offline maps or on-demand offline maps?

A Map View (AGSMapView) displays a single map at any one time. Each downloaded map is a separate map, so when you display one, you are displaying it instead of whichever map (online, or offline) the map view was previously displaying.

If you need to merge the contents of multiple downloaded maps into a single map and display that merged map in the map view, that's possible but would require some coding. You'd essentially need to load multiple separate maps as described in the link above, but not display them, then copy the basemap layers and operational layers from each into one destination AGSMap, which is the map you would display.

View solution in original post

0 Kudos
3 Replies
Nicholas-Furness
Esri Regular Contributor

Hi.

You don't use the FileManager. See here for more details about how to re-open the downloaded map.

Can you explain more about what you want the user experience to be when you say "I need to be able to go do a different area in the map, view my offline maps, then show them after downloading them, not just replace the current screen."? Are you using preplanned offline maps or on-demand offline maps?

A Map View (AGSMapView) displays a single map at any one time. Each downloaded map is a separate map, so when you display one, you are displaying it instead of whichever map (online, or offline) the map view was previously displaying.

If you need to merge the contents of multiple downloaded maps into a single map and display that merged map in the map view, that's possible but would require some coding. You'd essentially need to load multiple separate maps as described in the link above, but not display them, then copy the basemap layers and operational layers from each into one destination AGSMap, which is the map you would display.

0 Kudos
ThomasKellough
New Contributor

Hey Nicholas,

Thanks so much for that link. I was under the impression the mobile map package was something completely different, but using the docs I was able to display the saved map and view it offline.

Sorry if my post was confusing. To be a bit more clear, I need to be able to...

1) Show users a list of various pre-made maps loaded from an offline maps generated through a portal item and specific item ID

2) Give users options to download each map ahead of time

3) When users are offline, see a list of their downloaded maps and click each one to view them separately.

I am able to do this by prompting the user to give each download a custom name, then I can save that list of names and display it in a table view. Then I can use the link you provided above to load each map based of the name in the tableview.

 

However, I do have another question. Users currently have options to use features such as see a legend and change base layers. Those are done using online methods such as 

private func loadBaseMapsFromPortal() {
        portal.fetchBasemaps { (basemaps, error) in
            if let error = error {
                log.error("Error fetching basemaps: \(error)")
                return
            }
            
            if let basemaps = basemaps {
                self.baseMapDataSource.basemaps = basemaps
                self.baseMapCollectionView.reloadData()
                return
            }
            
            return
        }
    }


...
layer.fetchLegendInfos { [weak self] (legendInfos, error) in
                    if let error = error {
                        log.error("Error fetching legend info for layer: \(layer.name). \nError: \(error.localizedDescription)")
                        dispatchGroup.leave()
                    } else {
                        if let legendInfos = legendInfos, !legendInfos.isEmpty {
                            var array = [AGSLegendInfo]()
                            for info in legendInfos {
                                if info.name.isEmpty {
                                    continue
                                }
                                array.append(info)
                            }
                            
                            array = array.unique()
                            if !array.isEmpty {
                                self?.mapLegendDataSource.legendInfosDict[layer.name] = array
                            } else {
                                self?.mapLegendDataSource.legendInfosDict.removeValue(forKey: layer.name)
                            }
                        }
                        dispatchGroup.leave()
                    }
                }
...

 

However, we are unable to use these while offline. Is there a way to continue using these features while offline?

0 Kudos
Nicholas-Furness
Esri Regular Contributor

Hi Thomas.

You should be able to do both, although there is some custom code required for the basemap options, and it depends on the basemaps you want to use.

The fetchLegendInfos should just work against layers in an offline map. If that's not the case, let me know and we can dig in some more.

For the basemaps, you can switch out the basemap for an offline map, but if you want to do that while offline, you will need basemaps downloaded to your device, and you will need to manage and load those yourself (there is no equivalent to the Portal.fetchBasemaps call).

Imagery basemaps and old image tile basemaps are downloaded as a TPK file.

Vector tile basemaps are downloaded as a VTPK file and a Style Resource folder (this contains the style definition JSON, sprites, etc.).

You can use the AGSExportTileCacheTask and AGSExportVectorTilesTask to download these. Once downloaded, you can open them as AGSArcGISTileLayer or AGSArcGISVectorTiledLayer respectively, create an AGSBasemap of that layer, and set that as the basemap on your offline AGSMap.

Note, for vector tile basemaps you do not need to download the tiles multiple times for every style you want offline. The ArcGIS vector tile basemap styles all use the same set of tiles, but different style resources to render them. So you can download the tiles once for a particular geographic area, and separately call exportStyleResourceCacheJobWithDownloadDirectory to get individual style overrides. One caveat: Runtime does not yet allow you to change vector tile layer styles on the fly, so whenever your app changes the basemap style you would need to create a new AGSArcGISVectorTileLayer with a new style selection and update your map's basemap.

You can see some sample code for downloading vector tile basemaps here: https://developers.arcgis.com/documentation/mapping-apis-and-services/offline/offline-data/#download...

Hope that helps.

0 Kudos