I'm working on enabling offline sync in an iOS app using ArcGIS runtime 100.6. The back end is ArcGIS Enterprise 10.7.1.
I created a web map which only uses the World Topography Map (for Export) as a basemap and a single feature service created by ESRI to as a controlled test to guard against any mistakes I could have made while publishing the services which the production app will need to consume. These should present no problem being taken offline, but this error is generated after I initiate the download:
I checked the web map settings on portal. It is shared with everyone and the "offline mode" switch is enabled, so I don't understand how I could be getting this error. To clarify, the basemap loads successfully, but the feature layer does not.
The code for initiating offline mode doesn't deviate much from the sample in this article (The function "downloadGeodatabaseForLayers() follows this article😞
func takeMapOffline(areaOfInterest: AGSGeometry) {
let offlineMap = AGSMap.init(url: URL(string: self.offlineWebMapUrl3)!)
let offlineMapTask = AGSOfflineMapTask(onlineMap: offlineMap!)
offlineMapTask.defaultGenerateOfflineMapParameters(withAreaOfInterest: areaOfInterest, completion: {(parameters, error) in
print("@@@ Generate parameters 1: Start")
if let error = error {
print("@@@ Generate parameters 2b: Error, getting parameters failed")
print(error)
self.showDownloadFailedAlert("Error generating offline parameters: \(error.localizedDescription)")
return
}
guard parameters != nil else {
print("takeMapOffline: No parameters provided")
return
}
if let parameters = parameters {
parameters.maxScale = 3600
parameters.minScale = 30000
parameters.includeBasemap = true
parameters.isDefinitionExpressionFilterEnabled = true
parameters.continueOnErrors = true
parameters.returnSchemaOnlyForEditableLayers = true
parameters.attachmentSyncDirection = .bidirectional
parameters.returnLayerAttachmentOption = .allLayers
print("@@@ Generate parameters 2a: Got parameters!")
print("@@@ Generate parameters 3: create job")
let mapStorageURL = self.getNewOfflineMapDirectoryURL()
UserDefaults.standard.set(mapStorageURL, forKey: "OfflineMapDirectoryUrl")
let AGSOfflineMapJob = offlineMapTask.generateOfflineMapJob(with: parameters, downloadDirectory: mapStorageURL)
self.startOfflineMapJob(job: AGSOfflineMapJob, areaOfInterest: areaOfInterest)
}
})
}
func startOfflineMapJob(job: AGSGenerateOfflineMapJob, areaOfInterest: AGSGeometry) {
job.start(statusHandler: { (status) in
DispatchQueue.main.async {
SVProgressHUD.showDismissable(with: Float(job.progress.fractionCompleted), status: "Downloading map selection. This may take several minutes. Tap here to cancel.")
}
print("Status [\(String(describing: job.progress.fractionCompleted))]: \(status)")
if job.status == .failed {
DispatchQueue.main.async {
SVProgressHUD.dismiss()
}
self.showDownloadFailedAlert("Server Error")
return
}
}) { (result, error) in
DispatchQueue.main.async {
SVProgressHUD.dismiss()
}
if let error = error {
print(error)
self.showDownloadFailedAlert(error.localizedDescription)
return
}
guard let result = result else {
self.showDownloadFailedAlert("Didn't receive a response.")
return
}
if result.hasErrors {
result.layerErrors.forEach{(layerError) in
print((layerError.key.name), " Error taking this layer offline: ", (layerError.value))
}
result.tableErrors.forEach{(tableError) in
print((tableError.key.tableName), " Error taking this table offline")
}
self.showDownloadFailedAlert("Error taking layers offline.")
}
else {
self.mapView.map = result.offlineMap
DispatchQueue.main.async {
self.downloadGeodatabaseForLayers(areaOfInterest: areaOfInterest)
}
}
}
}
func downloadGeodatabaseForLayers(areaOfInterest: AGSGeometry) {
print("@@@Downloading geodatabase")
let syncTask = AGSGeodatabaseSyncTask(url: URL(string: testOfflineServiceUrl)!)
syncTask.defaultGenerateGeodatabaseParameters(withExtent: areaOfInterest, completion: {[weak self] (parameters, error) in
if let error = error {
print("@@@Error generating geodatabase:" + error.localizedDescription)
print(error)
return
}
guard parameters != nil else {
print("@@@No parameters")
return
}
if let parameters = parameters {
parameters.syncModel = .layer
parameters.layerOptions.removeAll()
let layersToInclude = [0]
for val in layersToInclude {
parameters.layerOptions.append(AGSGenerateLayerOption(layerID: val, includeRelated: true))
}
parameters.returnAttachments = false
let geodatabaseUrl = self?.getNewOfflineMapDirectoryURL().appendingPathExtension(".geodatabase")
let generateJob = syncTask.generateJob(with: parameters, downloadFileURL: (geodatabaseUrl)!)
generateJob.start(statusHandler: { (status) in
DispatchQueue.main.async {
SVProgressHUD.showProgress(Float(generateJob.progress.fractionCompleted), status: "Downloading Geodatabase")
}
}, completion: { (geodatabase, error) in
SVProgressHUD.dismiss()
if let error = error {
print("@@@Error downloading geodatabase: ")
print(error)
return
}
else if let geoDb = geodatabase {
self!.generatedGeodatabase = geoDb
self!.displayLayersFromGeodatabase(geoDb: geoDb)
}
})
}
})
}
If I download the app container, I can see both the mmpk file and the geodatabase file, but only the basemap displays. Can someone suggest a solution?